diff --git a/doc/Section_commands.html b/doc/Section_commands.html index 5fb8988b4..2f222a14c 100644 --- a/doc/Section_commands.html +++ b/doc/Section_commands.html @@ -1,498 +1,498 @@ <HTML> <CENTER><A HREF = "Section_start.html">Previous Section</A> - <A HREF = "http://lammps.sandia.gov">LAMMPS WWW Site</A> - <A HREF = "Manual.html">LAMMPS Documentation</A> - <A HREF = "Section_commands.html#comm">LAMMPS Commands</A> - <A HREF = "Section_howto.html">Next Section</A> </CENTER> <HR> <H3>3. Commands </H3> <P>This section describes how a LAMMPS input script is formatted and what commands are used to define a LAMMPS simulation. </P> 3.1 <A HREF = "#3_1">LAMMPS input script</A><BR> 3.2 <A HREF = "#3_2">Parsing rules</A><BR> 3.3 <A HREF = "#3_3">Input script structure</A><BR> 3.4 <A HREF = "#3_4">Commands listed by category</A><BR> 3.5 <A HREF = "#3_5">Commands listed alphabetically</A> <BR> <HR> <A NAME = "3_1"></A><H4>3.1 LAMMPS input script </H4> <P>LAMMPS executes by reading commands from a input script (text file), one line at a time. When the input script ends, LAMMPS exits. Each command causes LAMMPS to take some action. It may set an internal variable, read in a file, or run a simulation. Most commands have default settings, which means you only need to use the command if you wish to change the default. </P> <P>In many cases, the ordering of commands in an input script is not important. However the following rules apply: </P> <P>(1) LAMMPS does not read your entire input script and then perform a simulation with all the settings. Rather, the input script is read one line at a time and each command takes effect when it is read. Thus this sequence of commands: </P> <PRE>timestep 0.5 run 100 run 100 </PRE> <P>does something different than this sequence: </P> <PRE>run 100 timestep 0.5 run 100 </PRE> <P>In the first case, the specified timestep (0.5 fmsec) is used for two simulations of 100 timesteps each. In the 2nd case, the default timestep (1.0 fmsec) is used for the 1st 100 step simulation and a 0.5 fmsec timestep is used for the 2nd one. </P> <P>(2) Some commands are only valid when they follow other commands. For example you cannot set the temperature of a group of atoms until atoms have been defined and a group command is used to define which atoms belong to the group. </P> <P>(3) Sometimes command B will use values that can be set by command A. This means command A must precede command B in the input script if it is to have the desired effect. For example, the <A HREF = "read_data.html">read_data</A> command initializes the system by setting up the simulation box and assigning atoms to processors. If default values are not desired, the <A HREF = "processors.html">processors</A> and <A HREF = "boundary.html">boundary</A> commands need to be used before read_data to tell LAMMPS how to map processors to the simulation box. </P> <P>Many input script errors are detected by LAMMPS and an ERROR or WARNING message is printed. <A HREF = "Section_errors.html">This section</A> gives more information on what errors mean. The documentation for each command lists restrictions on how the command can be used. </P> <HR> <A NAME = "3_2"></A><H4>3.2 Parsing rules </H4> <P>Each non-blank line in the input script is treated as a command. LAMMPS commands are case sensitive. Command names are lower-case, as are specified command arguments. Upper case letters may be used in file names or user-chosen ID strings. </P> <P>Here is how each line in the input script is parsed by LAMMPS: </P> <P>(1) If the last printable character on the line is a "&" character (with no surrounding quotes), the command is assumed to continue on the next line. The next line is concatenated to the previous line by removing the "&" character and newline. This allows long commands to be continued across two or more lines. </P> <P>(2) All characters from the first "#" character onward are treated as comment and discarded. See an exception in (6). Note that a comment after a trailing "&" character will prevent the command from continuing on the next line. Also note that for multi-line commands a single leading "#" will comment out the entire command. </P> <P>(3) The line is searched repeatedly for $ characters, which indicate variables that are replaced with a text string. See an exception in (6). If the $ is followed by curly brackets, then the variable name is the text inside the curly brackets. If no curly brackets follow the $, then the variable name is the single character immediately following the $. Thus ${myTemp} and $x refer to variable names "myTemp" and "x". See the <A HREF = "variable.html">variable</A> command for details of how strings are assigned to variables and how they are substituted for in input script commands. </P> <P>(4) The line is broken into "words" separated by whitespace (tabs, spaces). Note that words can thus contain letters, digits, underscores, or punctuation characters. </P> <P>(5) The first word is the command name. All successive words in the line are arguments. </P> <P>(6) If you want text with spaces to be treated as a single argument, it can be enclosed in either double or single quotes. E.g. </P> <PRE>print "Volume = $v" print 'Volume = $v' </PRE> <P>The quotes are removed when the single argument is stored internally. See the <A HREF = "dump_modify.html">dump modify format</A> or <A HREF = "if.html">if</A> commands for examples. A "#" or "$" character that is between quotes will not be treated as a comment indicator in (2) or substituted for as a variable in (3). </P> <P>IMPORTANT NOTE: If the argument is itself a command that requires a quoted argument (e.g. using a <A HREF = "print.html">print</A> command as part of an <A HREF = "if.html">if</A> or <A HREF = "run.html">run every</A> command), then the double and single quotes can be nested in the usual manner. See the doc pages for those commands for examples. Only one of level of nesting is allowed, but that should be sufficient for most use cases. </P> <HR> <H4><A NAME = "3_3"></A>3.3 Input script structure </H4> <P>This section describes the structure of a typical LAMMPS input script. The "examples" directory in the LAMMPS distribution contains many sample input scripts; the corresponding problems are discussed in <A HREF = "Section_example.html">this section</A>, and animated on the <A HREF = "http://lammps.sandia.gov">LAMMPS WWW Site</A>. </P> <P>A LAMMPS input script typically has 4 parts: </P> <OL><LI>Initialization <LI>Atom definition <LI>Settings <LI>Run a simulation </OL> <P>The last 2 parts can be repeated as many times as desired. I.e. run a simulation, change some settings, run some more, etc. Each of the 4 parts is now described in more detail. Remember that almost all the commands need only be used if a non-default value is desired. </P> <P>(1) Initialization </P> <P>Set parameters that need to be defined before atoms are created or read-in from a file. </P> <P>The relevant commands are <A HREF = "units.html">units</A>, <A HREF = "dimension.html">dimension</A>, <A HREF = "newton.html">newton</A>, <A HREF = "processors.html">processors</A>, <A HREF = "boundary.html">boundary</A>, <A HREF = "atom_style.html">atom_style</A>, <A HREF = "atom_modify.html">atom_modify</A>. </P> <P>If force-field parameters appear in the files that will be read, these commands tell LAMMPS what kinds of force fields are being used: <A HREF = "pair_style.html">pair_style</A>, <A HREF = "bond_style.html">bond_style</A>, <A HREF = "angle_style.html">angle_style</A>, <A HREF = "dihedral_style.html">dihedral_style</A>, <A HREF = "improper_style.html">improper_style</A>. </P> <P>(2) Atom definition </P> <P>There are 3 ways to define atoms in LAMMPS. Read them in from a data or restart file via the <A HREF = "read_data.html">read_data</A> or <A HREF = "read_restart.html">read_restart</A> commands. These files can contain molecular topology information. Or create atoms on a lattice (with no molecular topology), using these commands: <A HREF = "lattice.html">lattice</A>, <A HREF = "region.html">region</A>, <A HREF = "create_box.html">create_box</A>, <A HREF = "create_atoms.html">create_atoms</A>. The entire set of atoms can be duplicated to make a larger simulation using the <A HREF = "replicate.html">replicate</A> command. </P> <P>(3) Settings </P> <P>Once atoms and molecular topology are defined, a variety of settings can be specified: force field coefficients, simulation parameters, output options, etc. </P> <P>Force field coefficients are set by these commands (they can also be set in the read-in files): <A HREF = "pair_coeff.html">pair_coeff</A>, <A HREF = "bond_coeff.html">bond_coeff</A>, <A HREF = "angle_coeff.html">angle_coeff</A>, <A HREF = "dihedral_coeff.html">dihedral_coeff</A>, <A HREF = "improper_coeff.html">improper_coeff</A>, <A HREF = "kspace_style.html">kspace_style</A>, <A HREF = "dielectric.html">dielectric</A>, <A HREF = "special_bonds.html">special_bonds</A>. </P> <P>Various simulation parameters are set by these commands: <A HREF = "neighbor.html">neighbor</A>, <A HREF = "neigh_modify.html">neigh_modify</A>, <A HREF = "group.html">group</A>, <A HREF = "timestep.html">timestep</A>, <A HREF = "reset_timestep.html">reset_timestep</A>, <A HREF = "run_style.html">run_style</A>, <A HREF = "min_style.html">min_style</A>, <A HREF = "min_modify.html">min_modify</A>. </P> <P>Fixes impose a variety of boundary conditions, time integration, and diagnostic options. The <A HREF = "fix.html">fix</A> command comes in many flavors. </P> <P>Various computations can be specified for execution during a simulation using the <A HREF = "compute.html">compute</A>, <A HREF = "compute_modify.html">compute_modify</A>, and <A HREF = "variable.html">variable</A> commands. </P> <P>Output options are set by the <A HREF = "thermo.html">thermo</A>, <A HREF = "dump.html">dump</A>, and <A HREF = "restart.html">restart</A> commands. </P> <P>(4) Run a simulation </P> <P>A molecular dynamics simulation is run using the <A HREF = "run.html">run</A> command. Energy minimization (molecular statics) is performed using the <A HREF = "minimize.html">minimize</A> command. A parallel tempering (replica-exchange) simulation can be run using the <A HREF = "temper.html">temper</A> command. </P> <HR> <A NAME = "3_4"></A><H4>3.4 Commands listed by category </H4> <P>This section lists all LAMMPS commands, grouped by category. The <A HREF = "#3_5">next section</A> lists the same commands alphabetically. Note that some style options for some commands are part of specific LAMMPS packages, which means they cannot be used unless the package was included when LAMMPS was built. Not all packages are included in a default LAMMPS build. These dependencies are listed as Restrictions in the command's documentation. </P> <P>Initialization: </P> <P><A HREF = "atom_modify.html">atom_modify</A>, <A HREF = "atom_style.html">atom_style</A>, <A HREF = "boundary.html">boundary</A>, <A HREF = "dimension.html">dimension</A>, <A HREF = "newton.html">newton</A>, <A HREF = "processors.html">processors</A>, <A HREF = "units.html">units</A> </P> <P>Atom definition: </P> <P><A HREF = "create_atoms.html">create_atoms</A>, <A HREF = "create_box.html">create_box</A>, <A HREF = "lattice.html">lattice</A>, <A HREF = "read_data.html">read_data</A>, <A HREF = "read_restart.html">read_restart</A>, <A HREF = "region.html">region</A>, <A HREF = "replicate.html">replicate</A> </P> <P>Force fields: </P> <P><A HREF = "angle_coeff.html">angle_coeff</A>, <A HREF = "angle_style.html">angle_style</A>, <A HREF = "bond_coeff.html">bond_coeff</A>, <A HREF = "bond_style.html">bond_style</A>, <A HREF = "dielectric.html">dielectric</A>, <A HREF = "dihedral_coeff.html">dihedral_coeff</A>, <A HREF = "dihedral_style.html">dihedral_style</A>, <A HREF = "improper_coeff.html">improper_coeff</A>, <A HREF = "improper_style.html">improper_style</A>, <A HREF = "kspace_modify.html">kspace_modify</A>, <A HREF = "kspace_style.html">kspace_style</A>, <A HREF = "pair_coeff.html">pair_coeff</A>, <A HREF = "pair_modify.html">pair_modify</A>, <A HREF = "pair_style.html">pair_style</A>, <A HREF = "pair_write.html">pair_write</A>, <A HREF = "special_bonds.html">special_bonds</A> </P> <P>Settings: </P> <P><A HREF = "communicate.html">communicate</A>, <A HREF = "dipole.html">dipole</A>, <A HREF = "group.html">group</A>, <A HREF = "mass.html">mass</A>, <A HREF = "min_modify.html">min_modify</A>, <A HREF = "min_style.html">min_style</A>, <A HREF = "neigh_modify.html">neigh_modify</A>, <A HREF = "neighbor.html">neighbor</A>, <A HREF = "reset_timestep.html">reset_timestep</A>, <A HREF = "run_style.html">run_style</A>, <A HREF = "set.html">set</A>, <A HREF = "shape.html">shape</A>, <A HREF = "timestep.html">timestep</A>, <A HREF = "velocity.html">velocity</A> </P> <P>Fixes: </P> <P><A HREF = "fix.html">fix</A>, <A HREF = "fix_modify.html">fix_modify</A>, <A HREF = "unfix.html">unfix</A> </P> <P>Computes: </P> <P><A HREF = "compute.html">compute</A>, <A HREF = "compute_modify.html">compute_modify</A>, <A HREF = "uncompute.html">uncompute</A> </P> <P>Output: </P> <P><A HREF = "dump.html">dump</A>, <A HREF = "dump_modify.html">dump_modify</A>, <A HREF = "restart.html">restart</A>, <A HREF = "thermo.html">thermo</A>, <A HREF = "thermo_modify.html">thermo_modify</A>, <A HREF = "thermo_style.html">thermo_style</A>, <A HREF = "undump.html">undump</A>, <A HREF = "write_restart.html">write_restart</A> </P> <P>Actions: </P> <P><A HREF = "delete_atoms.html">delete_atoms</A>, <A HREF = "delete_bonds.html">delete_bonds</A>, <A HREF = "displace_atoms.html">displace_atoms</A>, <A HREF = "displace_box.html">displace_box</A>, <A HREF = "minimize.html">minimize</A>, <A HREF = "neb.html">neb</A> <A HREF = "prd.html">prd</A>, <A HREF = "run.html">run</A>, <A HREF = "temper.html">temper</A> </P> <P>Miscellaneous: </P> <P><A HREF = "clear.html">clear</A>, <A HREF = "echo.html">echo</A>, <A HREF = "if.html">if</A>, <A HREF = "include.html">include</A>, <A HREF = "jump.html">jump</A>, <A HREF = "label.html">label</A>, <A HREF = "log.html">log</A>, <A HREF = "next.html">next</A>, <A HREF = "print.html">print</A>, <A HREF = "shell.html">shell</A>, <A HREF = "variable.html">variable</A> </P> <HR> <H4><A NAME = "3_5"></A><A NAME = "comm"></A>3.5 Individual commands </H4> <P>This section lists all LAMMPS commands alphabetically, with a separate listing below of styles within certain commands. The <A HREF = "#3_4">previous section</A> lists the same commands, grouped by category. Note that some style options for some commands are part of specific LAMMPS packages, which means they cannot be used unless the package was included when LAMMPS was built. Not all packages are included in a default LAMMPS build. These dependencies are listed as Restrictions in the command's documentation. </P> <DIV ALIGN=center><TABLE BORDER=1 > <TR ALIGN="center"><TD ><A HREF = "angle_coeff.html">angle_coeff</A></TD><TD ><A HREF = "angle_style.html">angle_style</A></TD><TD ><A HREF = "atom_modify.html">atom_modify</A></TD><TD ><A HREF = "atom_style.html">atom_style</A></TD><TD ><A HREF = "bond_coeff.html">bond_coeff</A></TD><TD ><A HREF = "bond_style.html">bond_style</A></TD></TR> <TR ALIGN="center"><TD ><A HREF = "boundary.html">boundary</A></TD><TD ><A HREF = "change_box.html">change_box</A></TD><TD ><A HREF = "clear.html">clear</A></TD><TD ><A HREF = "communicate.html">communicate</A></TD><TD ><A HREF = "compute.html">compute</A></TD><TD ><A HREF = "compute_modify.html">compute_modify</A></TD></TR> <TR ALIGN="center"><TD ><A HREF = "create_atoms.html">create_atoms</A></TD><TD ><A HREF = "create_box.html">create_box</A></TD><TD ><A HREF = "delete_atoms.html">delete_atoms</A></TD><TD ><A HREF = "delete_bonds.html">delete_bonds</A></TD><TD ><A HREF = "dielectric.html">dielectric</A></TD><TD ><A HREF = "dihedral_coeff.html">dihedral_coeff</A></TD></TR> <TR ALIGN="center"><TD ><A HREF = "dihedral_style.html">dihedral_style</A></TD><TD ><A HREF = "dimension.html">dimension</A></TD><TD ><A HREF = "dipole.html">dipole</A></TD><TD ><A HREF = "displace_atoms.html">displace_atoms</A></TD><TD ><A HREF = "displace_box.html">displace_box</A></TD><TD ><A HREF = "dump.html">dump</A></TD></TR> <TR ALIGN="center"><TD ><A HREF = "dump_modify.html">dump_modify</A></TD><TD ><A HREF = "echo.html">echo</A></TD><TD ><A HREF = "fix.html">fix</A></TD><TD ><A HREF = "fix_modify.html">fix_modify</A></TD><TD ><A HREF = "group.html">group</A></TD><TD ><A HREF = "if.html">if</A></TD></TR> <TR ALIGN="center"><TD ><A HREF = "improper_coeff.html">improper_coeff</A></TD><TD ><A HREF = "improper_style.html">improper_style</A></TD><TD ><A HREF = "include.html">include</A></TD><TD ><A HREF = "jump.html">jump</A></TD><TD ><A HREF = "kspace_modify.html">kspace_modify</A></TD><TD ><A HREF = "kspace_style.html">kspace_style</A></TD></TR> <TR ALIGN="center"><TD ><A HREF = "label.html">label</A></TD><TD ><A HREF = "lattice.html">lattice</A></TD><TD ><A HREF = "log.html">log</A></TD><TD ><A HREF = "mass.html">mass</A></TD><TD ><A HREF = "minimize.html">minimize</A></TD><TD ><A HREF = "min_modify.html">min_modify</A></TD></TR> <TR ALIGN="center"><TD ><A HREF = "min_style.html">min_style</A></TD><TD ><A HREF = "neb.html">neb</A></TD><TD ><A HREF = "neigh_modify.html">neigh_modify</A></TD><TD ><A HREF = "neighbor.html">neighbor</A></TD><TD ><A HREF = "newton.html">newton</A></TD><TD ><A HREF = "next.html">next</A></TD></TR> <TR ALIGN="center"><TD ><A HREF = "pair_coeff.html">pair_coeff</A></TD><TD ><A HREF = "pair_modify.html">pair_modify</A></TD><TD ><A HREF = "pair_style.html">pair_style</A></TD><TD ><A HREF = "pair_write.html">pair_write</A></TD><TD ><A HREF = "prd.html">prd</A></TD><TD ><A HREF = "print.html">print</A></TD></TR> <TR ALIGN="center"><TD ><A HREF = "processors.html">processors</A></TD><TD ><A HREF = "read_data.html">read_data</A></TD><TD ><A HREF = "read_restart.html">read_restart</A></TD><TD ><A HREF = "region.html">region</A></TD><TD ><A HREF = "replicate.html">replicate</A></TD><TD ><A HREF = "reset_timestep.html">reset_timestep</A></TD></TR> <TR ALIGN="center"><TD ><A HREF = "restart.html">restart</A></TD><TD ><A HREF = "run.html">run</A></TD><TD ><A HREF = "run_style.html">run_style</A></TD><TD ><A HREF = "set.html">set</A></TD><TD ><A HREF = "shape.html">shape</A></TD><TD ><A HREF = "shell.html">shell</A></TD></TR> -<TR ALIGN="center"><TD ><A HREF = "special_bonds.html">special_bonds</A></TD><TD ><A HREF = "temper.html">temper</A></TD><TD ><A HREF = "thermo.html">thermo</A></TD><TD ><A HREF = "thermo_modify.html">thermo_modify</A></TD><TD ><A HREF = "thermo_style.html">thermo_style</A></TD><TD ><A HREF = "timestep.html">timestep</A></TD></TR> -<TR ALIGN="center"><TD ><A HREF = "uncompute.html">uncompute</A></TD><TD ><A HREF = "undump.html">undump</A></TD><TD ><A HREF = "unfix.html">unfix</A></TD><TD ><A HREF = "units.html">units</A></TD><TD ><A HREF = "variable.html">variable</A></TD><TD ><A HREF = "velocity.html">velocity</A></TD></TR> -<TR ALIGN="center"><TD ><A HREF = "write_restart.html">write_restart</A> +<TR ALIGN="center"><TD ><A HREF = "special_bonds.html">special_bonds</A></TD><TD ><A HREF = "tad.html">tad</A></TD><TD ><A HREF = "temper.html">temper</A></TD><TD ><A HREF = "thermo.html">thermo</A></TD><TD ><A HREF = "thermo_modify.html">thermo_modify</A></TD><TD ><A HREF = "thermo_style.html">thermo_style</A></TD></TR> +<TR ALIGN="center"><TD ><A HREF = "timestep.html">timestep</A></TD><TD ><A HREF = "uncompute.html">uncompute</A></TD><TD ><A HREF = "undump.html">undump</A></TD><TD ><A HREF = "unfix.html">unfix</A></TD><TD ><A HREF = "units.html">units</A></TD><TD ><A HREF = "variable.html">variable</A></TD></TR> +<TR ALIGN="center"><TD ><A HREF = "velocity.html">velocity</A></TD><TD ><A HREF = "write_restart.html">write_restart</A> </TD></TR></TABLE></DIV> <HR> <H4>Fix styles </H4> <P>See the <A HREF = "fix.html">fix</A> command for one-line descriptions of each style or click on the style itself for a full description: </P> <DIV ALIGN=center><TABLE BORDER=1 > <TR ALIGN="center"><TD ><A HREF = "fix_adapt.html">adapt</A></TD><TD ><A HREF = "fix_addforce.html">addforce</A></TD><TD ><A HREF = "fix_aveforce.html">aveforce</A></TD><TD ><A HREF = "fix_ave_atom.html">ave/atom</A></TD><TD ><A HREF = "fix_ave_correlate.html">ave/correlate</A></TD><TD ><A HREF = "fix_ave_histo.html">ave/histo</A></TD><TD ><A HREF = "fix_ave_spatial.html">ave/spatial</A></TD><TD ><A HREF = "fix_ave_time.html">ave/time</A></TD></TR> <TR ALIGN="center"><TD ><A HREF = "fix_bond_break.html">bond/break</A></TD><TD ><A HREF = "fix_bond_create.html">bond/create</A></TD><TD ><A HREF = "fix_bond_swap.html">bond/swap</A></TD><TD ><A HREF = "fix_box_relax.html">box/relax</A></TD><TD ><A HREF = "fix_deform.html">deform</A></TD><TD ><A HREF = "fix_deposit.html">deposit</A></TD><TD ><A HREF = "fix_drag.html">drag</A></TD><TD ><A HREF = "fix_dt_reset.html">dt/reset</A></TD></TR> <TR ALIGN="center"><TD ><A HREF = "fix_efield.html">efield</A></TD><TD ><A HREF = "fix_enforce2d.html">enforce2d</A></TD><TD ><A HREF = "fix_evaporate.html">evaporate</A></TD><TD ><A HREF = "fix_external.html">external</A></TD><TD ><A HREF = "fix_freeze.html">freeze</A></TD><TD ><A HREF = "fix_gravity.html">gravity</A></TD><TD ><A HREF = "fix_heat.html">heat</A></TD><TD ><A HREF = "fix_indent.html">indent</A></TD></TR> <TR ALIGN="center"><TD ><A HREF = "fix_langevin.html">langevin</A></TD><TD ><A HREF = "fix_lineforce.html">lineforce</A></TD><TD ><A HREF = "fix_momentum.html">momentum</A></TD><TD ><A HREF = "fix_move.html">move</A></TD><TD ><A HREF = "fix_msst.html">msst</A></TD><TD ><A HREF = "fix_neb.html">neb</A></TD><TD ><A HREF = "fix_nh.html">nph</A></TD><TD ><A HREF = "fix_nph_asphere.html">nph/asphere</A></TD></TR> <TR ALIGN="center"><TD ><A HREF = "fix_nph_sphere.html">nph/sphere</A></TD><TD ><A HREF = "fix_nh.html">npt</A></TD><TD ><A HREF = "fix_npt_asphere.html">npt/asphere</A></TD><TD ><A HREF = "fix_npt_sphere.html">npt/sphere</A></TD><TD ><A HREF = "fix_nve.html">nve</A></TD><TD ><A HREF = "fix_nve_asphere.html">nve/asphere</A></TD><TD ><A HREF = "fix_nve_limit.html">nve/limit</A></TD><TD ><A HREF = "fix_nve_noforce.html">nve/noforce</A></TD></TR> <TR ALIGN="center"><TD ><A HREF = "fix_nve_sphere.html">nve/sphere</A></TD><TD ><A HREF = "fix_nh.html">nvt</A></TD><TD ><A HREF = "fix_nvt_asphere.html">nvt/asphere</A></TD><TD ><A HREF = "fix_nvt_sllod.html">nvt/sllod</A></TD><TD ><A HREF = "fix_nvt_sphere.html">nvt/sphere</A></TD><TD ><A HREF = "fix_orient_fcc.html">orient/fcc</A></TD><TD ><A HREF = "fix_planeforce.html">planeforce</A></TD><TD ><A HREF = "fix_poems.html">poems</A></TD></TR> <TR ALIGN="center"><TD ><A HREF = "fix_pour.html">pour</A></TD><TD ><A HREF = "fix_press_berendsen.html">press/berendsen</A></TD><TD ><A HREF = "fix_print.html">print</A></TD><TD ><A HREF = "fix_qeq_comb.html">qeq/comb</A></TD><TD ><A HREF = "fix_reax_bonds.html">reax/bonds</A></TD><TD ><A HREF = "fix_recenter.html">recenter</A></TD><TD ><A HREF = "fix_rigid.html">rigid</A></TD><TD ><A HREF = "fix_rigid.html">rigid/nve</A></TD></TR> <TR ALIGN="center"><TD ><A HREF = "fix_rigid.html">rigid/nvt</A></TD><TD ><A HREF = "fix_setforce.html">setforce</A></TD><TD ><A HREF = "fix_shake.html">shake</A></TD><TD ><A HREF = "fix_spring.html">spring</A></TD><TD ><A HREF = "fix_spring_rg.html">spring/rg</A></TD><TD ><A HREF = "fix_spring_self.html">spring/self</A></TD><TD ><A HREF = "fix_srd.html">srd</A></TD><TD ><A HREF = "fix_store_force.html">store/force</A></TD></TR> <TR ALIGN="center"><TD ><A HREF = "fix_store_state.html">store/state</A></TD><TD ><A HREF = "fix_temp_berendsen.html">temp/berendsen</A></TD><TD ><A HREF = "fix_temp_rescale.html">temp/rescale</A></TD><TD ><A HREF = "fix_thermal_conductivity.html">thermal/conductivity</A></TD><TD ><A HREF = "fix_tmd.html">tmd</A></TD><TD ><A HREF = "fix_ttm.html">ttm</A></TD><TD ><A HREF = "fix_viscosity.html">viscosity</A></TD><TD ><A HREF = "fix_viscous.html">viscous</A></TD></TR> <TR ALIGN="center"><TD ><A HREF = "fix_wall.html">wall/colloid</A></TD><TD ><A HREF = "fix_wall_gran.html">wall/gran</A></TD><TD ><A HREF = "fix_wall.html">wall/harmonic</A></TD><TD ><A HREF = "fix_wall.html">wall/lj126</A></TD><TD ><A HREF = "fix_wall.html">wall/lj93</A></TD><TD ><A HREF = "fix_wall_reflect.html">wall/reflect</A></TD><TD ><A HREF = "fix_wall_region.html">wall/region</A></TD><TD ><A HREF = "fix_wall_srd.html">wall/srd</A> </TD></TR></TABLE></DIV> <P>These are fix styles contributed by users, which can be used if <A HREF = "Section_start.html#2_3">LAMMPS is built with the appropriate package</A>. </P> <DIV ALIGN=center><TABLE BORDER=1 > <TR ALIGN="center"><TD ><A HREF = "fix_atc.html">atc</A></TD><TD ><A HREF = "fix_imd.html">imd</A></TD><TD ><A HREF = "fix_langevin_eff.html">langevin/eff</A></TD><TD ><A HREF = "fix_nh_eff.html">nph/eff</A></TD><TD ><A HREF = "fix_nh_eff.html">npt/eff</A></TD><TD ><A HREF = "fix_nve_eff.html">nve/eff</A></TD></TR> <TR ALIGN="center"><TD ><A HREF = "fix_nh_eff.html">nvt/eff</A></TD><TD ><A HREF = "fix_nvt_sllod_eff.html">nvt/sllod/eff</A></TD><TD ><A HREF = "fix_qeq_reax.html">qeq/reax</A></TD><TD ><A HREF = "fix_smd.html">smd</A></TD><TD ><A HREF = "fix_temp_rescale_eff.html">temp/rescale/eff</A> </TD></TR></TABLE></DIV> <HR> <H4>Compute styles </H4> <P>See the <A HREF = "compute.html">compute</A> command for one-line descriptions of each style or click on the style itself for a full description: </P> <DIV ALIGN=center><TABLE BORDER=1 > <TR ALIGN="center"><TD ><A HREF = "compute_angle_local.html">angle/local</A></TD><TD ><A HREF = "compute_atom_molecule.html">atom/molecule</A></TD><TD ><A HREF = "compute_bond_local.html">bond/local</A></TD><TD ><A HREF = "compute_centro_atom.html">centro/atom</A></TD><TD ><A HREF = "compute_cna_atom.html">cna/atom</A></TD><TD ><A HREF = "compute_com.html">com</A></TD></TR> <TR ALIGN="center"><TD ><A HREF = "compute_com_molecule.html">com/molecule</A></TD><TD ><A HREF = "compute_coord_atom.html">coord/atom</A></TD><TD ><A HREF = "compute_damage_atom.html">damage/atom</A></TD><TD ><A HREF = "compute_dihedral_local.html">dihedral/local</A></TD><TD ><A HREF = "compute_displace_atom.html">displace/atom</A></TD><TD ><A HREF = "compute_erotate_asphere.html">erotate/asphere</A></TD></TR> <TR ALIGN="center"><TD ><A HREF = "compute_erotate_sphere.html">erotate/sphere</A></TD><TD ><A HREF = "compute_event_displace.html">event/displace</A></TD><TD ><A HREF = "compute_group_group.html">group/group</A></TD><TD ><A HREF = "compute_gyration.html">gyration</A></TD><TD ><A HREF = "compute_gyration_molecule.html">gyration/molecule</A></TD><TD ><A HREF = "compute_heat_flux.html">heat/flux</A></TD></TR> <TR ALIGN="center"><TD ><A HREF = "compute_improper_local.html">improper/local</A></TD><TD ><A HREF = "compute_ke.html">ke</A></TD><TD ><A HREF = "compute_ke_atom.html">ke/atom</A></TD><TD ><A HREF = "compute_msd.html">msd</A></TD><TD ><A HREF = "compute_msd_molecule.html">msd/molecule</A></TD><TD ><A HREF = "compute_pair.html">pair</A></TD></TR> <TR ALIGN="center"><TD ><A HREF = "compute_pair_local.html">pair/local</A></TD><TD ><A HREF = "compute_pe.html">pe</A></TD><TD ><A HREF = "compute_pe_atom.html">pe/atom</A></TD><TD ><A HREF = "compute_pressure.html">pressure</A></TD><TD ><A HREF = "compute_property_atom.html">property/atom</A></TD><TD ><A HREF = "compute_property_local.html">property/local</A></TD></TR> <TR ALIGN="center"><TD ><A HREF = "compute_property_molecule.html">property/molecule</A></TD><TD ><A HREF = "compute_rdf.html">rdf</A></TD><TD ><A HREF = "compute_reduce.html">reduce</A></TD><TD ><A HREF = "compute_reduce.html">reduce/region</A></TD><TD ><A HREF = "compute_stress_atom.html">stress/atom</A></TD><TD ><A HREF = "compute_temp.html">temp</A></TD></TR> <TR ALIGN="center"><TD ><A HREF = "compute_temp_asphere.html">temp/asphere</A></TD><TD ><A HREF = "compute_temp_com.html">temp/com</A></TD><TD ><A HREF = "compute_temp_deform.html">temp/deform</A></TD><TD ><A HREF = "compute_temp_partial.html">temp/partial</A></TD><TD ><A HREF = "compute_temp_profile.html">temp/profile</A></TD><TD ><A HREF = "compute_temp_ramp.html">temp/ramp</A></TD></TR> <TR ALIGN="center"><TD ><A HREF = "compute_temp_region.html">temp/region</A></TD><TD ><A HREF = "compute_temp_sphere.html">temp/sphere</A></TD><TD ><A HREF = "compute_ti.html">ti</A> </TD></TR></TABLE></DIV> <P>These are compute styles contributed by users, which can be used if <A HREF = "Section_start.html#2_3">LAMMPS is built with the appropriate package</A>. </P> <DIV ALIGN=center><TABLE BORDER=1 > <TR ALIGN="center"><TD ><A HREF = "compute_ackland_atom.html">ackland/atom</A></TD><TD ><A HREF = "compute_ke_eff.html">ke/eff</A></TD><TD ><A HREF = "compute_ke_atom_eff.html">ke/atom/eff</A></TD><TD ><A HREF = "compute_temp_eff.html">temp/eff</A></TD><TD ><A HREF = "compute_temp_deform_eff.html">temp/deform/eff</A></TD><TD ><A HREF = "compute_temp_region_eff.html">temp/region/eff</A> </TD></TR></TABLE></DIV> <HR> <H4>Pair_style potentials </H4> <P>See the <A HREF = "pair_style.html">pair_style</A> command for an overview of pair potentials. Click on the style itself for a full description: </P> <DIV ALIGN=center><TABLE BORDER=1 > <TR ALIGN="center"><TD ><A HREF = "pair_none.html">none</A></TD><TD ><A HREF = "pair_hybrid.html">hybrid</A></TD><TD ><A HREF = "pair_hybrid.html">hybrid/overlay</A></TD><TD ><A HREF = "pair_airebo.html">airebo</A></TD></TR> <TR ALIGN="center"><TD ><A HREF = "pair_born.html">born</A></TD><TD ><A HREF = "pair_born.html">born/coul/long</A></TD><TD ><A HREF = "pair_buck.html">buck</A></TD><TD ><A HREF = "pair_buck.html">buck/coul/cut</A></TD></TR> <TR ALIGN="center"><TD ><A HREF = "pair_buck.html">buck/coul/long</A></TD><TD ><A HREF = "pair_colloid.html">colloid</A></TD><TD ><A HREF = "pair_comb.html">comb</A></TD><TD ><A HREF = "pair_coul.html">coul/cut</A></TD></TR> <TR ALIGN="center"><TD ><A HREF = "pair_coul.html">coul/debye</A></TD><TD ><A HREF = "pair_coul.html">coul/long</A></TD><TD ><A HREF = "pair_dipole.html">dipole/cut</A></TD><TD ><A HREF = "pair_dpd.html">dpd</A></TD></TR> <TR ALIGN="center"><TD ><A HREF = "pair_dpd.html">dpd/tstat</A></TD><TD ><A HREF = "pair_dsmc.html">dsmc</A></TD><TD ><A HREF = "pair_eam.html">eam</A></TD><TD ><A HREF = "pair_eam.html">eam/opt</A></TD></TR> <TR ALIGN="center"><TD ><A HREF = "pair_eam.html">eam/alloy</A></TD><TD ><A HREF = "pair_eam.html">eam/alloy/opt</A></TD><TD ><A HREF = "pair_eam.html">eam/fs</A></TD><TD ><A HREF = "pair_eam.html">eam/fs/opt</A></TD></TR> <TR ALIGN="center"><TD ><A HREF = "pair_eim.html">eim</A></TD><TD ><A HREF = "pair_gauss.html">gauss</A></TD><TD ><A HREF = "pair_gayberne.html">gayberne</A></TD><TD ><A HREF = "pair_gayberne.html">gayberne/gpu</A></TD></TR> <TR ALIGN="center"><TD ><A HREF = "pair_gran.html">gran/hertz/history</A></TD><TD ><A HREF = "pair_gran.html">gran/hooke</A></TD><TD ><A HREF = "pair_gran.html">gran/hooke/history</A></TD><TD ><A HREF = "pair_hbond_dreiding.html">hbond/dreiding/lj</A></TD></TR> <TR ALIGN="center"><TD ><A HREF = "pair_hbond_dreiding.html">hbond/dreiding/morse</A></TD><TD ><A HREF = "pair_charmm.html">lj/charmm/coul/charmm</A></TD><TD ><A HREF = "pair_charmm.html">lj/charmm/coul/charmm/implicit</A></TD><TD ><A HREF = "pair_charmm.html">lj/charmm/coul/long</A></TD></TR> <TR ALIGN="center"><TD ><A HREF = "pair_charmm.html">lj/charmm/coul/long/opt</A></TD><TD ><A HREF = "pair_class2.html">lj/class2</A></TD><TD ><A HREF = "pair_class2.html">lj/class2/coul/cut</A></TD><TD ><A HREF = "pair_class2.html">lj/class2/coul/long</A></TD></TR> <TR ALIGN="center"><TD ><A HREF = "pair_lj.html">lj/cut</A></TD><TD ><A HREF = "pair_lj.html">lj/cut/gpu</A></TD><TD ><A HREF = "pair_lj.html">lj/cut/opt</A></TD><TD ><A HREF = "pair_lj.html">lj/cut/coul/cut</A></TD></TR> <TR ALIGN="center"><TD ><A HREF = "pair_lj.html">lj/cut/coul/cut/gpu</A></TD><TD ><A HREF = "pair_lj.html">lj/cut/coul/debye</A></TD><TD ><A HREF = "pair_lj.html">lj/cut/coul/long</A></TD><TD ><A HREF = "pair_lj.html">lj/cut/coul/long/gpu</A></TD></TR> <TR ALIGN="center"><TD ><A HREF = "pair_lj.html">lj/cut/coul/long/tip4p</A></TD><TD ><A HREF = "pair_lj_expand.html">lj/expand</A></TD><TD ><A HREF = "pair_gromacs.html">lj/gromacs</A></TD><TD ><A HREF = "pair_gromacs.html">lj/gromacs/coul/gromacs</A></TD></TR> <TR ALIGN="center"><TD ><A HREF = "pair_lj_smooth.html">lj/smooth</A></TD><TD ><A HREF = "pair_lj96_cut.html">lj96/cut</A></TD><TD ><A HREF = "pair_lj96_cut.html">lj96/cut/gpu</A></TD><TD ><A HREF = "pair_lubricate.html">lubricate</A></TD></TR> <TR ALIGN="center"><TD ><A HREF = "pair_meam.html">meam</A></TD><TD ><A HREF = "pair_morse.html">morse</A></TD><TD ><A HREF = "pair_morse.html">morse/opt</A></TD><TD ><A HREF = "pair_peri.html">peri/lps</A></TD></TR> <TR ALIGN="center"><TD ><A HREF = "pair_peri.html">peri/pmb</A></TD><TD ><A HREF = "pair_reax.html">reax</A></TD><TD ><A HREF = "pair_resquared.html">resquared</A></TD><TD ><A HREF = "pair_soft.html">soft</A></TD></TR> <TR ALIGN="center"><TD ><A HREF = "pair_sw.html">sw</A></TD><TD ><A HREF = "pair_table.html">table</A></TD><TD ><A HREF = "pair_tersoff.html">tersoff</A></TD><TD ><A HREF = "pair_tersoff_zbl.html">tersoff/zbl</A></TD></TR> <TR ALIGN="center"><TD ><A HREF = "pair_yukawa.html">yukawa</A></TD><TD ><A HREF = "pair_yukawa_colloid.html">yukawa/colloid</A> </TD></TR></TABLE></DIV> <P>These are pair styles contributed by users, which can be used if <A HREF = "Section_start.html#2_3">LAMMPS is built with the appropriate package</A>. </P> <DIV ALIGN=center><TABLE BORDER=1 > <TR ALIGN="center"><TD ><A HREF = "pair_buck_coul.html">buck/coul</A></TD><TD ><A HREF = "pair_cmm.html">cg/cmm</A></TD><TD ><A HREF = "pair_cmm.html">cg/cmm/gpu</A></TD><TD ><A HREF = "pair_cmm.html">cg/cmm/coul/cut</A></TD></TR> <TR ALIGN="center"><TD ><A HREF = "pair_cmm.html">cg/cmm/coul/long</A></TD><TD ><A HREF = "pair_cmm.html">cg/cmm/coul/long/gpu</A></TD><TD ><A HREF = "pair_eam.html">eam/cd</A></TD><TD ><A HREF = "pair_eff.html">eff/cut</A></TD></TR> <TR ALIGN="center"><TD ><A HREF = "pair_lj_coul.html">lj/coul</A></TD><TD ><A HREF = "pair_reax_c.html">reax/c</A> </TD></TR></TABLE></DIV> <HR> <H4>Bond_style potentials </H4> <P>See the <A HREF = "bond_style.html">bond_style</A> command for an overview of bond potentials. Click on the style itself for a full description: </P> <DIV ALIGN=center><TABLE BORDER=1 > <TR ALIGN="center"><TD WIDTH="100"><A HREF = "bond_none.html">none</A></TD><TD WIDTH="100"><A HREF = "bond_hybrid.html">hybrid</A></TD><TD WIDTH="100"><A HREF = "bond_class2.html">class2</A></TD><TD WIDTH="100"><A HREF = "bond_fene.html">fene</A></TD></TR> <TR ALIGN="center"><TD WIDTH="100"><A HREF = "bond_fene_expand.html">fene/expand</A></TD><TD WIDTH="100"><A HREF = "bond_harmonic.html">harmonic</A></TD><TD WIDTH="100"><A HREF = "bond_morse.html">morse</A></TD><TD WIDTH="100"><A HREF = "bond_nonlinear.html">nonlinear</A></TD></TR> <TR ALIGN="center"><TD WIDTH="100"><A HREF = "bond_quartic.html">quartic</A></TD><TD WIDTH="100"><A HREF = "bond_table.html">table</A> </TD></TR></TABLE></DIV> <HR> <H4>Angle_style potentials </H4> <P>See the <A HREF = "angle_style.html">angle_style</A> command for an overview of angle potentials. Click on the style itself for a full description: </P> <DIV ALIGN=center><TABLE BORDER=1 > <TR ALIGN="center"><TD WIDTH="100"><A HREF = "angle_none.html">none</A></TD><TD WIDTH="100"><A HREF = "angle_hybrid.html">hybrid</A></TD><TD WIDTH="100"><A HREF = "angle_charmm.html">charmm</A></TD><TD WIDTH="100"><A HREF = "angle_class2.html">class2</A></TD></TR> <TR ALIGN="center"><TD WIDTH="100"><A HREF = "angle_cosine.html">cosine</A></TD><TD WIDTH="100"><A HREF = "angle_cosine_delta.html">cosine/delta</A></TD><TD WIDTH="100"><A HREF = "angle_cosine_periodic.html">cosine/periodic</A></TD><TD WIDTH="100"><A HREF = "angle_cosine_squared.html">cosine/squared</A></TD></TR> <TR ALIGN="center"><TD WIDTH="100"><A HREF = "angle_harmonic.html">harmonic</A></TD><TD WIDTH="100"><A HREF = "angle_table.html">table</A> </TD></TR></TABLE></DIV> <P>These are angle styles contributed by users, which can be used if <A HREF = "Section_start.html#2_3">LAMMPS is built with the appropriate package</A>. </P> <DIV ALIGN=center><TABLE BORDER=1 > <TR ALIGN="center"><TD ><A HREF = "angle_cmm.html">cg/cmm</A> </TD></TR></TABLE></DIV> <HR> <H4>Dihedral_style potentials </H4> <P>See the <A HREF = "dihedral_style.html">dihedral_style</A> command for an overview of dihedral potentials. Click on the style itself for a full description: </P> <DIV ALIGN=center><TABLE BORDER=1 > <TR ALIGN="center"><TD WIDTH="100"><A HREF = "dihedral_none.html">none</A></TD><TD WIDTH="100"><A HREF = "dihedral_hybrid.html">hybrid</A></TD><TD WIDTH="100"><A HREF = "dihedral_charmm.html">charmm</A></TD><TD WIDTH="100"><A HREF = "dihedral_class2.html">class2</A></TD></TR> <TR ALIGN="center"><TD WIDTH="100"><A HREF = "dihedral_harmonic.html">harmonic</A></TD><TD WIDTH="100"><A HREF = "dihedral_helix.html">helix</A></TD><TD WIDTH="100"><A HREF = "dihedral_multi_harmonic.html">multi/harmonic</A></TD><TD WIDTH="100"><A HREF = "dihedral_opls.html">opls</A> </TD></TR></TABLE></DIV> <HR> <H4>Improper_style potentials </H4> <P>See the <A HREF = "improper_style.html">improper_style</A> command for an overview of improper potentials. Click on the style itself for a full description: </P> <DIV ALIGN=center><TABLE BORDER=1 > <TR ALIGN="center"><TD WIDTH="100"><A HREF = "improper_none.html">none</A></TD><TD WIDTH="100"><A HREF = "improper_hybrid.html">hybrid</A></TD><TD WIDTH="100"><A HREF = "improper_class2.html">class2</A></TD><TD WIDTH="100"><A HREF = "improper_cvff.html">cvff</A></TD></TR> <TR ALIGN="center"><TD WIDTH="100"><A HREF = "improper_harmonic.html">harmonic</A></TD><TD WIDTH="100"><A HREF = "improper_umbrella.html">umbrella</A> </TD></TR></TABLE></DIV> <HR> <H4>Kspace solvers </H4> <P>See the <A HREF = "kspace_style.html">kspace_style</A> command for an overview of Kspace solvers. Click on the style itself for a full description: </P> <DIV ALIGN=center><TABLE BORDER=1 > <TR ALIGN="center"><TD WIDTH="100"><A HREF = "kspace_style.html">ewald</A></TD><TD WIDTH="100"><A HREF = "kspace_style.html">pppm</A></TD><TD WIDTH="100"><A HREF = "kspace_style.html">pppm/tip4p</A> </TD></TR></TABLE></DIV> <P>These are Kspace solvers contributed by users, which can be used if <A HREF = "Section_start.html#2_3">LAMMPS is built with the appropriate package</A>. </P> <DIV ALIGN=center><TABLE BORDER=1 > <TR ALIGN="center"><TD WIDTH="100"><A HREF = "kspace_style.html">ewald/n</A> </TD></TR></TABLE></DIV> </HTML> diff --git a/doc/Section_howto.html b/doc/Section_howto.html index 0b92fc19a..4bc3da2a8 100644 --- a/doc/Section_howto.html +++ b/doc/Section_howto.html @@ -1,1940 +1,1940 @@ <HTML> <CENTER><A HREF = "Section_commands.html">Previous Section</A> - <A HREF = "http://lammps.sandia.gov">LAMMPS WWW Site</A> - <A HREF = "Manual.html">LAMMPS Documentation</A> - <A HREF = "Section_commands.html#comm">LAMMPS Commands</A> - <A HREF = "Section_example.html">Next Section</A> </CENTER> <HR> <H3>4. How-to discussions </H3> <P>The following sections describe how to use various options within LAMMPS. </P> 4.1 <A HREF = "#4_1">Restarting a simulation</A><BR> 4.2 <A HREF = "#4_2">2d simulations</A><BR> 4.3 <A HREF = "#4_3">CHARMM, AMBER, and DREIDING force fields</A><BR> 4.4 <A HREF = "#4_4">Running multiple simulations from one input script</A><BR> 4.5 <A HREF = "#4_5">Multi-replica simulations</A><BR> 4.6 <A HREF = "#4_6">Granular models</A><BR> 4.7 <A HREF = "#4_7">TIP3P water model</A><BR> 4.8 <A HREF = "#4_8">TIP4P water model</A><BR> 4.9 <A HREF = "#4_9">SPC water model</A><BR> 4.10 <A HREF = "#4_10">Coupling LAMMPS to other codes</A><BR> 4.11 <A HREF = "#4_11">Visualizing LAMMPS snapshots</A><BR> 4.12 <A HREF = "#4_12">Triclinic (non-orthogonal) simulation boxes</A><BR> 4.13 <A HREF = "#4_13">NEMD simulations</A><BR> 4.14 <A HREF = "#4_14">Extended spherical and aspherical particles</A><BR> 4.15 <A HREF = "#4_15">Output from LAMMPS (thermo, dumps, computes, fixes, variables)</A><BR> 4.16 <A HREF = "#4_16">Thermostatting, barostatting and computing temperature</A><BR> 4.17 <A HREF = "#4_17">Walls</A><BR> 4.18 <A HREF = "#4_18">Elastic constants</A><BR> 4.19 <A HREF = "#4_19">Library interface to LAMMPS</A><BR> 4.20 <A HREF = "#4_20">Calculating thermal conductivity</A><BR> 4.21 <A HREF = "#4_21">Calculating viscosity</A> <BR> <P>The example input scripts included in the LAMMPS distribution and highlighted in <A HREF = "Section_example.html">this section</A> also show how to setup and run various kinds of simulations. </P> <HR> <A NAME = "4_1"></A><H4>4.1 Restarting a simulation </H4> <P>There are 3 ways to continue a long LAMMPS simulation. Multiple <A HREF = "run.html">run</A> commands can be used in the same input script. Each run will continue from where the previous run left off. Or binary restart files can be saved to disk using the <A HREF = "restart.html">restart</A> command. At a later time, these binary files can be read via a <A HREF = "read_restart.html">read_restart</A> command in a new script. Or they can be converted to text data files and read by a <A HREF = "read_data.html">read_data</A> command in a new script. <A HREF = "Section_tools.html">This section</A> discusses the <I>restart2data</I> tool that is used to perform the conversion. </P> <P>Here we give examples of 2 scripts that read either a binary restart file or a converted data file and then issue a new run command to continue where the previous run left off. They illustrate what settings must be made in the new script. Details are discussed in the documentation for the <A HREF = "read_restart.html">read_restart</A> and <A HREF = "read_data.html">read_data</A> commands. </P> <P>Look at the <I>in.chain</I> input script provided in the <I>bench</I> directory of the LAMMPS distribution to see the original script that these 2 scripts are based on. If that script had the line </P> <PRE>restart 50 tmp.restart </PRE> <P>added to it, it would produce 2 binary restart files (tmp.restart.50 and tmp.restart.100) as it ran. </P> <P>This script could be used to read the 1st restart file and re-run the last 50 timesteps: </P> <PRE>read_restart tmp.restart.50 </PRE> <PRE>neighbor 0.4 bin neigh_modify every 1 delay 1 </PRE> <PRE>fix 1 all nve fix 2 all langevin 1.0 1.0 10.0 904297 </PRE> <PRE>timestep 0.012 </PRE> <PRE>run 50 </PRE> <P>Note that the following commands do not need to be repeated because their settings are included in the restart file: <I>units, atom_style, special_bonds, pair_style, bond_style</I>. However these commands do need to be used, since their settings are not in the restart file: <I>neighbor, fix, timestep</I>. </P> <P>If you actually use this script to perform a restarted run, you will notice that the thermodynamic data match at step 50 (if you also put a "thermo 50" command in the original script), but do not match at step 100. This is because the <A HREF = "fix_langevin.html">fix langevin</A> command uses random numbers in a way that does not allow for perfect restarts. </P> <P>As an alternate approach, the restart file could be converted to a data file using this tool: </P> <PRE>restart2data tmp.restart.50 tmp.restart.data </PRE> <P>Then, this script could be used to re-run the last 50 steps: </P> <PRE>units lj atom_style bond pair_style lj/cut 1.12 pair_modify shift yes bond_style fene special_bonds 0.0 1.0 1.0 </PRE> <PRE>read_data tmp.restart.data </PRE> <PRE>neighbor 0.4 bin neigh_modify every 1 delay 1 </PRE> <PRE>fix 1 all nve fix 2 all langevin 1.0 1.0 10.0 904297 </PRE> <PRE>timestep 0.012 </PRE> <PRE>reset_timestep 50 run 50 </PRE> <P>Note that nearly all the settings specified in the original <I>in.chain</I> script must be repeated, except the <I>pair_coeff</I> and <I>bond_coeff</I> commands since the new data file lists the force field coefficients. Also, the <A HREF = "reset_timestep.html">reset_timestep</A> command is used to tell LAMMPS the current timestep. This value is stored in restart files, but not in data files. </P> <HR> <A NAME = "4_2"></A><H4>4.2 2d simulations </H4> <P>Use the <A HREF = "dimension.html">dimension</A> command to specify a 2d simulation. </P> <P>Make the simulation box periodic in z via the <A HREF = "boundary.html">boundary</A> command. This is the default. </P> <P>If using the <A HREF = "create_box.html">create box</A> command to define a simulation box, set the z dimensions narrow, but finite, so that the create_atoms command will tile the 3d simulation box with a single z plane of atoms - e.g. </P> <PRE><A HREF = "create_box.html">create box</A> 1 -10 10 -10 10 -0.25 0.25 </PRE> <P>If using the <A HREF = "read_data.html">read data</A> command to read in a file of atom coordinates, set the "zlo zhi" values to be finite but narrow, similar to the create_box command settings just described. For each atom in the file, assign a z coordinate so it falls inside the z-boundaries of the box - e.g. 0.0. </P> <P>Use the <A HREF = "fix_enforce2d.html">fix enforce2d</A> command as the last defined fix to insure that the z-components of velocities and forces are zeroed out every timestep. The reason to make it the last fix is so that any forces induced by other fixes will be zeroed out. </P> <P>Many of the example input scripts included in the LAMMPS distribution are for 2d models. </P> <P>IMPORTANT NOTE: Some models in LAMMPS treat particles as extended spheres, as opposed to point particles. In 2d, the particles will still be spheres, not disks, meaning their moment of inertia will be the same as in 3d. </P> <HR> <A NAME = "4_3"></A><H4>4.3 CHARMM, AMBER, and DREIDING force fields </H4> <P>A force field has 2 parts: the formulas that define it and the coefficients used for a particular system. Here we only discuss formulas implemented in LAMMPS that correspond to formulas commonly used in the CHARMM, AMBER, and DREIDING force fields. Setting coefficients is done in the input data file via the <A HREF = "read_data.html">read_data</A> command or in the input script with commands like <A HREF = "pair_coeff.html">pair_coeff</A> or <A HREF = "bond_coeff.html">bond_coeff</A>. See <A HREF = "Section_tools.html">this section</A> for additional tools that can use CHARMM or AMBER to assign force field coefficients and convert their output into LAMMPS input. </P> <P>See <A HREF = "#MacKerell">(MacKerell)</A> for a description of the CHARMM force field. See <A HREF = "#Cornell">(Cornell)</A> for a description of the AMBER force field. </P> <P>These style choices compute force field formulas that are consistent with common options in CHARMM or AMBER. See each command's documentation for the formula it computes. </P> <UL><LI><A HREF = "bond_harmonic.html">bond_style</A> harmonic <LI><A HREF = "angle_charmm.html">angle_style</A> charmm <LI><A HREF = "dihedral_charmm.html">dihedral_style</A> charmm <LI><A HREF = "pair_charmm.html">pair_style</A> lj/charmm/coul/charmm <LI><A HREF = "pair_charmm.html">pair_style</A> lj/charmm/coul/charmm/implicit <LI><A HREF = "pair_charmm.html">pair_style</A> lj/charmm/coul/long </UL> <UL><LI><A HREF = "special_bonds.html">special_bonds</A> charmm <LI><A HREF = "special_bonds.html">special_bonds</A> amber </UL> <P>DREIDING is a generic force field developed by the <A HREF = "http://www.wag.caltech.edu">Goddard group</A> at Caltech and is useful for predicting structures and dynamics of organic, biological and main-group inorganic molecules. The philosophy in DREIDING is to use general force constants and geometry parameters based on simple hybridization considerations, rather than individual force constants and geometric parameters that depend on the particular combinations of atoms involved in the bond, angle, or torsion terms. DREIDING has an <A HREF = "pair_hbond_dreiding.html">explicit hydrogen bond term</A> to describe interactions involving a hydrogen atom on very electronegative atoms (N, O, F). </P> <P>See <A HREF = "#Mayo">(Mayo)</A> for a description of the DREIDING force field </P> <P>These style choices compute force field formulas that are consistent with the DREIDING force field. See each command's documentation for the formula it computes. </P> <UL><LI><A HREF = "bond_harmonic.html">bond_style</A> harmonic <LI><A HREF = "bond_morse.html">bond_style</A> morse </UL> <UL><LI><A HREF = "angle_harmonic.html">angle_style</A> harmonic <LI><A HREF = "angle_cosine.html">angle_style</A> cosine <LI><A HREF = "angle_cosine_periodic.html">angle_style</A> cosine/periodic </UL> <UL><LI><A HREF = "dihedral_charmm.html">dihedral_style</A> charmm <LI><A HREF = "improper_umbrella.html">improper_style</A> umbrella </UL> <UL><LI><A HREF = "pair_buck.html">pair_style</A> buck <LI><A HREF = "pair_buck.html">pair_style</A> buck/coul/cut <LI><A HREF = "pair_buck.html">pair_style</A> buck/coul/long <LI><A HREF = "pair_lj.html">pair_style</A> lj/cut <LI><A HREF = "pair_lj.html">pair_style</A> lj/cut/coul/cut <LI><A HREF = "pair_lj.html">pair_style</A> lj/cut/coul/long </UL> <UL><LI><A HREF = "pair_hbond_dreiding.html">pair_style</A> hbond/dreiding/lj <LI><A HREF = "pair_hbond_dreiding.html">pair_style</A> hbond/dreiding/morse </UL> <UL><LI><A HREF = "special_bonds.html">special_bonds</A> dreiding </UL> <HR> <A NAME = "4_4"></A><H4>4.4 Running multiple simulations from one input script </H4> <P>This can be done in several ways. See the documentation for individual commands for more details on how these examples work. </P> <P>If "multiple simulations" means continue a previous simulation for more timesteps, then you simply use the <A HREF = "run.html">run</A> command multiple times. For example, this script </P> <PRE>units lj atom_style atomic read_data data.lj run 10000 run 10000 run 10000 run 10000 run 10000 </PRE> <P>would run 5 successive simulations of the same system for a total of 50,000 timesteps. </P> <P>If you wish to run totally different simulations, one after the other, the <A HREF = "clear.html">clear</A> command can be used in between them to re-initialize LAMMPS. For example, this script </P> <PRE>units lj atom_style atomic read_data data.lj run 10000 clear units lj atom_style atomic read_data data.lj.new run 10000 </PRE> <P>would run 2 independent simulations, one after the other. </P> <P>For large numbers of independent simulations, you can use <A HREF = "variable.html">variables</A> and the <A HREF = "next.html">next</A> and <A HREF = "jump.html">jump</A> commands to loop over the same input script multiple times with different settings. For example, this script, named in.polymer </P> <PRE>variable d index run1 run2 run3 run4 run5 run6 run7 run8 shell cd $d read_data data.polymer run 10000 shell cd .. clear next d jump in.polymer </PRE> <P>would run 8 simulations in different directories, using a data.polymer file in each directory. The same concept could be used to run the same system at 8 different temperatures, using a temperature variable and storing the output in different log and dump files, for example </P> <PRE>variable a loop 8 variable t index 0.8 0.85 0.9 0.95 1.0 1.05 1.1 1.15 log log.$a read data.polymer velocity all create $t 352839 fix 1 all nvt $t $t 100.0 dump 1 all atom 1000 dump.$a run 100000 next t next a jump in.polymer </PRE> <P>All of the above examples work whether you are running on 1 or multiple processors, but assumed you are running LAMMPS on a single partition of processors. LAMMPS can be run on multiple partitions via the "-partition" command-line switch as described in <A HREF = "Section_start.html#2_6">this section</A> of the manual. </P> <P>In the last 2 examples, if LAMMPS were run on 3 partitions, the same scripts could be used if the "index" and "loop" variables were replaced with <I>universe</I>-style variables, as described in the <A HREF = "variable.html">variable</A> command. Also, the "next t" and "next a" commands would need to be replaced with a single "next a t" command. With these modifications, the 8 simulations of each script would run on the 3 partitions one after the other until all were finished. Initially, 3 simulations would be started simultaneously, one on each partition. When one finished, that partition would then start the 4th simulation, and so forth, until all 8 were completed. </P> <HR> <A NAME = "4_5"></A><H4>4.5 Multi-replica simulations </H4> <P>Several commands in LAMMPS run mutli-replica simulations, meaning that multiple instances (replicas) of your simulation are run simultaneously, with small amounts of data exchanged between replicas periodically. </P> <P>These are the relevant commands: </P> <UL><LI><A HREF = "neb.html">neb</A> for nudged elastic band calculations <LI><A HREF = "prd.html">prd</A> for parallel replica dynamics <LI><A HREF = "tad.html">tad</A> for temperature accelerated dynamics <LI><A HREF = "temper.html">temper</A> for parallel tempering </UL> <P>NEB is a method for finding transition states and barrier energies. PRD and TAD are methods for performing accelerated dynamics to find and perform infrequent events. Parallel tempering or replica exchange runs different replicas at a series of temperature to facilitate rare-event sampling. </P> <P>These command can only be used if LAMMPS was built with the "replica" package. See the <A HREF = "Section_start.html#2_3">Making LAMMPS</A> section for more info on packages. </P> <P>In all these cases, you must run with one or more processors per replica. The processors assigned to each replica are determined at run-time by using the <A HREF = "Section_start.html#2_6">-partition command-line switch</A> to launch LAMMPS on multiple partitions, which in this context are the same as replicas. E.g. these commands: </P> <PRE>mpirun -np 16 lmp_linux -partition 8x2 -in in.temper mpirun -np 8 lmp_linux -partition 8x1 -in in.neb </PRE> <P>would each run 8 replicas, on either 16 or 8 processors. Note the use of the <A HREF = "Section_start.html#2_6">-in command-line switch</A> to specify the input script which is required when running in multi-replica mode. </P> <P>Also note that with MPI installed on a machine (e.g. your desktop), you can run on more (virtual) processors than you have physical processors. Thus the above commands could be run on a single-processor (or few-processor) desktop so that you can run a multi-replica simulation on more replicas than you have physical processors. </P> <HR> <A NAME = "4_6"></A><H4>4.6 Granular models </H4> <P>Granular system are composed of spherical particles with a diameter, as opposed to point particles. This means they have an angular velocity and torque can be imparted to them to cause them to rotate. </P> <P>To run a simulation of a granular model, you will want to use the following commands: </P> <UL><LI><A HREF = "atom_style.html">atom_style</A> granular <LI><A HREF = "fix_nve_sphere.html">fix nve/sphere</A> <LI><A HREF = "fix_gravity.html">fix gravity</A> </UL> <P>This compute </P> <UL><LI><A HREF = "compute_erotate_sphere.html">compute erotate/sphere</A> </UL> <P>calculates rotational kinetic energy which can be <A HREF = "Section_howto.html#4_15">output with thermodynamic info</A>. </P> <P>Use one of these 3 pair potentials, which compute forces and torques between interacting pairs of particles: </P> <UL><LI><A HREF = "pair_style.html">pair_style</A> gran/history <LI><A HREF = "pair_style.html">pair_style</A> gran/no_history <LI><A HREF = "pair_style.html">pair_style</A> gran/hertzian </UL> <P>These commands implement fix options specific to granular systems: </P> <UL><LI><A HREF = "fix_freeze.html">fix freeze</A> <LI><A HREF = "fix_pour.html">fix pour</A> <LI><A HREF = "fix_viscous.html">fix viscous</A> <LI><A HREF = "fix_wall_gran.html">fix wall/gran</A> </UL> <P>The fix style <I>freeze</I> zeroes both the force and torque of frozen atoms, and should be used for granular system instead of the fix style <I>setforce</I>. </P> <P>For computational efficiency, you can eliminate needless pairwise computations between frozen atoms by using this command: </P> <UL><LI><A HREF = "neigh_modify.html">neigh_modify</A> exclude </UL> <HR> <A NAME = "4_7"></A><H4>4.7 TIP3P water model </H4> <P>The TIP3P water model as implemented in CHARMM <A HREF = "#MacKerell">(MacKerell)</A> specifies a 3-site rigid water molecule with charges and Lennard-Jones parameters assigned to each of the 3 atoms. In LAMMPS the <A HREF = "fix_shake.html">fix shake</A> command can be used to hold the two O-H bonds and the H-O-H angle rigid. A bond style of <I>harmonic</I> and an angle style of <I>harmonic</I> or <I>charmm</I> should also be used. </P> <P>These are the additional parameters (in real units) to set for O and H atoms and the water molecule to run a rigid TIP3P-CHARMM model with a cutoff. The K values can be used if a flexible TIP3P model (without fix shake) is desired. If the LJ epsilon and sigma for HH and OH are set to 0.0, it corresponds to the original 1983 TIP3P model <A HREF = "#Jorgensen">(Jorgensen)</A>. </P> <P>O mass = 15.9994<BR> H mass = 1.008 <BR> </P> <P>O charge = -0.834<BR> H charge = 0.417 <BR> </P> <P>LJ epsilon of OO = 0.1521<BR> LJ sigma of OO = 3.1507<BR> LJ epsilon of HH = 0.0460<BR> LJ sigma of HH = 0.4000<BR> LJ epsilon of OH = 0.0836<BR> LJ sigma of OH = 1.7753 <BR> </P> <P>K of OH bond = 450<BR> r0 of OH bond = 0.9572 <BR> </P> <P>K of HOH angle = 55<BR> theta of HOH angle = 104.52 <BR> </P> <P>These are the parameters to use for TIP3P with a long-range Coulombic solver (Ewald or PPPM in LAMMPS), see <A HREF = "#Price">(Price)</A> for details: </P> <P>O mass = 15.9994<BR> H mass = 1.008 <BR> </P> <P>O charge = -0.830<BR> H charge = 0.415 <BR> </P> <P>LJ epsilon of OO = 0.102<BR> LJ sigma of OO = 3.188<BR> LJ epsilon, sigma of OH, HH = 0.0 <BR> </P> <P>K of OH bond = 450<BR> r0 of OH bond = 0.9572 <BR> </P> <P>K of HOH angle = 55<BR> theta of HOH angle = 104.52 <BR> </P> <P>Wikipedia also has a nice article on <A HREF = "http://en.wikipedia.org/wiki/Water_model">water models</A>. </P> <HR> <A NAME = "4_8"></A><H4>4.8 TIP4P water model </H4> <P>The four-point TIP4P rigid water model extends the traditional three-point TIP3P model by adding an additional site, usually massless, where the charge associated with the oxygen atom is placed. This site M is located at a fixed distance away from the oxygen along the bisector of the HOH bond angle. A bond style of <I>harmonic</I> and an angle style of <I>harmonic</I> or <I>charmm</I> should also be used. </P> <P>Currently, only a four-point model for long-range Coulombics is implemented via the LAMMPS <A HREF = "pair_lj.html">pair style lj/cut/coul/long/tip4p</A>. A cutoff version may be added the future. For both models, the bond lengths and bond angles should be held fixed using the <A HREF = "fix_shake.html">fix shake</A> command. </P> <P>These are the additional parameters (in real units) to set for O and H atoms and the water molecule to run a rigid TIP4P model with a cutoff <A HREF = "#Jorgensen">(Jorgensen)</A>. Note that the OM distance is specified in the <A HREF = "pair_style.html">pair_style</A> command, not as part of the pair coefficients. </P> <P>O mass = 15.9994<BR> H mass = 1.008 <BR> </P> <P>O charge = -1.040<BR> H charge = 0.520 <BR> </P> <P>r0 of OH bond = 0.9572<BR> theta of HOH angle = 104.52 <BR> </P> <P>OM distance = 0.15 <BR> </P> <P>LJ epsilon of O-O = 0.1550<BR> LJ sigma of O-O = 3.1536<BR> LJ epsilon, sigma of OH, HH = 0.0 <BR> </P> <P>These are the parameters to use for TIP4P with a long-range Coulombic solver (Ewald or PPPM in LAMMPS): </P> <P>O mass = 15.9994<BR> H mass = 1.008 <BR> </P> <P>O charge = -1.0484<BR> H charge = 0.5242 <BR> </P> <P>r0 of OH bond = 0.9572<BR> theta of HOH angle = 104.52 <BR> </P> <P>OM distance = 0.1250 <BR> </P> <P>LJ epsilon of O-O = 0.16275<BR> LJ sigma of O-O = 3.16435<BR> LJ epsilon, sigma of OH, HH = 0.0 <BR> </P> <P>Wikipedia also has a nice article on <A HREF = "http://en.wikipedia.org/wiki/Water_model">water models</A>. </P> <HR> <A NAME = "4_9"></A><H4>4.9 SPC water model </H4> <P>The SPC water model specifies a 3-site rigid water molecule with charges and Lennard-Jones parameters assigned to each of the 3 atoms. In LAMMPS the <A HREF = "fix_shake.html">fix shake</A> command can be used to hold the two O-H bonds and the H-O-H angle rigid. A bond style of <I>harmonic</I> and an angle style of <I>harmonic</I> or <I>charmm</I> should also be used. </P> <P>These are the additional parameters (in real units) to set for O and H atoms and the water molecule to run a rigid SPC model. </P> <P>O mass = 15.9994<BR> H mass = 1.008 <BR> </P> <P>O charge = -0.820<BR> H charge = 0.410 <BR> </P> <P>LJ epsilon of OO = 0.1553<BR> LJ sigma of OO = 3.166<BR> LJ epsilon, sigma of OH, HH = 0.0 <BR> </P> <P>r0 of OH bond = 1.0<BR> theta of HOH angle = 109.47 <BR> </P> <P>Note that as originally proposed, the SPC model was run with a 9 Angstrom cutoff for both LJ and Coulommbic terms. It can also be used with long-range Coulombics (Ewald or PPPM in LAMMPS), without changing any of the parameters above, though it becomes a different model in that mode of usage. </P> <P>The SPC/E (extended) water model is the same, except the partial charge assignemnts change: </P> <P>O charge = -0.8476<BR> H charge = 0.4238 <BR> </P> <P>See the <A HREF = "#Berendsen">(Berendsen)</A> reference for more details on both the SPC and SPC/E models. </P> <P>Wikipedia also has a nice article on <A HREF = "http://en.wikipedia.org/wiki/Water_model">water models</A>. </P> <HR> <A NAME = "4_10"></A><H4>4.10 Coupling LAMMPS to other codes </H4> <P>LAMMPS is designed to allow it to be coupled to other codes. For example, a quantum mechanics code might compute forces on a subset of atoms and pass those forces to LAMMPS. Or a continuum finite element (FE) simulation might use atom positions as boundary conditions on FE nodal points, compute a FE solution, and return interpolated forces on MD atoms. </P> <P>LAMMPS can be coupled to other codes in at least 3 ways. Each has advantages and disadvantages, which you'll have to think about in the context of your application. </P> <P>(1) Define a new <A HREF = "fix.html">fix</A> command that calls the other code. In this scenario, LAMMPS is the driver code. During its timestepping, the fix is invoked, and can make library calls to the other code, which has been linked to LAMMPS as a library. This is the way the <A HREF = "http://www.rpi.edu/~anderk5/lab">POEMS</A> package that performs constrained rigid-body motion on groups of atoms is hooked to LAMMPS. See the <A HREF = "fix_poems.html">fix_poems</A> command for more details. See <A HREF = "Section_modify.html">this section</A> of the documentation for info on how to add a new fix to LAMMPS. </P> <P>(2) Define a new LAMMPS command that calls the other code. This is conceptually similar to method (1), but in this case LAMMPS and the other code are on a more equal footing. Note that now the other code is not called during the timestepping of a LAMMPS run, but between runs. The LAMMPS input script can be used to alternate LAMMPS runs with calls to the other code, invoked via the new command. The <A HREF = "run.html">run</A> command facilitates this with its <I>every</I> option, which makes it easy to run a few steps, invoke the command, run a few steps, invoke the command, etc. </P> <P>In this scenario, the other code can be called as a library, as in (1), or it could be a stand-alone code, invoked by a system() call made by the command (assuming your parallel machine allows one or more processors to start up another program). In the latter case the stand-alone code could communicate with LAMMPS thru files that the command writes and reads. </P> <P>See <A HREF = "Section_modify.html">this section</A> of the documentation for how to add a new command to LAMMPS. </P> <P>(3) Use LAMMPS as a library called by another code. In this case the other code is the driver and calls LAMMPS as needed. Or a wrapper code could link and call both LAMMPS and another code as libraries. Again, the <A HREF = "run.html">run</A> command has options that allow it to be invoked with minimal overhead (no setup or clean-up) if you wish to do multiple short runs, driven by another program. </P> <P>Examples of driver codes that call LAMMPS as a library are included in the "couple" directory of the LAMMPS distribution; see couple/README for more details: </P> <UL><LI>simple: simple driver programs in C++ and C which invoke LAMMPS as a library <LI>lammps_quest: coupling of LAMMPS and <A HREF = "http://dft.sandia.gov/Quest">Quest</A>, to run classical MD with quantum forces calculated by a density functional code <LI>lammps_spparks: coupling of LAMMPS and <A HREF = "http://www.sandia.gov/~sjplimp/spparks.html">SPPARKS</A>, to couple a kinetic Monte Carlo model for grain growth using MD to calculate strain induced across grain boundaries </UL> <P><A HREF = "Section_start.html#2_4">This section</A> of the documentation describes how to build LAMMPS as a library. Once this is done, you can interface with LAMMPS either via C++, C, Fortran, or Python (or any other language that supports a vanilla C-like interface). For example, from C++ you could create one (or more) "instances" of LAMMPS, pass it an input script to process, or execute individual commands, all by invoking the correct class methods in LAMMPS. From C or Fortran you can make function calls to do the same things. See <A HREF = "Section_python.html">this section</A> of the manual for a description of the Python wrapper provided with LAMMPS that operates through the LAMMPS library interface. </P> <P>The files src/library.cpp and library.h contain the C-style interface to LAMMPS. See <A HREF = "Section_howto.html#4_19">this section</A> of the manual for a description of the interface and how to extend it for your needs. </P> <P>Note that the lammps_open() function that creates an instance of LAMMPS takes an MPI communicator as an argument. This means that instance of LAMMPS will run on the set of processors in the communicator. Thus the calling code can run LAMMPS on all or a subset of processors. For example, a wrapper script might decide to alternate between LAMMPS and another code, allowing them both to run on all the processors. Or it might allocate half the processors to LAMMPS and half to the other code and run both codes simultaneously before syncing them up periodically. Or it might instantiate multiple instances of LAMMPS to perform different calculations. </P> <HR> <A NAME = "4_11"></A><H4>4.11 Visualizing LAMMPS snapshots </H4> <P>LAMMPS itself does not do visualization, but snapshots from LAMMPS simulations can be visualized (and analyzed) in a variety of ways. </P> <P>LAMMPS snapshots are created by the <A HREF = "dump.html">dump</A> command which can create files in several formats. The native LAMMPS dump format is a text file (see "dump atom" or "dump custom") which can be visualized by the <A HREF = "Section_tools.html#xmovie">xmovie</A> program, included with the LAMMPS package. This produces simple, fast 2d projections of 3d systems, and can be useful for rapid debugging of simulation geometry and atom trajectories. </P> <P>Several programs included with LAMMPS as auxiliary tools can convert native LAMMPS dump files to other formats. See the <A HREF = "Section_tools.html">Section_tools</A> doc page for details. The first is the <A HREF = "Section_tools.html#charmm">ch2lmp tool</A>, which contains a lammps2pdb Perl script which converts LAMMPS dump files into PDB files. The second is the <A HREF = "Section_tools.html#arc">lmp2arc tool</A> which converts LAMMPS dump files into Accelrys' Insight MD program files. The third is the <A HREF = "Section_tools.html#cfg">lmp2cfg tool</A> which converts LAMMPS dump files into CFG files which can be read into the <A HREF = "http://mt.seas.upenn.edu/Archive/Graphics/A">AtomEye</A> visualizer. </P> <P>A Python-based toolkit distributed by our group can read native LAMMPS dump files, including custom dump files with additional columns of user-specified atom information, and convert them to various formats or pipe them into visualization software directly. See the <A HREF = "http://www.sandia.gov/~sjplimp/pizza.html">Pizza.py WWW site</A> for details. Specifically, Pizza.py can convert LAMMPS dump files into PDB, XYZ, <A HREF = "http://www.ensight.com">Ensight</A>, and VTK formats. Pizza.py can pipe LAMMPS dump files directly into the Raster3d and RasMol visualization programs. Pizza.py has tools that do interactive 3d OpenGL visualization and one that creates SVG images of dump file snapshots. </P> <P>LAMMPS can create XYZ files directly (via "dump xyz") which is a simple text-based file format used by many visualization programs including <A HREF = "http://www.ks.uiuc.edu/Research/vmd">VMD</A>. </P> <P>LAMMPS can create DCD files directly (via "dump dcd") which can be read by <A HREF = "http://www.ks.uiuc.edu/Research/vmd">VMD</A> in conjunction with a CHARMM PSF file. Using this form of output avoids the need to convert LAMMPS snapshots to PDB files. See the <A HREF = "dump.html">dump</A> command for more information on DCD files. </P> <P>LAMMPS can create XTC files directly (via "dump xtc") which is GROMACS file format which can also be read by <A HREF = "http://www.ks.uiuc.edu/Research/vmd">VMD</A> for visualization. See the <A HREF = "dump.html">dump</A> command for more information on XTC files. </P> <HR> <A NAME = "4_12"></A><H4>4.12 Triclinic (non-orthogonal) simulation boxes </H4> <P>By default, LAMMPS uses an orthogonal simulation box to encompass the particles. The <A HREF = "boundary.html">boundary</A> command sets the boundary conditions of the box (periodic, non-periodic, etc). The orthogonal box has its "origin" at (xlo,ylo,zlo) and is defined by 3 edge vectors starting from the origin given by A = (xhi-xlo,0,0); B = (0,yhi-ylo,0); C = (0,0,zhi-zlo). The 6 parameters (xlo,xhi,ylo,yhi,zlo,zhi) are defined at the time the simluation box is created, e.g. by the <A HREF = "create_box.html">create_box</A> or <A HREF = "read_data.html">read_data</A> or <A HREF = "read_restart.html">read_restart</A> commands. Additionally, LAMMPS defines box size parameters lx,ly,lz where lx = xhi-xlo, and similarly in the y and z dimensions. The 6 parameters, as well as lx,ly,lz, can be output via the <A HREF = "thermo_style.html">thermo_style custom</A> command. </P> <P>LAMMPS also allows simulations to be perfored in non-orthogonal simulation boxes shaped as a parallelepiped with triclinic symmetry. The parallelepiped has its "origin" at (xlo,ylo,zlo) and is defined by 3 edge vectors starting from the origin given by A = (xhi-xlo,0,0); B = (xy,yhi-ylo,0); C = (xz,yz,zhi-zlo). <I>Xy,xz,yz</I> can be 0.0 or positive or negative values and are called "tilt factors" because they are the amount of displacement applied to faces of an originally orthogonal box to transform it into the parallelepiped. Note that in LAMMPS the triclinic simulation box edge vectors A,B,C cannot be arbitrary vectors. As indicated, A must be aligned with the x axis, B must be in the xy plane, and C is arbitrary. However, this is not a restriction since it is possible to rotate any set of 3 crystal basis vectors so that they meet this restriction. </P> <P>The 9 parameters (xlo,xhi,ylo,yhi,zlo,zhi,xy,xz,yz) are defined at the time the simluation box is created. This happens in one of 3 ways. If the <A HREF = "create_box.html">create_box</A> command is used with a region of style <I>prism</I>, then a triclinic box is setup. See the <A HREF = "region.html">region</A> command for details. If the <A HREF = "read_data.html">read_data</A> command is used to define the simulation box, and the header of the data file contains a line with the "xy xz yz" keyword, then a triclinic box is setup. See the <A HREF = "read_data.html">read_data</A> command for details. Finally, if the <A HREF = "read_restart.html">read_restart</A> command reads a restart file which was written from a simulation using a triclinic box, then a triclinic box will be setup for the restarted simulation. </P> <P>Note that you can define a triclinic box with all 3 tilt factors = 0.0, so that it is initially orthogonal. This is necessary if the box will become non-orthogonal, e.g. due to the <A HREF = "fix_nh.html">fix npt</A> or <A HREF = "fix_deform.html">fix deform</A> commands. Alternatively, you can use the <A HREF = "change_box.html">change_box</A> command to convert a simulation box from orthogonal to triclinic and vice versa. </P> <P>As with orthogonal boxes, LAMMPS defines triclinic box size parameters lx,ly,lz where lx = xhi-xlo, and similarly in the y and z dimensions. The 9 parameters, as well as lx,ly,lz, can be output via the <A HREF = "thermo_style.html">thermo_style custom</A> command. </P> <P>To avoid extremely tilted boxes (which would be computationally inefficient), no tilt factor can skew the box more than half the distance of the parallel box length, which is the 1st dimension in the tilt factor (x for xz). For example, if xlo = 2 and xhi = 12, then the x box length is 10 and the xy tilt factor must be between -5 and 5. Similarly, both xz and yz must be between -(xhi-xlo)/2 and +(yhi-ylo)/2. Note that this is not a limitation, since if the maximum tilt factor is 5 (as in this example), then configurations with tilt = ..., -15, -5, 5, 15, 25, ... are geometrically all equivalent. </P> <P>Triclinic crystal structures are often defined using three lattice constants <I>a</I>, <I>b</I>, and <I>c</I>, and three angles <I>alpha</I>, <I>beta</I> and <I>gamma</I>. Note that in this nomenclature, the a,b,c lattice constants are the scalar lengths of the 3 A,B,C edge vectors defined above. The relationship between these 6 quantities (a,b,c,alpha,beta,gamma) and the LAMMPS box sizes (lx,ly,lz) = (xhi-xlo,yhi-ylo,zhi-zlo) and tilt factors (xy,xz,yz) is as follows: </P> <CENTER><IMG SRC = "Eqs/box.jpg"> </CENTER> <P>As discussed on the <A HREF = "dump.html">dump</A> command doc page, when the BOX BOUNDS for a snapshot is written to a dump file for a triclinic box, an orthogonal bounding box which encloses the triclinic simulation box is output, along with the 3 tilt factors (xy, xz, yz) of the triclinic box, formatted as follows: </P> <PRE>ITEM: BOX BOUNDS xy xz yz xlo_bound xhi_bound xy ylo_bound yhi_bound xz zlo_bound zhi_bound yz </PRE> <P>This bounding box is convenient for many visualization programs and is calculated from the 9 triclinic box parameters (xlo,xhi,ylo,yhi,zlo,zhi,xy,xz,yz) as follows: </P> <PRE>xlo_bound = xlo + MIN(0.0,xy,xz,xy+xz) xhi_bound = xhi + MAX(0.0,xy,xz,xy+xz) ylo_bound = ylo + MIN(0.0,yz) yhi_bound = yhi + MAX(0.0,yz) zlo_bound = zlo zhi_bound = zhi </PRE> <P>These formulas can be inverted if you need to convert the bounding box back into the triclinic box parameters, e.g. xlo = xlo_bound - MIN(0.0,xy,xz,xy+xz). </P> <P>One use of triclinic simulation boxes is to model solid-state crystals with triclinic symmetry. The <A HREF = "lattice.html">lattice</A> command can be used with non-orthogonal basis vectors to define a lattice that will tile a triclinic simulation box via the <A HREF = "create_atoms.html">create_atoms</A> command. </P> <P>A second use is to run Parinello-Rahman dyanamics via the <A HREF = "fix_nh.html">fix npt</A> command, which will adjust the xy, xz, yz tilt factors to compensate for off-diagonal components of the pressure tensor. The analalog for an <A HREF = "minimize.html">energy minimization</A> is the <A HREF = "fix_box_relax.html">fix box/relax</A> command. </P> <P>A third use is to shear a bulk solid to study the response of the material. The <A HREF = "fix_deform.html">fix deform</A> command can be used for this purpose. It allows dynamic control of the xy, xz, yz tilt factors as a simulation runs. This is discussed in the next section on non-equilibrium MD (NEMD) simulations. </P> <HR> <A NAME = "4_13"></A><H4>4.13 NEMD simulations </H4> <P>Non-equilibrium molecular dynamics or NEMD simulations are typically used to measure a fluid's rheological properties such as viscosity. In LAMMPS, such simulations can be performed by first setting up a non-orthogonal simulation box (see the preceding Howto section). </P> <P>A shear strain can be applied to the simulation box at a desired strain rate by using the <A HREF = "fix_deform.html">fix deform</A> command. The <A HREF = "fix_nvt_sllod.html">fix nvt/sllod</A> command can be used to thermostat the sheared fluid and integrate the SLLOD equations of motion for the system. Fix nvt/sllod uses <A HREF = "compute_temp_deform.html">compute temp/deform</A> to compute a thermal temperature by subtracting out the streaming velocity of the shearing atoms. The velocity profile or other properties of the fluid can be monitored via the <A HREF = "fix_ave_spatial.html">fix ave/spatial</A> command. </P> <P>As discussed in the previous section on non-orthogonal simulation boxes, the amount of tilt or skew that can be applied is limited by LAMMPS for computational efficiency to be 1/2 of the parallel box length. However, <A HREF = "fix_deform.html">fix deform</A> can continuously strain a box by an arbitrary amount. As discussed in the <A HREF = "fix_deform.html">fix deform</A> command, when the tilt value reaches a limit, the box is re-shaped to the opposite limit which is an equivalent tiling of periodic space. The strain rate can then continue to change as before. In a long NEMD simulation these box re-shaping events may occur many times. </P> <P>In a NEMD simulation, the "remap" option of <A HREF = "fix_deform.html">fix deform</A> should be set to "remap v", since that is what <A HREF = "fix_nvt_sllod.html">fix nvt/sllod</A> assumes to generate a velocity profile consistent with the applied shear strain rate. </P> <P>An alternative method for calculating viscosities is provided via the <A HREF = "fix_viscosity.html">fix viscosity</A> command. </P> <HR> <A NAME = "4_14"></A><H4>4.14 Extended spherical and aspherical particles </H4> <P>Typical MD models treat atoms or particles as point masses. Sometimes, however, it is desirable to have a model with finite-size particles such as spherioids or aspherical ellipsoids. The difference is that such particles have a moment of inertia, rotational energy, and angular momentum. Rotation is induced by torque from interactions with other particles. </P> <P>LAMMPS has several options for running simulations with these kinds of particles. The following aspects are discussed in turn: </P> <UL><LI>atom styles <LI>pair potentials <LI>time integration <LI>computes, thermodynamics, and dump output <LI>rigid bodies composed of extended particles </UL> <H5>Atom styles </H5> <P>There are 3 <A HREF = "atom_style.html">atom styles</A> that allow for definition of finite-size particles: granular, dipole, ellipsoid. </P> <P>Granular particles are spheriods and each particle can have a unique diameter and mass (or density). These particles store an angular velocity (omega) and can be acted upon by torque. </P> <P>Dipolar particles are typically spheriods with a point dipole and each particle type has a diamater and mass, set by the <A HREF = "shape.html">shape</A> and <A HREF = "mass.html">mass</A> commands. These particles store an angular velocity (omega) and can be acted upon by torque. They also store an orientation for the point dipole (mu) which has a length set by the <A HREF = "dipole.html">dipole</A> command. The <A HREF = "set.html">set</A> command can be used to initialize the orientation of dipole moments. </P> <P>Ellipsoid particles are aspherical. Each particle type has an ellipsoidal shape and mass, defined by the <A HREF = "shape.html">shape</A> and <A HREF = "mass.html">mass</A> commands. These particles store an angular momentum and their orientation (quaternion), and can be acted upon by torque. They do not store an angular velocity (omega), which can be in a different direction than angular momentum, rather they compute it as needed. Ellipsoidal particles can also store a dipole moment if an <A HREF = "atom_style.html">atom_style hybrid ellipsoid dipole</A> is used. The <A HREF = "set.html">set</A> command can be used to initialize the orientation of ellipsoidal particles and has a brief explanation of quaternions. </P> <P>Note that if one of these atom styles is used (or multiple styles via the <A HREF = "atom_style.html">atom_style hybrid</A> command), not all particles in the system are required to be finite-size or aspherical. For example, if the 3 shape parameters are set to the same value, the particle will be a spheroid rather than an ellipsoid. If the 3 shape parameters are all set to 0.0 or if the diameter is set to 0.0, it will be a point particle. If the dipole moment is set to zero, the particle will not have a point dipole associated with it. The pair styles used to compute pairwise interactions will typically compute the correct interaction in these simplified (cheaper) cases. <A HREF = "pair_hybrid.html">Pair_style hybrid</A> can be used to insure the correct interactions are computed for the appropriate style of interactions. Likewise, using groups to partition particles (ellipsoid versus spheroid versus point particles) will allow you to use the appropriate time integrators and temperature computations for each class of particles. See the doc pages for various commands for details. </P> <P>Also note that for <A HREF = "dimension.html">2d simulations</A>, finite-size spheroids and ellipsoids are still treated as 3d particles, rather than as disks or ellipses. This means they have the same moment of inertia for a 3d extended object. When their temperature is coomputed, the correct degrees of freedom are used for rotation in a 2d versus 3d system. </P> <H5>Pair potentials </H5> <P>When a system with extended particles is defined, the particles will only rotate and experience torque if the force field computes such interactions. These are the various <A HREF = "pair_style.html">pair styles</A> that generate torque: </P> <UL><LI><A HREF = "pair_gran.html">pair_style gran/history</A> <LI><A HREF = "pair_gran.html">pair_style gran/hertzian</A> <LI><A HREF = "pair_gran.html">pair_style gran/no_history</A> <LI><A HREF = "pair_dipole.html">pair_style dipole/cut</A> <LI><A HREF = "pair_gayberne.html">pair_style gayberne</A> <LI><A HREF = "pair_resquared.html">pair_style resquared</A> <LI><A HREF = "pair_lubricate.html">pair_style lubricate</A> </UL> <P>The <A HREF = "pair_gran.html">granular pair styles</A> are used with <A HREF = "atom_style.html">atom_style granular</A>. The <A HREF = "pair_dipole.html">dipole pair style</A> is used with <A HREF = "atom_style.html">atom_style dipole</A>. The <A HREF = "pair_gayberne.html">GayBerne</A> and <A HREF = "pair_resquared.html">REsquared</A> potentials require particles have a <A HREF = "shape.html">shape</A> and are designed for <A HREF = "atom_style.html">ellipsoidal particles</A>. The <A HREF = "pair_lubricate.html">lubrication potential</A> requires that particles have a <A HREF = "shape.html">shape</A>. It can currently only be used with extended spherical particles. </P> <H5>Time integration </H5> <P>There are 3 fixes that perform time integration on extended spherical particles, meaning the integrators update the rotational orientation and angular velocity or angular momentum of the particles: </P> <UL><LI><A HREF = "fix_nve_sphere.html">fix nve/sphere</A> <LI><A HREF = "fix_nvt_sphere.html">fix nvt/sphere</A> <LI><A HREF = "fix_npt_sphere.html">fix npt/sphere</A> </UL> <P>Likewise, there are 3 fixes that perform time integration on extended aspherical particles: </P> <UL><LI><A HREF = "fix_nve_asphere.html">fix nve/asphere</A> <LI><A HREF = "fix_nvt_asphere.html">fix nvt/asphere</A> <LI><A HREF = "fix_npt_asphere.html">fix npt/asphere</A> </UL> <P>The advantage of these fixes is that those which thermostat the particles include the rotational degrees of freedom in the temperature calculation and thermostatting. Other thermostats can be used with fix nve/sphere or fix nve/asphere, such as fix langevin or fix temp/berendsen, but those thermostats only operate on the translational kinetic energy of the extended particles. </P> <P>Note that for mixtures of point and extended particles, you should only use these integration fixes on <A HREF = "group.html">groups</A> which contain extended particles. </P> <H5>Computes, thermodynamics, and dump output </H5> <P>There are 4 computes that calculate the temperature or rotational energy of extended spherical or aspherical particles: </P> <UL><LI><A HREF = "compute_temp_sphere.html">compute temp/sphere</A> <LI><A HREF = "compute_temp_asphere.html">compute temp/asphere</A> <LI><A HREF = "compute_erotate_sphere.html">compute erotate/sphere</A> <LI><A HREF = "compute_erotate_asphere.html">compute erotate/asphere</A> </UL> <P>These include rotational degrees of freedom in their computation. If you wish the thermodynamic output of temperature or pressure to use one of these computes (e.g. for a system entirely composed of extended particles), then the compute can be defined and the <A HREF = "thermo_modify.html">thermo_modify</A> command used. Note that by default thermodynamic quantities will be calculated with a temperature that only includes translational degrees of freedom. See the <A HREF = "thermo_style.html">thermo_style</A> command for details. </P> <P>The <A HREF = "dump.html">dump custom</A> command can output various attributes of extended particles, including the dipole moment (mu), the angular velocity (omega), the angular momentum (angmom), the quaternion (quat), and the torque (tq) on the particle. </P> <H5>Rigid bodies composed of extended particles </H5> <P>The <A HREF = "fix_rigid.html">fix rigid</A> command treats a collection of particles as a rigid body, computes its inertia tensor, sums the total force and torque on the rigid body each timestep due to forces on its constituent particles, and integrates the motion of the rigid body. </P> <P>(NOTE: the feature described in the following paragraph has not yet been released. It will be soon.) </P> <P>If any of the constituent particles of a rigid body are extended particles (spheroids or ellipsoids), then their contribution to the inertia tensor of the body is different than if they were point particles. This means the rotational dynamics of the rigid body will be different. Thus a model of a dimer is different if the dimer consists of two point masses versus two extended sphereoids, even if the two particles have the same mass. Extended particles that experience torque due to their interaction with other particles will also impart that torque to a rigid body they are part of. </P> <P>See the "fix rigid" command for example of complex rigid-body models it is possible to define in LAMMPS. </P> <P>Note that the <A HREF = "fix_shake.html">fix shake</A> command can also be used to treat 2, 3, or 4 particles as a rigid body, but it always assumes the particles are point masses. </P> <HR> <A NAME = "4_15"></A><H4>4.15 Output from LAMMPS (thermo, dumps, computes, fixes, variables) </H4> <P>There are four basic kinds of LAMMPS output: </P> <UL><LI><A HREF = "thermo_style.html">Thermodynamic output</A>, which is a list of quantities printed every few timesteps to the screen and logfile. <LI><A HREF = "dump.html">Dump files</A>, which contain snapshots of atoms and various per-atom values and are written at a specified frequency. <LI>Certain fixes can output user-specified quantities to files: <A HREF = "fix_ave_time.html">fix ave/time</A> for time averaging, <A HREF = "fix_ave_spatial.html">fix ave/spatial</A> for spatial averaging, and <A HREF = "fix_print.html">fix print</A> for single-line output of <A HREF = "variable.html">variables</A>. Fix print can also output to the screen. <LI><A HREF = "restart.html">Restart files</A>. </UL> <P>A simulation prints one set of thermodynamic output and (optionally) restart files. It can generate any number of dump files and fix output files, depending on what <A HREF = "dump.html">dump</A> and <A HREF = "fix.html">fix</A> commands you specify. </P> <P>As discussed below, LAMMPS gives you a variety of ways to determine what quantities are computed and printed when the thermodynamics, dump, or fix commands listed above perform output. Throughout this discussion, note that users can also <A HREF = "Section_modify.html">add their own computes and fixes to LAMMPS</A> which can then generate values that can then be output with these commands. </P> <P>The following sub-sections discuss different LAMMPS command related to output and the kind of data they operate on and produce: </P> <UL><LI><A HREF = "#global">Global/per-atom/local data</A> <LI><A HREF = "#scalar">Scalar/vector/array data</A> <LI><A HREF = "#thermo">Thermodynamic output</A> <LI><A HREF = "#dump">Dump file output</A> <LI><A HREF = "#fixoutput">Fixes that write output files</A> <LI><A HREF = "#computeoutput">Computes that process output quantities</A> <LI><A HREF = "#fixoutput">Fixes that process output quantities</A> <LI><A HREF = "#compute">Computes that generate values to output</A> <LI><A HREF = "#fix">Fixes that generate values to output</A> <LI><A HREF = "#variable">Variables that generate values to output</A> <LI><A HREF = "#table">Summary table of output options and data flow between commands</A> </UL> <H5><A NAME = "global"></A>Global/per-atom/local data </H5> <P>Various output-related commands work with three different styles of data: global, per-atom, or local. A global datum is one or more system-wide values, e.g. the temperature of the system. A per-atom datum is one or more values per atom, e.g. the kinetic energy of each atom. Local datums are calculated by each processor based on the atoms it owns, but there may be zero or more per atom, e.g. a list of bond distances. </P> <H5><A NAME = "scalar"></A>Scalar/vector/array data </H5> <P>Global, per-atom, and local datums can each come in three kinds: a single scalar value, a vector of values, or a 2d array of values. The doc page for a "compute" or "fix" or "variable" that generates data will specify both the style and kind of data it produces, e.g. a per-atom vector. </P> <P>When a quantity is accessed, as in many of the output commands discussed below, it can be referenced via the following bracket notation, where ID in this case is the ID of a compute. The leading "c_" would be replaced by "f_" for a fix, or "v_" for a variable: </P> -<DIV ALIGN=center><TABLE WIDTH="0%" BORDER=1 > +<DIV ALIGN=center><TABLE BORDER=1 > <TR><TD >c_ID </TD><TD > entire scalar, vector, or array</TD></TR> <TR><TD >c_ID[I] </TD><TD > one element of vector, one column of array</TD></TR> <TR><TD >c_ID[I][J] </TD><TD > one element of array </TD></TR></TABLE></DIV> <P>In other words, using one bracket reduces the dimension of the data once (vector -> scalar, array -> vector). Using two brackets reduces the dimension twice (array -> scalar). Thus a command that uses scalar values as input can typically also process elements of a vector or array. </P> <H5><A NAME = "thermo"></A>Thermodynamic output </H5> <P>The frequency and format of thermodynamic output is set by the <A HREF = "thermo.html">thermo</A>, <A HREF = "thermo_style.html">thermo_style</A>, and <A HREF = "thermo_modify.html">thermo_modify</A> commands. The <A HREF = "thermo_style.html">thermo_style</A> command also specifies what values are calculated and written out. Pre-defined keywords can be specified (e.g. press, etotal, etc). Three additional kinds of keywords can also be specified (c_ID, f_ID, v_name), where a <A HREF = "compute.html">compute</A> or <A HREF = "fix.html">fix</A> or <A HREF = "variable.html">variable</A> provides the value to be output. In each case, the compute, fix, or variable must generate global values for input to the <A HREF = "dump.html">thermo_style custom</A> command. </P> <H5><A NAME = "dump"></A>Dump file output </H5> <P>Dump file output is specified by the <A HREF = "dump.html">dump</A> and <A HREF = "dump_modify.html">dump_modify</A> commands. There are several pre-defined formats (dump atom, dump xtc, etc). </P> <P>There is also a <A HREF = "dump.html">dump custom</A> format where the user specifies what values are output with each atom. Pre-defined atom attributes can be specified (id, x, fx, etc). Three additional kinds of keywords can also be specified (c_ID, f_ID, v_name), where a <A HREF = "compute.html">compute</A> or <A HREF = "fix.html">fix</A> or <A HREF = "variable.html">variable</A> provides the values to be output. In each case, the compute, fix, or variable must generate per-atom values for input to the <A HREF = "dump.html">dump custom</A> command. </P> <P>There is also a <A HREF = "dump.html">dump local</A> format where the user specifies what local values to output. A pre-defined index keyword can be specified to enumuerate the local values. Two additional kinds of keywords can also be specified (c_ID, f_ID), where a <A HREF = "compute.html">compute</A> or <A HREF = "fix.html">fix</A> or <A HREF = "variable.html">variable</A> provides the values to be output. In each case, the compute or fix must generate local values for input to the <A HREF = "dump.html">dump local</A> command. </P> <H5><A NAME = "fixoutput"></A>Fixes that write output files </H5> <P>Sevarl fixes take various quantities as input and can write output files: <A HREF = "fix_ave_time.html">fix ave/time</A>, <A HREF = "fix_ave_spatial.html">fix ave/spatial</A>, <A HREF = "fix_ave_histo.html">fix ave/histo</A>, <A HREF = "fix_ave_correlate.html">fix ave/correlate</A>, and <A HREF = "fix_print.html">fix print</A>. </P> <P>The <A HREF = "fix_ave_time.html">fix ave/time</A> command enables direct output to a file and/or time-averaging of global scalars or vectors. The user specifies one or more quantities as input. These can be global <A HREF = "compute.html">compute</A> values, global <A HREF = "fix.html">fix</A> values, or <A HREF = "variable.html">variables</A> of any style except the atom style which produces per-atom values. Since a variable can refer to keywords used by the <A HREF = "thermo_style.html">thermo_style custom</A> command (like temp or press) and individual per-atom values, a wide variety of quantities can be time averaged and/or output in this way. If the inputs are one or more scalar values, then the fix generate a global scalar or vector of output. If the inputs are one or more vector values, then the fix generates a global vector or array of output. The time-averaged output of this fix can also be used as input to other output commands. </P> <P>The <A HREF = "fix_ave_spatial.html">fix ave/spatial</A> command enables direct output to a file of spatial-averaged per-atom quantities like those output in dump files, within 1d layers of the simulation box. The per-atom quantities can be atom density (mass or number) or atom attributes such as position, velocity, force. They can also be per-atom quantities calculated by a <A HREF = "compute.html">compute</A>, by a <A HREF = "fix.html">fix</A>, or by an atom-style <A HREF = "variable.html">variable</A>. The spatial-averaged output of this fix can also be used as input to other output commands. </P> <P>The <A HREF = "fix_ave_histo.html">fix ave/histo</A> command enables direct output to a file of histogrammed quantities, which can be global or per-atom or local quantities. The histogram output of this fix can also be used as input to other output commands. </P> <P>The <A HREF = "fix_ave_histo.html">fix ave/correlate</A> command enables direct output to a file of time-correlated quantities, which can be global scalars. The correlation matrix output of this fix can also be used as input to other output commands. </P> <P>The <A HREF = "fix_print.html">fix print</A> command can generate a line of output written to the screen and log file or to a separate file, periodically during a running simulation. The line can contain one or more <A HREF = "variable.html">variable</A> values for any style variable except the atom style). As explained above, variables themselves can contain references to global values generated by <A HREF = "thermo_style.html">thermodynamic keywords</A>, <A HREF = "compute.html">computes</A>, <A HREF = "fix.html">fixes</A>, or other <A HREF = "variable.html">variables</A>, or to per-atom values for a specific atom. Thus the <A HREF = "fix_print.html">fix print</A> command is a means to output a wide variety of quantities separate from normal thermodynamic or dump file output. </P> <H5><A NAME = "computeoutput"></A>Computes that process output quantities </H5> <P>The <A HREF = "compute_reduce.html">compute reduce</A> and <A HREF = "compute_reduce.html">compute reduce/region</A> commands take one or more per-atom or local vector quantities as inputs and "reduce" them (sum, min, max, ave) to scalar quantities. These are produced as output values which can be used as input to other output commands. </P> <P>The <A HREF = "compute_property_atom.html">compute property/atom</A> command takes a list of one or more pre-defined atom attributes (id, x, fx, etc) and stores the values in a per-atom vector or array. These are produced as output values which can be used as input to other output commands. The list of atom attributes is the same as for the <A HREF = "dump.html">dump custom</A> command. </P> <P>The <A HREF = "compute_property_local.html">compute property/local</A> command takes a list of one or more pre-defined local attributes (bond info, angle info, etc) and stores the values in a local vector or array. These are produced as output values which can be used as input to other output commands. </P> <P>The <A HREF = "compute_atom_molecule.html">compute atom/molecule</A> command takes a list of one or more per-atom quantities (from a compute, fix, per-atom variable) and sums the quantities on a per-molecule basis. It produces a global vector or array as output values which can be used as input to other output commands. </P> <H5><A NAME = "fixoutput"></A>Fixes that process output quantities </H5> <P>The <A HREF = "fix_ave_atom.html">fix ave/atom</A> command performs time-averaging of per-atom vectors. The per-atom quantities can be atom attributes such as position, velocity, force. They can also be per-atom quantities calculated by a <A HREF = "compute.html">compute</A>, by a <A HREF = "fix.html">fix</A>, or by an atom-style <A HREF = "variable.html">variable</A>. The time-averaged per-atom output of this fix can be used as input to other output commands. </P> <P>The <A HREF = "fix_store_state.html">fix store/state</A> command can archive one or more per-atom attributes at a particular time, so that the old values can be used in a future calculation or output. The list of atom attributes is the same as for the <A HREF = "dump.html">dump custom</A> command, including per-atom quantities calculated by a <A HREF = "compute.html">compute</A>, by a <A HREF = "fix.html">fix</A>, or by an atom-style <A HREF = "variable.html">variable</A>. The output of this fix can be used as input to other output commands. </P> <H5><A NAME = "compute"></A>Computes that generate values to output </H5> <P>Every <A HREF = "compute.html">compute</A> in LAMMPS produces either global or per-atom or local values. The values can be scalars or vectors or arrays of data. These values can be output using the other commands described in this section. The doc page for each compute command describes what it produces. Computes that produce per-atom or local values have the word "atom" or "local" in their style name. Computes without the word "atom" or "local" produce global values. </P> <H5><A NAME = "fix"></A>Fixes that generate values to output </H5> <P>Some <A HREF = "fix.html">fixes</A> in LAMMPS produces either global or per-atom or local values which can be accessed by other commands. The values can be scalars or vectors or arrays of data. These values can be output using the other commands described in this section. The doc page for each fix command tells whether it produces any output quantities and describes them. </P> <H5><A NAME = "variable"></A>Variables that generate values to output </H5> <P>Every <A HREF = "variable.html">variables</A> defined in an input script generates either a global scalar value or a per-atom vector (only atom-style variables) when it is accessed. The formulas used to define equal- and atom-style variables can contain references to the thermodynamic keywords and to global and per-atom data generated by computes, fixes, and other variables. The values generated by variables can be output using the other commands described in this section. </P> <H5><A NAME = "table"></A>Summary table of output options and data flow between commands </H5> <P>This table summarizes the various commands that can be used for generating output from LAMMPS. Each command produces output data of some kind and/or writes data to a file. Most of the commands can take data from other commands as input. Thus you can link many of these commands together in pipeline form, where data produced by one command is used as input to another command and eventually written to the screen or to a file. Note that to hook two commands together the output and input data types must match, e.g. global/per-atom/local data and scalar/vector/array data. </P> <P>Also note that, as described above, when a command takes a scalar as input, that could be an element of a vector or array. Likewise a vector input could be a column of an array. </P> -<DIV ALIGN=center><TABLE WIDTH="0%" BORDER=1 > +<DIV ALIGN=center><TABLE BORDER=1 > <TR><TD >Command</TD><TD > Input</TD><TD > Output</TD><TD ></TD></TR> <TR><TD ><A HREF = "thermo_style.html">thermo_style custom</A></TD><TD > global scalars</TD><TD > screen, log file</TD><TD ></TD></TR> <TR><TD ><A HREF = "dump.html">dump custom</A></TD><TD > per-atom vectors</TD><TD > dump file</TD><TD ></TD></TR> <TR><TD ><A HREF = "dump.html">dump local</A></TD><TD > local vectors</TD><TD > dump file</TD><TD ></TD></TR> <TR><TD ><A HREF = "fix_print.html">fix print</A></TD><TD > global scalar from variable</TD><TD > screen, file</TD><TD ></TD></TR> <TR><TD ><A HREF = "print.html">print</A></TD><TD > global scalar from variable</TD><TD > screen</TD><TD ></TD></TR> <TR><TD ><A HREF = "compute.html">computes</A></TD><TD > N/A</TD><TD > global/per-atom/local scalar/vector/array</TD><TD ></TD></TR> <TR><TD ><A HREF = "fix.html">fixes</A></TD><TD > N/A</TD><TD > global/per-atom/local scalar/vector/array</TD><TD ></TD></TR> <TR><TD ><A HREF = "variable.html">variables</A></TD><TD > global scalars, per-atom vectors</TD><TD > global scalar, per-atom vector</TD><TD ></TD></TR> <TR><TD ><A HREF = "compute_reduce.html">compute reduce</A></TD><TD > per-atom/local vectors</TD><TD > global scalar/vector</TD><TD ></TD></TR> <TR><TD ><A HREF = "compute_property_atom.html">compute property/atom</A></TD><TD > per-atom vectors</TD><TD > per-atom vector/array</TD><TD ></TD></TR> <TR><TD ><A HREF = "compute_property_local.html">compute property/local</A></TD><TD > local vectors</TD><TD > local vector/array</TD><TD ></TD></TR> <TR><TD ><A HREF = "compute_atom_molecule.html">compute atom/molecule</A></TD><TD > per-atom vectors</TD><TD > global vector/array</TD><TD ></TD></TR> <TR><TD ><A HREF = "fix_ave_atom.html">fix ave/atom</A></TD><TD > per-atom vectors</TD><TD > per-atom vector/array</TD><TD ></TD></TR> <TR><TD ><A HREF = "fix_ave_time.html">fix ave/time</A></TD><TD > global scalars/vectors</TD><TD > global scalar/vector/array, file</TD><TD ></TD></TR> <TR><TD ><A HREF = "fix_ave_spatial.html">fix ave/spatial</A></TD><TD > per-atom vectors</TD><TD > global array, file</TD><TD ></TD></TR> <TR><TD ><A HREF = "fix_ave_histo.html">fix ave/histo</A></TD><TD > global/per-atom/local scalars and vectors</TD><TD > global array, file</TD><TD ></TD></TR> <TR><TD ><A HREF = "fix_ave_correlate.html">fix ave/correlate</A></TD><TD > global scalars</TD><TD > global array, file</TD><TD ></TD></TR> <TR><TD ><A HREF = "fix_store_state.html">fix store/state</A></TD><TD > per-atom vectors</TD><TD > per-atom vector/array</TD><TD ></TD></TR> <TR><TD > </TD></TR></TABLE></DIV> <HR> <A NAME = "4_16"></A><H4>4.16 Thermostatting, barostatting, and computing temperature </H4> <P>Thermostatting means controlling the temperature of particles in an MD simulation. Barostatting means controlling the pressure. Since the pressure includes a kinetic component due to particle velocities, both these operations require calculation of the temperature. Typically a target temperature (T) and/or pressure (P) is specified by the user, and the thermostat or barostat attempts to equilibrate the system to the requested T and/or P. </P> <P>Temperature is computed as kinetic energy divided by some number of degrees of freedom (and the Boltzmann constant). Since kinetic energy is a function of particle velocity, there is often a need to distinguish between a particle's advection velocity (due to some aggregate motiion of particles) and its thermal velocity. The sum of the two is the particle's total velocity, but the latter is often what is wanted to compute a temperature. </P> <P>LAMMPS has several options for computing temperatures, any of which can be used in thermostatting and barostatting. These <A HREF = "compute.html">compute commands</A> calculate temperature, and the <A HREF = "compute_pressure.html">compute pressure</A> command calculates pressure. </P> <UL><LI><A HREF = "compute_temp.html">compute temp</A> <LI><A HREF = "compute_temp_sphere.html">compute temp/sphere</A> <LI><A HREF = "compute_temp_asphere.html">compute temp/asphere</A> <LI><A HREF = "compute_temp_com.html">compute temp/com</A> <LI><A HREF = "compute_temp_deform.html">compute temp/deform</A> <LI><A HREF = "compute_temp_partial.html">compute temp/partial</A> <LI><A HREF = "compute_temp_profile.html">compute temp/profile</A> <LI><A HREF = "compute_temp_ramp.html">compute temp/ramp</A> <LI><A HREF = "compute_temp_region.html">compute temp/region</A> </UL> <P>All but the first 3 calculate velocity biases (i.e. advection velocities) that are removed when computing the thermal temperature. <A HREF = "compute_temp_sphere.html">Compute temp/sphere</A> and <A HREF = "compute_temp_asphere.html">compute temp/asphere</A> compute kinetic energy for extended particles that includes rotational degrees of freedom. They both allow, as an extra argument, which is another temperature compute that subtracts a velocity bias. This allows the translational velocity of extended spherical or aspherical particles to be adjusted in prescribed ways. </P> <P>Thermostatting in LAMMPS is performed by <A HREF = "fix.html">fixes</A>, or in one case by a pair style. Four thermostatting fixes are currently available: Nose-Hoover (nvt), Berendsen, Langevin, and direct rescaling (temp/rescale). Dissipative particle dynamics (DPD) thermostatting can be invoked via the <I>dpd/tstat</I> pair style: </P> <UL><LI><A HREF = "fix_nh.html">fix nvt</A> <LI><A HREF = "fix_nvt_sphere.html">fix nvt/sphere</A> <LI><A HREF = "fix_nvt_asphere.html">fix nvt/asphere</A> <LI><A HREF = "fix_nvt_sllod.html">fix nvt/sllod</A> <LI><A HREF = "fix_temp_berendsen.html">fix temp/berendsen</A> <LI><A HREF = "fix_langevin.html">fix langevin</A> <LI><A HREF = "fix_temp_rescale.html">fix temp/rescale</A> <LI><A HREF = "pair_dpd.html">pair_style dpd/tstat</A> </UL> <P><A HREF = "fix_nh.html">Fix nvt</A> only thermostats the translational velocity of particles. <A HREF = "fix_nvt_sllod.html">Fix nvt/sllod</A> also does this, except that it subtracts out a velocity bias due to a deforming box and integrates the SLLOD equations of motion. See the <A HREF = "#4_13">NEMD simulations</A> section of this page for further details. <A HREF = "fix_nvt_sphere.html">Fix nvt/sphere</A> and <A HREF = "fix_nvt_asphere.html">fix nvt/asphere</A> thermostat not only translation velocities but also rotational velocities for spherical and aspherical particles. </P> <P>DPD thermostatting alters pairwise interactions in a manner analagous to the per-particle thermostatting of <A HREF = "fix_langevin.html">fix langevin</A>. </P> <P>Any of the thermostatting fixes can use temperature computes that remove bias for two purposes: (a) computing the current temperature to compare to the requested target temperature, and (b) adjusting only the thermal temperature component of the particle's velocities. See the doc pages for the individual fixes and for the <A HREF = "fix_modify.html">fix_modify</A> command for instructions on how to assign a temperature compute to a thermostatting fix. For example, you can apply a thermostat to only the x and z components of velocity by using it in conjunction with <A HREF = "compute_temp_partial.html">compute temp/partial</A>. </P> <P>IMPORTANT NOTE: Only the nvt fixes perform time integration, meaning they update the velocities and positions of particles due to forces and velocities respectively. The other thermostat fixes only adjust velocities; they do NOT perform time integration updates. Thus they should be used in conjunction with a constant NVE integration fix such as these: </P> <UL><LI><A HREF = "fix_nve.html">fix nve</A> <LI><A HREF = "fix_nve_sphere.html">fix nve/sphere</A> <LI><A HREF = "fix_nve_asphere.html">fix nve/asphere</A> </UL> <P>Barostatting in LAMMPS is also performed by <A HREF = "fix.html">fixes</A>. Two barosttating methods are currently available: Nose-Hoover (npt and nph) and Berendsen: </P> <UL><LI><A HREF = "fix_nh.html">fix npt</A> <LI><A HREF = "fix_npt_sphere.html">fix npt/sphere</A> <LI><A HREF = "fix_npt_asphere.html">fix npt/asphere</A> <LI><A HREF = "fix_nh.html">fix nph</A> <LI><A HREF = "fix_press_berendsen.html">fix press/berendsen</A> </UL> <P>The <A HREF = "fix_nh.html">fix npt</A> commands include a Nose-Hoover thermostat and barostat. <A HREF = "fix_nh.html">Fix nph</A> is just a Nose/Hoover barostat; it does no thermostatting. Both <A HREF = "fix_nh.html">fix nph</A> and <A HREF = "fix_press_berendsen.html">fix press/bernendsen</A> can be used in conjunction with any of the thermostatting fixes. </P> <P>As with the thermostats, <A HREF = "fix_nh.html">fix npt</A> and <A HREF = "fix_nh.html">fix nph</A> only use translational motion of the particles in computing T and P and performing thermo/barostatting. <A HREF = "fix_npt_sphere.html">Fix npt/sphere</A> and <A HREF = "fix_npt_asphere.html">fix npt/asphere</A> thermo/barostat using not only translation velocities but also rotational velocities for spherical and aspherical particles. </P> <P>All of the barostatting fixes use the <A HREF = "compute_pressure.html">compute pressure</A> compute to calculate a current pressure. By default, this compute is created with a simple <A HREF = "compute_temp.html">compute temp</A> (see the last argument of the <A HREF = "compute_pressure.html">compute pressure</A> command), which is used to calculated the kinetic componenet of the pressure. The barostatting fixes can also use temperature computes that remove bias for the purpose of computing the kinetic componenet which contributes to the current pressure. See the doc pages for the individual fixes and for the <A HREF = "fix_modify.html">fix_modify</A> command for instructions on how to assign a temperature or pressure compute to a barostatting fix. </P> <P>IMPORTANT NOTE: As with the thermostats, the Nose/Hoover methods (<A HREF = "fix_nh.html">fix npt</A> and <A HREF = "fix_nh.html">fix nph</A>) perform time integration. <A HREF = "fix_press_berendsen.html">Fix press/berendsen</A> does NOT, so it should be used with one of the constant NVE fixes or with one of the NVT fixes. </P> <P>Finally, thermodynamic output, which can be setup via the <A HREF = "thermo_style.html">thermo_style</A> command, often includes temperature and pressure values. As explained on the doc page for the <A HREF = "thermo_style.html">thermo_style</A> command, the default T and P are setup by the thermo command itself. They are NOT the ones associated with any thermostatting or barostatting fix you have defined or with any compute that calculates a temperature or pressure. Thus if you want to view these values of T and P, you need to specify them explicitly via a <A HREF = "thermo_style.html">thermo_style custom</A> command. Or you can use the <A HREF = "thermo_modify.html">thermo_modify</A> command to re-define what temperature or pressure compute is used for default thermodynamic output. </P> <HR> <A NAME = "4_17"></A><H4>4.17 Walls </H4> <P>Walls in an MD simulation are typically used to bound particle motion, i.e. to serve as a boundary condition. </P> <P>Walls in LAMMPS can be of rough (made of particles) or idealized surfaces. Ideal walls can be smooth, generating forces only in the normal direction, or frictional, generating forces also in the tangential direction. </P> <P>Rough walls, built of particles, can be created in various ways. The particles themselves can be generated like any other particle, via the <A HREF = "lattice.html">lattice</A> and <A HREF = "create_atoms.html">create_atoms</A> commands, or read in via the <A HREF = "read_data.html">read_data</A> command. </P> <P>Their motion can be constrained by many different commands, so that they do not move at all, move together as a group at constant velocity or in response to a net force acting on them, move in a prescribed fashion (e.g. rotate around a point), etc. Note that if a time integration fix like <A HREF = "fix_nve.html">fix nve</A> or <A HREF = "fix_nh.html">fix nvt</A> is not used with the group that contains wall particles, their positions and velocities will not be updated. </P> <UL><LI><A HREF = "fix_aveforce.html">fix aveforce</A> - set force on particles to average value, so they move together <LI><A HREF = "fix_setforce.html">fix setforce</A> - set force on particles to a value, e.g. 0.0 <LI><A HREF = "fix_freeze.html">fix freeze</A> - freeze particles for use as granular walls <LI><A HREF = "fix_nve_noforce.html">fix nve/noforce</A> - advect particles by their velocity, but without force <LI><A HREF = "fix_move.html">fix move</A> - prescribe motion of particles by a linear velocity, oscillation, rotation, variable </UL> <P>The <A HREF = "fix_move.html">fix move</A> command offers the most generality, since the motion of individual particles can be specified with <A HREF = "variable.html">variable</A> formula which depends on time and/or the particle position. </P> <P>For rough walls, it may be useful to turn off pairwise interactions between wall particles via the <A HREF = "neigh_modify.html">neigh_modify exclude</A> command. </P> <P>Rough walls can also be created by specifying frozen particles that do not move and do not interact with mobile particles, and then tethering other particles to the fixed particles, via a <A HREF = "bond_style.html">bond</A>. The bonded particles do interact with other mobile particles. </P> <P>Idealized walls can be specified via several fix commands. <A HREF = "fix_wall_gran.html">Fix wall/gran</A> creates frictional walls for use with granular particles; all the other commands create smooth walls. </P> <UL><LI><A HREF = "fix_wall_reflect.html">fix wall/reflect</A> - reflective flat walls <LI><A HREF = "fix_wall.html">fix wall/lj93</A> - flat walls, with Lennard-Jones 9/3 potential <LI><A HREF = "fix_wall.html">fix wall/lj126</A> - flat walls, with Lennard-Jones 12/6 potential <LI><A HREF = "fix_wall.html">fix wall/colloid</A> - flat walls, with <A HREF = "pair_colloid.html">pair_style colloid</A> potential <LI><A HREF = "fix_wall.html">fix wall/harmonic</A> - flat walls, with repulsive harmonic spring potential <LI><A HREF = "fix_wall_region.html">fix wall/region</A> - use region surface as wall <LI><A HREF = "fix_wall_gran.html">fix wall/gran</A> - flat or curved walls with <A HREF = "pair_gran.html">pair_style granular</A> potential </UL> <P>The <I>lj93</I>, <I>lj126</I>, <I>colloid</I>, and <I>harmonic</I> styles all allow the flat walls to move with a constant velocity, or oscillate in time. The <A HREF = "fix_wall_region.html">fix wall/region</A> command offers the most generality, since the region surface is treated as a wall, and the geometry of the region can be a simple primitive volume (e.g. a sphere, or cube, or plane), or a complex volume made from the union and intersection of primitive volumes. <A HREF = "region.html">Regions</A> can also specify a volume "interior" or "exterior" to the specified primitive shape or <I>union</I> or <I>intersection</I>. <A HREF = "region.html">Regions</A> can also be "dynamic" meaning they move with constant velocity, oscillate, or rotate. </P> <P>The only frictional idealized walls currently in LAMMPS are flat or curved surfaces specified by the <A HREF = "fix_wall_gran.html">fix wall/gran</A> command. At some point we plan to allow regoin surfaces to be used as frictional walls, as well as triangulated surfaces. </P> <HR> <A NAME = "4_18"></A><H4>4.18 Elastic constants </H4> <P>Elastic constants characterize the stiffness of a material. The formal definition is provided by the linear relation that holds between the stress and strain tensors in the limit of infinitesimal deformation. In tensor notation, this is expressed as s_ij = C_ijkl * e_kl, where the repeated indices imply summation. s_ij are the elements of the symmetric stress tensor. e_kl are the elements of the symmetric strain tensor. C_ijkl are the elements of the fourth rank tensor of elastic constants. In three dimensions, this tensor has 3^4=81 elements. Using Voigt notation, the tensor can be written as a 6x6 matrix, where C_ij is now the derivative of s_i w.r.t. e_j. Because s_i is itself a derivative w.r.t. e_i, it follows that C_ij is also symmetric, with at most 7*6/2 = 21 distinct elements. </P> <P>At zero temperature, it is easy to estimate these derivatives by deforming the cell in one of the six directions using the command <A HREF = "displace_box.html">displace_box</A> and measuring the change in the stress tensor. A general-purpose script that does this is given in the examples/elastic directory described in <A HREF = "Section_example.html">this section</A>. </P> <P>Calculating elastic constants at finite temperature is more challenging, because it is necessary to run a simulation that perfoms time averages of differential properties. One way to do this is to measure the change in average stress tensor in an NVT simulations when the cell volume undergoes a finite deformation. In order to balance the systematic and statistical errors in this method, the magnitude of the deformation must be chosen judiciously, and care must be taken to fully equilibrate the deformed cell before sampling the stress tensor. Another approach is to sample the triclinic cell fluctuations that occur in an NPT simulation. This method can also be slow to converge and requires careful post-processing <A HREF = "#Shinoda">(Shinoda)</A> </P> <HR> <A NAME = "4_19"></A><H4>4.19 Library interface to LAMMPS </H4> <P>As described in <A HREF = "Section_start.html#2_4">this section</A>, LAMMPS can be built as a library, so that it can be called by another code, used in a <A HREF = "Section_howto.html#4_10">coupled manner</A> with other codes, or driven through a <A HREF = "Section_python.html">Python interface</A>. </P> <P>All of these methodologies use a C-style interface to LAMMPS that is provided in the files src/library.cpp and src/library.h. The functions therein have a C-style argument list, but contain C++ code you could write yourself in a C++ application that was invoking LAMMPS directly. The C++ code in the functions illustrates how to invoke internal LAMMPS operations. Note that LAMMPS classes are defined within a LAMMPS namespace (LAMMPS_NS) if you use them from another C++ application. </P> <P>Library.cpp contains these 4 functions: </P> <PRE>void lammps_open(int, char **, MPI_Comm, void **); void lammps_close(void *); void lammps_file(void *, char *); char *lammps_command(void *, char *); </PRE> <P>The lammps_open() function is used to initialize LAMMPS, passing in a list of strings as if they were <A HREF = "#2_6">command-line arguments</A> when LAMMPS is run in stand-alone mode from the command line, and a MPI communicator for LAMMPS to run under. It returns a ptr to the LAMMPS object that is created, and which is used in subsequent library calls. The lammps_open() function can be called multiple times, to create multiple instances of LAMMPS. </P> <P>LAMMPS will run on the set of processors in the communicator. This means the calling code can run LAMMPS on all or a subset of processors. For example, a wrapper script might decide to alternate between LAMMPS and another code, allowing them both to run on all the processors. Or it might allocate half the processors to LAMMPS and half to the other code and run both codes simultaneously before syncing them up periodically. Or it might instantiate multiple instances of LAMMPS to perform different calculations. </P> <P>The lammps_close() function is used to shut down an instance of LAMMPS and free all its memory. </P> <P>The lammps_file() and lammps_command() functions are used to pass a file or string to LAMMPS as if it were an input script or single command in an input script. Thus the calling code can read or generate a series of LAMMPS commands one line at a time and pass it thru the library interface to setup a problem and then run it, interleaving the lammps_command() calls with other calls to extract information from LAMMPS, perform its own operations, or call another code's library. </P> <P>Other useful functions are also included in library.cpp. For example: </P> <PRE>void *lammps_extract_global(void *, char *) void *lammps_extract_atom(void *, char *) void *lammps_extract_compute(void *, char *, int, int) void *lammps_extract_fix(void *, char *, int, int, int, int) void *lammps_extract_variable(void *, char *, char *) int lammps_get_natoms(void *) void lammps_get_coords(void *, double *) void lammps_put_coords(void *, double *) </PRE> <P>These can extract various global or per-atom quantities from LAMMPS as well as values calculated by a compute, fix, or variable. The "get" and "put" operations can retrieve and reset atom coordinates. See the library.cpp file and its associated header file library.h for details. </P> <P>The key idea of the library interface is that you can write any functions you wish to define how your code talks to LAMMPS and add them to src/library.cpp and src/library.h, as well as to the <A HREF = "Section_python.html">Python interface</A>. The routines you add can access or change any LAMMPS data you wish. The couple and python directories have example C++ and C and Python codes which show how a driver code can link to LAMMPS as a library, run LAMMPS on a subset of processors, grab data from LAMMPS, change it, and put it back into LAMMPS. </P> <HR> <A NAME = "4_20"></A><H4>4.20 Calculating thermal conductivity </H4> <P>The thermal conductivity kappa of a material can be measured in at least 3 ways using various options in LAMMPS. (See <A HREF = "Section_howto.html#4_21">this section</A> of the manual for an analogous discussion for viscosity). The thermal conducitivity tensor kappa is a measure of the propensity of a material to transmit heat energy in a diffusive manner as given by Fourier's law </P> <P>J = -kappa grad(T) </P> <P>where J is the heat flux in units of energy per area per time and grad(T) is the spatial gradient of temperature. The thermal conductivity thus has units of energy per distance per time per degree K and is often approximated as an isotropic quantity, i.e. as a scalar. </P> <P>The first method is to setup two thermostatted regions at opposite ends of a simulation box, or one in the middle and one at the end of a periodic box. By holding the two regions at different temperatures with a <A HREF = "Section_howto.html#4_13">thermostatting fix</A>, the energy added to the hot region should equal the energy subtracted from the cold region and be proportional to the heat flux moving between the regions. See the paper by <A HREF = "#Ikeshoji">Ikeshoji and Hafskjold</A> for details of this idea. Note that thermostatting fixes such as <A HREF = "fix_nh.html">fix nvt</A>, <A HREF = "fix_langevin.html">fix langevin</A>, and <A HREF = "fix_temp_rescale.html">fix temp/rescale</A> store the cumulative energy they add/subtract. Alternatively, the <A HREF = "fix_heat.html">fix heat</A> command can used in place of thermostats on each of two regions, and the resulting temperatures of the two regions monitored with the "compute temp/region" command or the temperature profile of the intermediate region monitored with the <A HREF = "fix_ave_spatial.html">fix ave/spatial</A> and <A HREF = "compute_ke_atom.html">compute ke/atom</A> commands. </P> <P>The second method is to perform a reverse non-equilibrium MD simulation using the <A HREF = "fix_thermal_conductivity.html">fix thermal/conductivity</A> command which implements the rNEMD algorithm of Muller-Plathe. Kinetic energy is swapped between atoms in two different layers of the simulation box. This induces a temperature gradient between the two layers which can be monitored with the <A HREF = "fix_ave_spatial.html">fix ave/spatial</A> and <A HREF = "compute_ke_atom.html">compute ke/atom</A> commands. The fix tallies the cumulative energy transfer that it performs. See the <A HREF = "fix_thermal_conductivity.html">fix thermal/conductivity</A> command for details. </P> <P>The third method is based on the Green-Kubo (GK) formula which relates the ensemble average of the auto-correlation of the heat flux to kappa. The heat flux can be calculated from the fluctuations of per-atom potential and kinetic energies and per-atom stress tensor in a steady-state equilibrated simulation. This is in contrast to the two preceding non-equilibrium methods, where energy flows continuously between hot and cold regions of the simulation box. </P> <P>The <A HREF = "compute_heat_flux.html">compute heat/flux</A> command can calculate the needed heat flux and describes how to implement the Green_Kubo formalism using additional LAMMPS commands, such as the <A HREF = "fix_ave_correlate.html">fix ave/correlate</A> command to calculate the needed auto-correlation. See the doc page for the <A HREF = "compute_heat_flux.html">compute heat/flux</A> command for an example input script that calculates the thermal conductivity of solid Ar via the GK formalism. </P> <HR> <A NAME = "4_21"></A><H4>4.21 Calculating viscosity </H4> <P>The shear viscosity eta of a fluid can be measured in at least 3 ways using various options in LAMMPS. (See <A HREF = "Section_howto.html#4_20">this section</A> of the manual for an analogous discussion for thermal conductivity). Eta is a measure of the propensity of a fluid to transmit momentum in a direction perpendicular to the direction of velocity or momentum flow. Alternatively it is the resistance the fluid has to being sheared. It is given by </P> <P>J = -eta grad(Vstream) </P> <P>where J is the momentum flux in units of momentum per area per time. and grad(Vstream) is the spatial gradient of the velocity of the fluid moving in another direction, normal to the area through which the momentum flows. Viscosity thus has units of pressure-time. </P> <P>The first method is to perform a non-equlibrium MD (NEMD) simulation by shearing the simulation box via the <A HREF = "fix_deform.html">fix deform</A> command, and using the <A HREF = "fix_nvt_sllod.html">fix nvt/sllod</A> command to thermostat the fluid via the SLLOD equations of motion. The velocity profile setup in the fluid by this procedure can be monitored by the <A HREF = "fix_ave_spatial.html">fix ave/spatial</A> command, which determines grad(Vstream) in the equation above. E.g. the derivative in the y-direction of the Vx component of fluid motion or grad(Vstream) = dVx/dy. In this case, the Pxy off-diagonal component of the pressure or stress tensor, as calculated by the <A HREF = "compute_pressure.html">compute pressure</A> command, can also be monitored, which is the J term in the equation above. See <A HREF = "Section_howto.html#4_13">this section</A> of the manual for details on NEMD simulations. </P> <P>The second method is to perform a reverse non-equilibrium MD simulation using the <A HREF = "fix_viscosity.html">fix viscosity</A> command which implements the rNEMD algorithm of Muller-Plathe. Momentum in one dimension is swapped between atoms in two different layers of the simulation box in a different dimension. This induces a velocity gradient which can be monitored with the <A HREF = "fix_ave_spatial.html">fix ave/spatial</A> command. The fix tallies the cummulative momentum transfer that it performs. See the <A HREF = "fix_viscosity.html">fix viscosity</A> command for details. </P> <P>The third method is based on the Green-Kubo (GK) formula which relates the ensemble average of the auto-correlation of the stress/pressure tensor to eta. This can be done in a steady-state equilibrated simulation which is in contrast to the two preceding non-equilibrium methods, where momentum flows continuously through the simulation box. </P> <P>Here is an example input script that calculates the viscosity of liquid Ar via the GK formalism: </P> <PRE># Sample LAMMPS input script for viscosity of liquid Ar </PRE> <PRE>units real variable T equal 86.4956 variable V equal vol variable dt equal 4.0 variable p equal 400 # correlation length variable s equal 5 # sample interval variable d equal $p*$s # dump interval </PRE> <PRE># convert from LAMMPS real units to SI </PRE> <PRE>variable kB equal 1.3806504e-23 # [J/K/</B> Boltzmann variable atm2Pa equal 101325.0 variable A2m equal 1.0e-10 variable fs2s equal 1.0e-15 variable convert equal ${atm2Pa}*${atm2Pa}*${fs2s}*${A2m}*${A2m}*${A2m} </PRE> <PRE># setup problem </PRE> <PRE>dimension 3 boundary p p p lattice fcc 5.376 orient x 1 0 0 orient y 0 1 0 orient z 0 0 1 region box block 0 4 0 4 0 4 create_box 1 box create_atoms 1 box mass 1 39.948 pair_style lj/cut 13.0 pair_coeff * * 0.2381 3.405 timestep ${dt} thermo $d </PRE> <PRE># equilibration and thermalization </PRE> <PRE>velocity all create $T 102486 mom yes rot yes dist gaussian fix NVT all nvt temp $T $T 10 drag 0.2 run 8000 </PRE> <PRE># viscosity calculation, switch to NVE if desired </PRE> <PRE>#unfix NVT #fix NVE all nve </PRE> <PRE>reset_timestep 0 variable pxy equal pxy variable pxz equal pxz variable pyz equal pyz fix SS all ave/correlate $s $p $d & v_pxy v_pxz v_pyz type auto file S0St.dat ave running variable scale equal ${convert}/(${kB}*$T)*$V*$s*${dt} variable v11 equal trap(f_SS[3/</B>)*${scale} variable v22 equal trap(f_SS[4/</B>)*${scale} variable v33 equal trap(f_SS[5/</B>)*${scale} thermo_style custom step temp press v_pxy v_pxz v_pyz v_v11 v_v22 v_v33 run 100000 variable v equal (v_v11+v_v22+v_v33)/3.0 variable ndens equal count(all)/vol print "average viscosity: $v [Pa.s/</B> @ $T K, ${ndens} /A^3" </PRE> <HR> <HR> <A NAME = "Berendsen"></A> <P><B>(Berendsen)</B> Berendsen, Grigera, Straatsma, J Phys Chem, 91, 6269-6271 (1987). </P> <A NAME = "Cornell"></A> <P><B>(Cornell)</B> Cornell, Cieplak, Bayly, Gould, Merz, Ferguson, Spellmeyer, Fox, Caldwell, Kollman, JACS 117, 5179-5197 (1995). </P> <A NAME = "Horn"></A> <P><B>(Horn)</B> Horn, Swope, Pitera, Madura, Dick, Hura, and Head-Gordon, J Chem Phys, 120, 9665 (2004). </P> <A NAME = "Ikeshoji"></A> <P><B>(Ikeshoji)</B> Ikeshoji and Hafskjold, Molecular Physics, 81, 251-261 (1994). </P> <A NAME = "MacKerell"></A> <P><B>(MacKerell)</B> MacKerell, Bashford, Bellott, Dunbrack, Evanseck, Field, Fischer, Gao, Guo, Ha, et al, J Phys Chem, 102, 3586 (1998). </P> <A NAME = "Mayo"></A> <P><B>(Mayo)</B> Mayo, Olfason, Goddard III, J Phys Chem, 94, 8897-8909 (1990). </P> <A NAME = "Jorgensen"></A> <P><B>(Jorgensen)</B> Jorgensen, Chandrasekhar, Madura, Impey, Klein, J Chem Phys, 79, 926 (1983). </P> <A NAME = "Price"></A> <P><B>(Price)</B> Price and Brooks, J Chem Phys, 121, 10096 (2004). </P> <A NAME = "Shinoda"></A> <P><B>(Shinoda)</B> Shinoda, Shiga, and Mikami, Phys Rev B, 69, 134103 (2004). </P> </HTML> diff --git a/doc/Section_intro.html b/doc/Section_intro.html index 5e7cd6e06..f9b00bb68 100644 --- a/doc/Section_intro.html +++ b/doc/Section_intro.html @@ -1,624 +1,625 @@ <HTML> <CENTER><A HREF = "Manual.html">Previous Section</A> - <A HREF = "http://lammps.sandia.gov">LAMMPS WWW Site</A> - <A HREF = "Manual.html">LAMMPS Documentation</A> - <A HREF = "Section_commands.html#comm">LAMMPS Commands</A> - <A HREF = "Section_start.html">Next Section</A> </CENTER> <HR> <H3>1. Introduction </H3> <P>These sections provide an overview of what LAMMPS can and can't do, describe what it means for LAMMPS to be an open-source code, and acknowledge the funding and people who have contributed to LAMMPS over the years. </P> 1.1 <A HREF = "#1_1">What is LAMMPS</A><BR> 1.2 <A HREF = "#1_2">LAMMPS features</A><BR> 1.3 <A HREF = "#1_3">LAMMPS non-features</A><BR> 1.4 <A HREF = "#1_4">Open source distribution</A><BR> 1.5 <A HREF = "#1_5">Acknowledgments and citations</A> <BR> <HR> <A NAME = "1_1"></A><H4>1.1 What is LAMMPS </H4> <P>LAMMPS is a classical molecular dynamics code that models an ensemble of particles in a liquid, solid, or gaseous state. It can model atomic, polymeric, biological, metallic, granular, and coarse-grained systems using a variety of force fields and boundary conditions. </P> <P>For examples of LAMMPS simulations, see the Publications page of the <A HREF = "http://lammps.sandia.gov">LAMMPS WWW Site</A>. </P> <P>LAMMPS runs efficiently on single-processor desktop or laptop machines, but is designed for parallel computers. It will run on any parallel machine that compiles C++ and supports the <A HREF = "http://www-unix.mcs.anl.gov/mpi">MPI</A> message-passing library. This includes distributed- or shared-memory parallel machines and Beowulf-style clusters. </P> <P>LAMMPS can model systems with only a few particles up to millions or billions. See <A HREF = "Section_perf.html">this section</A> for information on LAMMPS performance and scalability, or the Benchmarks section of the <A HREF = "http://lammps.sandia.gov">LAMMPS WWW Site</A>. </P> <P>LAMMPS is a freely-available open-source code, distributed under the terms of the <A HREF = "http://www.gnu.org/copyleft/gpl.html">GNU Public License</A>, which means you can use or modify the code however you wish. See <A HREF = "#1_4">this section</A> for a brief discussion of the open-source philosophy. </P> <P>LAMMPS is designed to be easy to modify or extend with new capabilities, such as new force fields, atom types, boundary conditions, or diagnostics. See <A HREF = "Section_modify.html">this section</A> for more details. </P> <P>The current version of LAMMPS is written in C++. Earlier versions were written in F77 and F90. See <A HREF = "Section_history.html">this section</A> for more information on different versions. All versions can be downloaded from the <A HREF = "http://lammps.sandia.gov">LAMMPS WWW Site</A>. </P> <P>LAMMPS was originally developed under a US Department of Energy CRADA (Cooperative Research and Development Agreement) between two DOE labs and 3 companies. It is distributed by <A HREF = "http://www.sandia.gov">Sandia National Labs</A>. See <A HREF = "#1_5">this section</A> for more information on LAMMPS funding and individuals who have contributed to LAMMPS. </P> <P>In the most general sense, LAMMPS integrates Newton's equations of motion for collections of atoms, molecules, or macroscopic particles that interact via short- or long-range forces with a variety of initial and/or boundary conditions. For computational efficiency LAMMPS uses neighbor lists to keep track of nearby particles. The lists are optimized for systems with particles that are repulsive at short distances, so that the local density of particles never becomes too large. On parallel machines, LAMMPS uses spatial-decomposition techniques to partition the simulation domain into small 3d sub-domains, one of which is assigned to each processor. Processors communicate and store "ghost" atom information for atoms that border their sub-domain. LAMMPS is most efficient (in a parallel sense) for systems whose particles fill a 3d rectangular box with roughly uniform density. Papers with technical details of the algorithms used in LAMMPS are listed in <A HREF = "#1_5">this section</A>. </P> <HR> <A NAME = "1_2"></A><H4>1.2 LAMMPS features </H4> <P>This section highlights LAMMPS features, with pointers to specific commands which give more details. If LAMMPS doesn't have your favorite interatomic potential, boundary condition, or atom type, see <A HREF = "Section_modify.html">this section</A>, which describes how you can add it to LAMMPS. </P> <H4>General features </H4> <UL><LI> runs on a single processor or in parallel <LI> distributed-memory message-passing parallelism (MPI) <LI> spatial-decomposition of simulation domain for parallelism <LI> open-source distribution <LI> highly portable C++ <LI> optional libraries used: MPI and single-processor FFT <LI> easy to extend with new features and functionality <LI> runs from an input script <LI> syntax for defining and using variables and formulas <LI> syntax for looping over runs and breaking out of loops <LI> run one or multiple simulations simultaneously (in parallel) from one script <LI> build as library, invoke LAMMPS thru library interface or provided Python wrapper <LI> couple with other codes: LAMMPS calls other code, other code calls LAMMPS, umbrella code calls both </UL> <H4>Particle and model types </H4> <P>(<A HREF = "atom_style.html">atom style</A> command) </P> <UL><LI> atoms <LI> coarse-grained particles (e.g. bead-spring polymers) <LI> united-atom polymers or organic molecules <LI> all-atom polymers, organic molecules, proteins, DNA <LI> metals <LI> granular materials <LI> coarse-grained mesoscale models <LI> extended spherical and ellipsoidal particles <LI> point dipolar particles <LI> rigid collections of particles <LI> hybrid combinations of these </UL> <H4>Force fields </H4> <P>(<A HREF = "pair_style.html">pair style</A>, <A HREF = "bond_style.html">bond style</A>, <A HREF = "angle_style.html">angle style</A>, <A HREF = "dihedral_style.html">dihedral style</A>, <A HREF = "improper_style.html">improper style</A>, <A HREF = "kspace_style.html">kspace style</A> commands) </P> <UL><LI> pairwise potentials: Lennard-Jones, Buckingham, Morse, Born-Mayer-Huggins, Yukawa, soft, class 2 (COMPASS), hydrogen bond, tabulated <LI> charged pairwise potentials: Coulombic, point-dipole <LI> manybody potentials: EAM, Finnis/Sinclair EAM, modified EAM (MEAM), embedded ion method (EIM), Stillinger-Weber, Tersoff, AI-REBO, ReaxFF, COMB <LI> electron force field (eFF) <LI> coarse-grained potentials: DPD, GayBerne, REsquared, colloidal, DLVO <LI> mesoscopic potentials: granular, Peridynamics <LI> bond potentials: harmonic, FENE, Morse, nonlinear, class 2, quartic (breakable) <LI> angle potentials: harmonic, CHARMM, cosine, cosine/squared, cosine/periodic, class 2 (COMPASS) <LI> dihedral potentials: harmonic, CHARMM, multi-harmonic, helix, class 2 (COMPASS), OPLS <LI> improper potentials: harmonic, cvff, umbrella, class 2 (COMPASS) <LI> polymer potentials: all-atom, united-atom, bead-spring, breakable <LI> water potentials: TIP3P, TIP4P, SPC <LI> implicit solvent potentials: hydrodynamic lubrication, Debye <LI> long-range Coulombics and dispersion: Ewald, PPPM (similar to particle-mesh Ewald), Ewald/N for long-range Lennard-Jones <LI> force-field compatibility with common CHARMM, AMBER, DREIDING, OPLS, GROMACS, COMPASS options <LI> handful of GPU-enabled pair styles </UL> <P> hybrid potentials: multiple pair, bond, angle, dihedral, improper potentials can be used in one simulation overlaid potentials: superposition of multiple pair potentials </P> <H4>Atom creation </H4> <P>(<A HREF = "read_data.html">read_data</A>, <A HREF = "lattice.html">lattice</A>, <A HREF = "create_atoms.html">create_atoms</A>, <A HREF = "delete_atoms.html">delete_atoms</A>, <A HREF = "displace_atoms.html">displace_atoms</A>, <A HREF = "replicate.html">replicate</A> commands) </P> <UL><LI> read in atom coords from files <LI> create atoms on one or more lattices (e.g. grain boundaries) <LI> delete geometric or logical groups of atoms (e.g. voids) <LI> replicate existing atoms multiple times <LI> displace atoms </UL> <H4>Ensembles, constraints, and boundary conditions </H4> <P>(<A HREF = "fix.html">fix</A> command) </P> <UL><LI> 2d or 3d systems <LI> orthogonal or non-orthogonal (triclinic symmetry) simulation domains <LI> constant NVE, NVT, NPT, NPH, Parinello/Rahman integrators <LI> thermostatting options for groups and geometric regions of atoms <LI> pressure control via Nose/Hoover or Berendsen barostatting in 1 to 3 dimensions <LI> simulation box deformation (tensile and shear) <LI> harmonic (umbrella) constraint forces <LI> rigid body constraints <LI> SHAKE bond and angle constraints <LI> bond breaking, formation, swapping <LI> walls of various kinds <LI> non-equilibrium molecular dynamics (NEMD) <LI> variety of additional boundary conditions and constraints </UL> <H4>Integrators </H4> <P>(<A HREF = "run.html">run</A>, <A HREF = "run_style.html">run_style</A>, <A HREF = "minimize.html">minimize</A> commands) </P> <UL><LI> velocity-Verlet integrator <LI> Brownian dynamics <LI> rigid body integration <LI> energy minimization via conjugate gradient or steepest descent relaxation <LI> rRESPA hierarchical timestepping </UL> <H4>Diagnostics </H4> <UL><LI> see the various flavors of the <A HREF = "fix.html">fix</A> and <A HREF = "compute.html">compute</A> commands </UL> <H4>Output </H4> <P>(<A HREF = "dump.html">dump</A>, <A HREF = "restart.html">restart</A> commands) </P> <UL><LI> log file of thermodynamic info <LI> text dump files of atom coords, velocities, other per-atom quantities <LI> binary restart files <LI> parallel I/O of dump and restart files <LI> per-atom quantities (energy, stress, centro-symmetry parameter, CNA, etc) <LI> user-defined system-wide (log file) or per-atom (dump file) calculations <LI> spatial and time averaging of per-atom quantities <LI> time averaging of system-wide quantities <LI> atom snapshots in native, XYZ, XTC, DCD, CFG formats </UL> <H4>Multi-replica models </H4> <P><A HREF = "neb.html">nudged elastic band</A> <A HREF = "prd.html">parallel replica dynamics</A> +<A HREF = "tad.html">temperature accelerated dynamics</A> <A HREF = "temper.html">parallel tempering</A> </P> <H4>Pre- and post-processing </H4> <UL><LI>Various pre- and post-processing serial tools are packaged with LAMMPS; see these <A HREF = "Section_tools.html">doc pages</A>. <LI>Our group has also written and released a separate toolkit called <A HREF = "http://www.sandia.gov/~sjplimp/pizza.html">Pizza.py</A> which provides tools for doing setup, analysis, plotting, and visualization for LAMMPS simulations. Pizza.py is written in <A HREF = "http://www.python.org">Python</A> and is available for download from <A HREF = "http://www.sandia.gov/~sjplimp/pizza.html">the Pizza.py WWW site</A>. </UL> <H4>Specialized features </H4> <P>These are LAMMPS capabilities which you may not think of as typical molecular dynamics options: </P> <UL><LI><A HREF = "fix_srd.html">stochastic rotation dynamics (SRD)</A> <LI><A HREF = "fix_imd.html">real-time visualization and interactive MD</A> <LI><A HREF = "fix_atc.html">atom-to-continuum coupling</A> with finite elements <LI>coupled rigid body integration via the <A HREF = "fix_poems.html">POEMS</A> library <LI><A HREF = "pair_dsmc.html">Direct Simulation Monte Carlo</A> for low-density fluids <LI><A HREF = "pair_peri.html">Peridynamics mesoscale modeling</A> <LI><A HREF = "fix_tmd.html">targeted</A> and <A HREF = "fix_smd.html">steered</A> molecular dynamics <LI><A HREF = "fix_ttm.html">two-temperature electron model</A> </UL> <HR> <A NAME = "1_3"></A><H4>1.3 LAMMPS non-features </H4> <P>LAMMPS is designed to efficiently compute Newton's equations of motion for a system of interacting particles. Many of the tools needed to pre- and post-process the data for such simulations are not included in the LAMMPS kernel for several reasons: </P> <UL><LI>the desire to keep LAMMPS simple <LI>they are not parallel operations <LI>other codes already do them <LI>limited development resources </UL> <P>Specifically, LAMMPS itself does not: </P> <UL><LI>run thru a GUI <LI>build molecular systems <LI>assign force-field coefficients automagically <LI>perform sophisticated analyses of your MD simulation <LI>visualize your MD simulation <LI>plot your output data </UL> <P>A few tools for pre- and post-processing tasks are provided as part of the LAMMPS package; they are described in <A HREF = "Section_tools.html">this section</A>. However, many people use other codes or write their own tools for these tasks. </P> <P>As noted above, our group has also written and released a separate toolkit called <A HREF = "http://www.sandia.gov/~sjplimp/pizza.html">Pizza.py</A> which addresses some of the listed bullets. It provides tools for doing setup, analysis, plotting, and visualization for LAMMPS simulations. Pizza.py is written in <A HREF = "http://www.python.org">Python</A> and is available for download from <A HREF = "http://www.sandia.gov/~sjplimp/pizza.html">the Pizza.py WWW site</A>. </P> <P>LAMMPS requires as input a list of initial atom coordinates and types, molecular topology information, and force-field coefficients assigned to all atoms and bonds. LAMMPS will not build molecular systems and assign force-field parameters for you. </P> <P>For atomic systems LAMMPS provides a <A HREF = "create_atoms.html">create_atoms</A> command which places atoms on solid-state lattices (fcc, bcc, user-defined, etc). Assigning small numbers of force field coefficients can be done via the <A HREF = "pair_coeff.html">pair coeff</A>, <A HREF = "bond_coeff.html">bond coeff</A>, <A HREF = "angle_coeff.html">angle coeff</A>, etc commands. For molecular systems or more complicated simulation geometries, users typically use another code as a builder and convert its output to LAMMPS input format, or write their own code to generate atom coordinate and molecular topology for LAMMPS to read in. </P> <P>For complicated molecular systems (e.g. a protein), a multitude of topology information and hundreds of force-field coefficients must typically be specified. We suggest you use a program like <A HREF = "http://www.scripps.edu/brooks">CHARMM</A> or <A HREF = "http://amber.scripps.edu">AMBER</A> or other molecular builders to setup such problems and dump its information to a file. You can then reformat the file as LAMMPS input. Some of the tools in <A HREF = "Section_tools.html">this section</A> can assist in this process. </P> <P>Similarly, LAMMPS creates output files in a simple format. Most users post-process these files with their own analysis tools or re-format them for input into other programs, including visualization packages. If you are convinced you need to compute something on-the-fly as LAMMPS runs, see <A HREF = "Section_modify.html">this section</A> for a discussion of how you can use the <A HREF = "dump.html">dump</A> and <A HREF = "compute.html">compute</A> and <A HREF = "fix.html">fix</A> commands to print out data of your choosing. Keep in mind that complicated computations can slow down the molecular dynamics timestepping, particularly if the computations are not parallel, so it is often better to leave such analysis to post-processing codes. </P> <P>A very simple (yet fast) visualizer is provided with the LAMMPS package - see the <A HREF = "Section_tools.html#xmovie">xmovie</A> tool in <A HREF = "Section_tools.html">this section</A>. It creates xyz projection views of atomic coordinates and animates them. We find it very useful for debugging purposes. For high-quality visualization we recommend the following packages: </P> <UL><LI><A HREF = "http://www.ks.uiuc.edu/Research/vmd">VMD</A> <LI><A HREF = "http://mt.seas.upenn.edu/Archive/Graphics/A">AtomEye</A> <LI><A HREF = "http://pymol.sourceforge.net">PyMol</A> <LI><A HREF = "http://www.bmsc.washington.edu/raster3d/raster3d.html">Raster3d</A> <LI><A HREF = "http://www.openrasmol.org">RasMol</A> </UL> <P>Other features that LAMMPS does not yet (and may never) support are discussed in <A HREF = "Section_history.html">this section</A>. </P> <P>Finally, these are freely-available molecular dynamics codes, most of them parallel, which may be well-suited to the problems you want to model. They can also be used in conjunction with LAMMPS to perform complementary modeling tasks. </P> <UL><LI><A HREF = "http://www.scripps.edu/brooks">CHARMM</A> <LI><A HREF = "http://amber.scripps.edu">AMBER</A> <LI><A HREF = "http://www.ks.uiuc.edu/Research/namd/">NAMD</A> <LI><A HREF = "http://www.emsl.pnl.gov/docs/nwchem/nwchem.html">NWCHEM</A> <LI><A HREF = "http://www.cse.clrc.ac.uk/msi/software/DL_POLY">DL_POLY</A> <LI><A HREF = "http://dasher.wustl.edu/tinker">Tinker</A> </UL> <P>CHARMM, AMBER, NAMD, NWCHEM, and Tinker are designed primarily for modeling biological molecules. CHARMM and AMBER use atom-decomposition (replicated-data) strategies for parallelism; NAMD and NWCHEM use spatial-decomposition approaches, similar to LAMMPS. Tinker is a serial code. DL_POLY includes potentials for a variety of biological and non-biological materials; both a replicated-data and spatial-decomposition version exist. </P> <HR> <A NAME = "1_4"></A><H4>1.4 Open source distribution </H4> <P>LAMMPS comes with no warranty of any kind. As each source file states in its header, it is a copyrighted code that is distributed free-of- charge, under the terms of the <A HREF = "http://www.gnu.org/copyleft/gpl.html">GNU Public License</A> (GPL). This is often referred to as open-source distribution - see <A HREF = "http://www.gnu.org">www.gnu.org</A> or <A HREF = "http://www.opensource.org">www.opensource.org</A> for more details. The legal text of the GPL is in the LICENSE file that is included in the LAMMPS distribution. </P> <P>Here is a summary of what the GPL means for LAMMPS users: </P> <P>(1) Anyone is free to use, modify, or extend LAMMPS in any way they choose, including for commercial purposes. </P> <P>(2) If you distribute a modified version of LAMMPS, it must remain open-source, meaning you distribute it under the terms of the GPL. You should clearly annotate such a code as a derivative version of LAMMPS. </P> <P>(3) If you release any code that includes LAMMPS source code, then it must also be open-sourced, meaning you distribute it under the terms of the GPL. </P> <P>(4) If you give LAMMPS files to someone else, the GPL LICENSE file and source file headers (including the copyright and GPL notices) should remain part of the code. </P> <P>In the spirit of an open-source code, these are various ways you can contribute to making LAMMPS better. You can send email to the <A HREF = "http://lammps.sandia.gov/authors.html">developers</A> on any of these items. </P> <UL><LI>Point prospective users to the <A HREF = "http://lammps.sandia.gov">LAMMPS WWW Site</A>. Mention it in talks or link to it from your WWW site. <LI>If you find an error or omission in this manual or on the <A HREF = "http://lammps.sandia.gov">LAMMPS WWW Site</A>, or have a suggestion for something to clarify or include, send an email to the <A HREF = "http://lammps.sandia.gov/authors.html">developers</A>. <LI>If you find a bug, <A HREF = "Section_errors.html#10_2">this section</A> describes how to report it. <LI>If you publish a paper using LAMMPS results, send the citation (and any cool pictures or movies if you like) to add to the Publications, Pictures, and Movies pages of the <A HREF = "http://lammps.sandia.gov">LAMMPS WWW Site</A>, with links and attributions back to you. <LI>Create a new Makefile.machine that can be added to the src/MAKE directory. <LI>The tools sub-directory of the LAMMPS distribution has various stand-alone codes for pre- and post-processing of LAMMPS data. More details are given in <A HREF = "Section_tools.html">this section</A>. If you write a new tool that users will find useful, it can be added to the LAMMPS distribution. <LI>LAMMPS is designed to be easy to extend with new code for features like potentials, boundary conditions, diagnostic computations, etc. <A HREF = "Section_modify.html">This section</A> gives details. If you add a feature of general interest, it can be added to the LAMMPS distribution. <LI>The Benchmark page of the <A HREF = "http://lammps.sandia.gov">LAMMPS WWW Site</A> lists LAMMPS performance on various platforms. The files needed to run the benchmarks are part of the LAMMPS distribution. If your machine is sufficiently different from those listed, your timing data can be added to the page. <LI>You can send feedback for the User Comments page of the <A HREF = "http://lammps.sandia.gov">LAMMPS WWW Site</A>. It might be added to the page. No promises. <LI>Cash. Small denominations, unmarked bills preferred. Paper sack OK. Leave on desk. VISA also accepted. Chocolate chip cookies encouraged. </UL> <HR> <H4><A NAME = "1_5"></A>1.5 Acknowledgments and citations </H4> <P>LAMMPS development has been funded by the <A HREF = "http://www.doe.gov">US Department of Energy</A> (DOE), through its CRADA, LDRD, ASCI, and Genomes-to-Life programs and its <A HREF = "http://www.sc.doe.gov/ascr/home.html">OASCR</A> and <A HREF = "http://www.er.doe.gov/production/ober/ober_top.html">OBER</A> offices. </P> <P>Specifically, work on the latest version was funded in part by the US Department of Energy's Genomics:GTL program (<A HREF = "http://www.doegenomestolife.org">www.doegenomestolife.org</A>) under the <A HREF = "http://www.genomes2life.org">project</A>, "Carbon Sequestration in Synechococcus Sp.: From Molecular Machines to Hierarchical Modeling". </P> <P>The following papers describe the parallel algorithms used in LAMMPS. </P> <P>S. J. Plimpton, <B>Fast Parallel Algorithms for Short-Range Molecular Dynamics</B>, J Comp Phys, 117, 1-19 (1995). </P> <P>S. J. Plimpton, R. Pollock, M. Stevens, <B>Particle-Mesh Ewald and rRESPA for Parallel Molecular Dynamics Simulations</B>, in Proc of the Eighth SIAM Conference on Parallel Processing for Scientific Computing, Minneapolis, MN (March 1997). </P> <P>If you use LAMMPS results in your published work, please cite the J Comp Phys reference and include a pointer to the <A HREF = "http://lammps.sandia.gov">LAMMPS WWW Site</A> (http://lammps.sandia.gov). </P> <P>If you send is information about your publication, we'll be pleased to add it to the Publications page of the <A HREF = "http://lammps.sandia.gov">LAMMPS WWW Site</A>. Ditto for a picture or movie for the Pictures or Movies pages. </P> <P>The core group of LAMMPS developers is at Sandia National Labs. They include <A HREF = "http://www.sandia.gov/~sjplimp">Steve Plimpton</A>, Paul Crozier, and Aidan Thompson and can be contacted via email: sjplimp, pscrozi, athomps at sandia.gov. </P> <P>Here are various folks who have made significant contributions to features in LAMMPS. The most recent contributions are at the top of the list. </P> <DIV ALIGN=center><TABLE BORDER=1 > <TR><TD >ipp Perl script tool </TD><TD > Reese Jones (Sandia)</TD></TR> <TR><TD >eam_database and createatoms tools </TD><TD > Xiaowang Zhou (Sandia)</TD></TR> <TR><TD >electron force field (eFF) </TD><TD > Andres Jaramillo-Botero and Julius Su (Caltech)</TD></TR> <TR><TD >embedded ion method (EIM) potential </TD><TD > Xiaowang Zhou (Sandia)</TD></TR> <TR><TD >COMB potential with charge equilibration </TD><TD > Tzu-Ray Shan (U Florida)</TD></TR> <TR><TD >fix ave/correlate </TD><TD > Benoit Leblanc, Dave Rigby, Paul Saxe (Materials Design) and Reese Jones (Sandia)</TD></TR> <TR><TD >pair_style peri/lps </TD><TD > Mike Parks (Sandia)</TD></TR> <TR><TD >fix msst </TD><TD > Lawrence Fried (LLNL), Evan Reed (LLNL, Stanford)</TD></TR> <TR><TD >thermo_style custom tpcpu & spcpu keywords </TD><TD > Axel Kohlmeyer (Temple U) </TD></TR> <TR><TD >fix rigid/nve, fix rigid/nvt </TD><TD > Tony Sheh and Trung Dac Nguyen (U Michigan)</TD></TR> <TR><TD >public SVN & Git repositories for LAMMPS </TD><TD > Axel Kohlmeyer (Temple U) and Bill Goldman (Sandia)</TD></TR> <TR><TD >fix nvt, fix nph, fix npt, Parinello/Rahman dynamics, fix box/relax </TD><TD > Aidan Thompson (Sandia)</TD></TR> <TR><TD >compute heat/flux </TD><TD > German Samolyuk (ORNL) and Mario Pinto (Computational Research Lab, Pune, India)</TD></TR> <TR><TD >pair yukawa/colloid </TD><TD > Randy Schunk (Sandia)</TD></TR> <TR><TD >fix wall/colloid </TD><TD > Jeremy Lechman (Sandia)</TD></TR> <TR><TD >pair_style dsmc for Direct Simulation Monte Carlo (DSMC) modeling </TD><TD > Paul Crozier (Sandia)</TD></TR> <TR><TD >fix imd for real-time viz and interactive MD </TD><TD > Axel Kohlmeyer (Temple Univ)</TD></TR> <TR><TD >concentration-dependent EAM potential </TD><TD > Alexander Stukowski (Technical University of Darmstadt)</TD></TR> <TR><TD >parallel replica dymamics (PRD) </TD><TD > Mike Brown (Sandia)</TD></TR> <TR><TD >min_style hftn </TD><TD > Todd Plantenga (Sandia)</TD></TR> <TR><TD >fix atc </TD><TD > Reese Jones, Jon Zimmerman, Jeremy Templeton (Sandia)</TD></TR> <TR><TD >dump cfg </TD><TD > Liang Wan (Chinese Academy of Sciences)</TD></TR> <TR><TD >fix nvt with Nose/Hoover chains </TD><TD > Andy Ballard (U Maryland)</TD></TR> <TR><TD >pair_style lj/cut/gpu, pair_style gayberne/gpu </TD><TD > Mike Brown (Sandia)</TD></TR> <TR><TD >pair_style lj96/cut, bond_style table, angle_style table </TD><TD > Chuanfu Luo</TD></TR> <TR><TD >fix langevin tally </TD><TD > Carolyn Phillips (U Michigan)</TD></TR> <TR><TD >compute heat/flux for Green-Kubo </TD><TD > Reese Jones (Sandia), Philip Howell (Siemens), Vikas Varsney (AFRL)</TD></TR> <TR><TD >region cone </TD><TD > Pim Schravendijk</TD></TR> <TR><TD >fix reax/bonds </TD><TD > Aidan Thompson (Sandia)</TD></TR> <TR><TD >pair born/coul/long </TD><TD > Ahmed Ismail (Sandia)</TD></TR> <TR><TD >fix ttm </TD><TD > Paul Crozier (Sandia) and Carolyn Phillips (U Michigan)</TD></TR> <TR><TD >fix box/relax </TD><TD > Aidan Thompson and David Olmsted (Sandia)</TD></TR> <TR><TD >ReaxFF potential </TD><TD > Aidan Thompson (Sandia) and Hansohl Cho (MIT)</TD></TR> <TR><TD >compute cna/atom </TD><TD > Wan Liang (Chinese Academy of Sciences)</TD></TR> <TR><TD >Tersoff/ZBL potential </TD><TD > Dave Farrell (Northwestern U)</TD></TR> <TR><TD >peridynamics </TD><TD > Mike Parks (Sandia)</TD></TR> <TR><TD >fix smd for steered MD </TD><TD > Axel Kohlmeyer (U Penn)</TD></TR> <TR><TD >GROMACS pair potentials </TD><TD > Mark Stevens (Sandia)</TD></TR> <TR><TD >lmp2vmd tool </TD><TD > Axel Kohlmeyer (U Penn)</TD></TR> <TR><TD >compute group/group </TD><TD > Naveen Michaud-Agrawal (Johns Hopkins U)</TD></TR> <TR><TD >CG-CMM user package for coarse-graining </TD><TD > Axel Kohlmeyer (U Penn)</TD></TR> <TR><TD >cosine/delta angle potential </TD><TD > Axel Kohlmeyer (U Penn)</TD></TR> <TR><TD >VIM editor add-ons for LAMMPS input scripts </TD><TD > Gerolf Ziegenhain</TD></TR> <TR><TD >pair lubricate </TD><TD > Randy Schunk (Sandia)</TD></TR> <TR><TD >compute ackland/atom </TD><TD > Gerolf Zeigenhain</TD></TR> <TR><TD >kspace_style ewald/n, pair_style lj/coul, pair_style buck/coul </TD><TD > Pieter in 't Veld (Sandia)</TD></TR> <TR><TD >AI-REBO bond-order potential </TD><TD > Ase Henry (MIT)</TD></TR> <TR><TD >making LAMMPS a true "object" that can be instantiated multiple times, e.g. as a library </TD><TD > Ben FrantzDale (RPI)</TD></TR> <TR><TD >pymol_asphere viz tool </TD><TD > Mike Brown (Sandia)</TD></TR> <TR><TD >NEMD SLLOD integration </TD><TD > Pieter in 't Veld (Sandia)</TD></TR> <TR><TD >tensile and shear deformations </TD><TD > Pieter in 't Veld (Sandia)</TD></TR> <TR><TD >GayBerne potential </TD><TD > Mike Brown (Sandia)</TD></TR> <TR><TD >ellipsoidal particles </TD><TD > Mike Brown (Sandia)</TD></TR> <TR><TD >colloid potentials </TD><TD > Pieter in 't Veld (Sandia)</TD></TR> <TR><TD >fix heat </TD><TD > Paul Crozier and Ed Webb (Sandia)</TD></TR> <TR><TD >neighbor multi and communicate multi </TD><TD > Pieter in 't Veld (Sandia)</TD></TR> <TR><TD >MATLAB post-processing scripts </TD><TD > Arun Subramaniyan (Purdue)</TD></TR> <TR><TD >triclinic (non-orthogonal) simulation domains </TD><TD > Pieter in 't Veld (Sandia)</TD></TR> <TR><TD >thermo_extract tool</TD><TD > Vikas Varshney (Wright Patterson AFB)</TD></TR> <TR><TD >fix ave/time and fix ave/spatial </TD><TD > Pieter in 't Veld (Sandia)</TD></TR> <TR><TD >MEAM potential </TD><TD > Greg Wagner (Sandia)</TD></TR> <TR><TD >optimized pair potentials for lj/cut, charmm/long, eam, morse </TD><TD > James Fischer (High Performance Technologies), David Richie and Vincent Natoli (Stone Ridge Technologies)</TD></TR> <TR><TD >fix wall/lj126 </TD><TD > Mark Stevens (Sandia)</TD></TR> <TR><TD >Stillinger-Weber and Tersoff potentials </TD><TD > Aidan Thompson and Xiaowang Zhou (Sandia)</TD></TR> <TR><TD >region prism </TD><TD > Pieter in 't Veld (Sandia)</TD></TR> <TR><TD >LJ tail corrections for energy/pressure </TD><TD > Paul Crozier (Sandia)</TD></TR> <TR><TD >fix momentum and recenter </TD><TD > Naveen Michaud-Agrawal (Johns Hopkins U)</TD></TR> <TR><TD >multi-letter variable names </TD><TD > Naveen Michaud-Agrawal (Johns Hopkins U)</TD></TR> <TR><TD >OPLS dihedral potential</TD><TD > Mark Stevens (Sandia)</TD></TR> <TR><TD >POEMS coupled rigid body integrator</TD><TD > Rudranarayan Mukherjee (RPI)</TD></TR> <TR><TD >faster pair hybrid potential</TD><TD > James Fischer (High Performance Technologies, Inc), Vincent Natoli and David Richie (Stone Ridge Technology)</TD></TR> <TR><TD >breakable bond quartic potential</TD><TD > Chris Lorenz and Mark Stevens (Sandia)</TD></TR> <TR><TD >DCD and XTC dump styles</TD><TD > Naveen Michaud-Agrawal (Johns Hopkins U)</TD></TR> <TR><TD >grain boundary orientation fix </TD><TD > Koenraad Janssens and David Olmsted (Sandia)</TD></TR> <TR><TD >lj/smooth pair potential </TD><TD > Craig Maloney (UCSB) </TD></TR> <TR><TD >radius-of-gyration spring fix </TD><TD > Naveen Michaud-Agrawal (Johns Hopkins U) and Paul Crozier (Sandia)</TD></TR> <TR><TD >self spring fix </TD><TD > Naveen Michaud-Agrawal (Johns Hopkins U)</TD></TR> <TR><TD >EAM CoAl and AlCu potentials </TD><TD > Kwang-Reoul Lee (KIST, Korea)</TD></TR> <TR><TD >cosine/squared angle potential </TD><TD > Naveen Michaud-Agrawal (Johns Hopkins U)</TD></TR> <TR><TD >helix dihedral potential </TD><TD > Naveen Michaud-Agrawal (Johns Hopkins U) and Mark Stevens (Sandia)</TD></TR> <TR><TD >Finnis/Sinclair EAM</TD><TD > Tim Lau (MIT)</TD></TR> <TR><TD >dissipative particle dynamics (DPD) potentials</TD><TD > Kurt Smith (U Pitt) and Frank van Swol (Sandia)</TD></TR> <TR><TD >TIP4P potential (4-site water)</TD><TD > Ahmed Ismail and Amalie Frischknecht (Sandia)</TD></TR> <TR><TD >uniaxial strain fix</TD><TD > Carsten Svaneborg (Max Planck Institute)</TD></TR> <TR><TD >thermodynamics enhanced by fix quantities</TD><TD > Aidan Thompson (Sandia)</TD></TR> <TR><TD >compressed dump files</TD><TD > Erik Luijten (U Illinois)</TD></TR> <TR><TD >cylindrical indenter fix</TD><TD > Ravi Agrawal (Northwestern U)</TD></TR> <TR><TD >electric field fix</TD><TD > Christina Payne (Vanderbilt U)</TD></TR> <TR><TD >AMBER <-> LAMMPS tool</TD><TD > Keir Novik (Univ College London) and Vikas Varshney (U Akron)</TD></TR> <TR><TD >CHARMM <-> LAMMPS tool</TD><TD > Pieter in 't Veld and Paul Crozier (Sandia)</TD></TR> <TR><TD >Morse bond potential</TD><TD > Jeff Greathouse (Sandia)</TD></TR> <TR><TD >radial distribution functions</TD><TD > Paul Crozier & Jeff Greathouse (Sandia)</TD></TR> <TR><TD >force tables for long-range Coulombics</TD><TD > Paul Crozier (Sandia)</TD></TR> <TR><TD >targeted molecular dynamics (TMD)</TD><TD > Paul Crozier (Sandia) and Christian Burisch (Bochum University, Germany)</TD></TR> <TR><TD >FFT support for SGI SCSL (Altix)</TD><TD > Jim Shepherd (Ga Tech)</TD></TR> <TR><TD >lmp2cfg and lmp2traj tools</TD><TD > Ara Kooser, Jeff Greathouse, Andrey Kalinichev (Sandia)</TD></TR> <TR><TD >parallel tempering</TD><TD > Mark Sears (Sandia)</TD></TR> <TR><TD >embedded atom method (EAM) potential</TD><TD > Stephen Foiles (Sandia)</TD></TR> <TR><TD >multi-harmonic dihedral potential</TD><TD > Mathias Puetz (Sandia)</TD></TR> <TR><TD >granular force fields and BC</TD><TD > Leo Silbert & Gary Grest (Sandia)</TD></TR> <TR><TD >2d Ewald/PPPM</TD><TD > Paul Crozier (Sandia)</TD></TR> <TR><TD >CHARMM force fields</TD><TD > Paul Crozier (Sandia)</TD></TR> <TR><TD >msi2lmp tool</TD><TD > Steve Lustig (Dupont), Mike Peachey & John Carpenter (Cray)</TD></TR> <TR><TD >HTFN energy minimizer</TD><TD > Todd Plantenga (Sandia)</TD></TR> <TR><TD >class 2 force fields</TD><TD > Eric Simon (Cray)</TD></TR> <TR><TD >NVT/NPT integrators</TD><TD > Mark Stevens (Sandia)</TD></TR> <TR><TD >rRESPA</TD><TD > Mark Stevens & Paul Crozier (Sandia)</TD></TR> <TR><TD >Ewald and PPPM solvers</TD><TD > Roy Pollock (LLNL) </TD><TD > </TD></TR></TABLE></DIV> <P>Other CRADA partners involved in the design and testing of LAMMPS were </P> <UL><LI>John Carpenter (Mayo Clinic, formerly at Cray Research) <LI>Terry Stouch (Lexicon Pharmaceuticals, formerly at Bristol Myers Squibb) <LI>Steve Lustig (Dupont) <LI>Jim Belak (LLNL) </UL> </HTML> diff --git a/doc/Section_start.html b/doc/Section_start.html index 4be3c8953..419414938 100644 --- a/doc/Section_start.html +++ b/doc/Section_start.html @@ -1,1087 +1,1126 @@ <HTML> <CENTER><A HREF = "Section_intro.html">Previous Section</A> - <A HREF = "http://lammps.sandia.gov">LAMMPS WWW Site</A> - <A HREF = "Manual.html">LAMMPS Documentation</A> - <A HREF = "Section_commands.html#comm">LAMMPS Commands</A> - <A HREF = "Section_commands.html">Next Section</A> </CENTER> <HR> <H3>2. Getting Started </H3> <P>This section describes how to build and run LAMMPS, for both new and experienced users. </P> 2.1 <A HREF = "#2_1">What's in the LAMMPS distribution</A><BR> 2.2 <A HREF = "#2_2">Making LAMMPS</A><BR> 2.3 <A HREF = "#2_3">Making LAMMPS with optional packages</A><BR> 2.4 <A HREF = "#2_4">Building LAMMPS as a library</A><BR> 2.5 <A HREF = "#2_5">Running LAMMPS</A><BR> 2.6 <A HREF = "#2_6">Command-line options</A><BR> 2.7 <A HREF = "#2_7">Screen output</A><BR> 2.8 <A HREF = "#2_8">Running on GPUs</A><BR> 2.9 <A HREF = "#2_9">Tips for users of previous versions</A> <BR> <HR> <H4><A NAME = "2_1"></A>2.1 What's in the LAMMPS distribution </H4> <P>When you download LAMMPS you will need to unzip and untar the downloaded file with the following commands, after placing the file in an appropriate directory. </P> <PRE>gunzip lammps*.tar.gz tar xvf lammps*.tar </PRE> <P>This will create a LAMMPS directory containing two files and several sub-directories: </P> <DIV ALIGN=center><TABLE BORDER=1 > <TR><TD >README</TD><TD > text file</TD></TR> <TR><TD >LICENSE</TD><TD > the GNU General Public License (GPL)</TD></TR> <TR><TD >bench</TD><TD > benchmark problems</TD></TR> <TR><TD >couple</TD><TD > code coupling examples, using LAMMPS as a library</TD></TR> <TR><TD >doc</TD><TD > documentation</TD></TR> <TR><TD >examples</TD><TD > simple test problems</TD></TR> <TR><TD >potentials</TD><TD > embedded atom method (EAM) potential files</TD></TR> <TR><TD >src</TD><TD > source files</TD></TR> <TR><TD >tools</TD><TD > pre- and post-processing tools </TD></TR></TABLE></DIV> <P>If you download the Windows executable from the download page, then you just get a single file: </P> <PRE>lmp_windows.exe </PRE> <P>Skip to the <A HREF = "#2_5">Running LAMMPS</A> section, to learn how to launch this executable on a Windows box. </P> <P>The Windows executable also only includes certain packages and bug-fixes/upgrades listed on <A HREF = "http://lammps.sandia.gov/bug.html">this page</A> up to a certain date, as stated on the download page. If you want something with more packages or that is more current, you'll have to download the source tarball and build it yourself, as described in the next section. </P> <HR> <H4><A NAME = "2_2"></A>2.2 Making LAMMPS </H4> <P>This section has the following sub-sections: </P> <UL><LI><A HREF = "#2_2_1">Read this first</A> <LI><A HREF = "#2_2_2">Building a LAMMPS executable</A> <LI><A HREF = "#2_2_3">Common errors that can occur when making LAMMPS</A> <LI><A HREF = "#2_2_4">Editing a new low-level Makefile</A> <LI><A HREF = "#2_2_5">Additional build tips</A> </UL> <HR> <A NAME = "2_2_1"></A><B><I>Read this first:</I></B> <P>Building LAMMPS can be non-trivial. You will likely need to edit a makefile, there are compiler options, additional libraries can be used (MPI, FFT), etc. Please read this section carefully. If you are not comfortable with makefiles, or building codes on a Unix platform, or running an MPI job on your machine, please find a local expert to help you. Many compiling, linking, and run problems that users are not really LAMMPS issues - they are peculiar to the user's system, compilers, libraries, etc. Such questions are better answered by a local expert. </P> <P>If you have a build problem that you are convinced is a LAMMPS issue (e.g. the compiler complains about a line of LAMMPS source code), then please send an email to the <A HREF = "http://lammps.sandia.gov/authors.html">developers</A>. </P> <P>If you succeed in building LAMMPS on a new kind of machine, for which there isn't a similar Makefile for in the src/MAKE directory, send it to the developers and we'll include it in future LAMMPS releases. </P> <HR> <A NAME = "2_2_2"></A><B><I>Building a LAMMPS executable:</I></B> <P>The src directory contains the C++ source and header files for LAMMPS. It also contains a top-level Makefile and a MAKE sub-directory with low-level Makefile.* files for several machines. From within the src directory, type "make" or "gmake". You should see a list of available choices. If one of those is the machine and options you want, you can type a command like: </P> <PRE>make linux gmake mac </PRE> <P>Note that on a multi-processor or multi-core platform you can launch a parallel make, by using the "-j" switch with the make command, which will build LAMMPS more quickly. </P> <P>If you get no errors and an executable like lmp_linux or lmp_mac is produced, you're done; it's your lucky day. </P> <HR> <A NAME = "2_2_3"></A><B><I>Common errors that can occur when making LAMMPS:</I></B> <P>(1) If the make command breaks immediately with errors that indicate it can't find files with a "*" in their names, this can be because your machine's make doesn't support wildcard expansion in a makefile. Try gmake instead of make. If that doesn't work, try using a -f switch with your make command to use Makefile.list which explicitly lists all the needed files, e.g. </P> <PRE>make makelist make -f Makefile.list linux gmake -f Makefile.list mac </PRE> <P>The first "make" command will create a current Makefile.list with all the file names in your src dir. The 2nd "make" command (make or gmake) will use it to build LAMMPS. </P> <P>(2) Other errors typically occur because the low-level Makefile isn't setup correctly for your machine. If your platform is named "foo", you will need to create a Makefile.foo in the MAKE sub-directory. Use whatever existing file is closest to your platform as a starting point. See the next section for more instructions. </P> <P>(3) If you get a link-time error about missing libraries or missing dependencies, then it can be because: </P> <UL><LI>you are including a package that needs an extra library, but have not pre-built the necessary <A HREF = "#2_3_3">package library</A> <LI>you are linking to a library that doesn't exist on your system <LI>you are not linking to the necessary system library </UL> <P>The first issue is discussed below. The other two issue mean you need to edit your low-level Makefile.foo, as discussed in the next sub-section. </P> <HR> <A NAME = "2_2_4"></A><B><I>Editing a new low-level Makefile.foo:</I></B> <P>These are the issues you need to address when editing a low-level Makefile for your machine. The portions of the file you typically need to edit are the first line, the "compiler/linker settings" section, and the "system-specific settings" section. </P> <P>(1) Change the first line of Makefile.foo to list the word "foo" after the "#", and whatever other options you set. This is the line you will see if you just type "make". </P> <P>(3) The "compiler/linker settings" section lists compiler and linker settings for your C++ compiler, including optimization flags. You can use g++, the open-source GNU compiler, which is available on all Unix systems. You can also use mpicc which will typically be available if MPI is installed on your system, though you should check which actual compiler it wraps. Vendor compilers often produce faster code. On boxes with Intel CPUs, we suggest using the free Intel icc compiler, which you can download from <A HREF = "http://www.intel.com/software/products/noncom">Intel's compiler site</A>. </P> <P>If building a C++ code on your machine requires additional libraries, then you should list them as part of the LIB variable. </P> <P>The DEPFLAGS setting is what triggers the C++ compiler to create a dependency list for a source file. This speeds re-compilation when source (*.cpp) or header (*.h) files are edited. Some compilers do not support dependency file creation, or may use a different switch than -D. GNU g++ works with -D. If your compiler can't create dependency files (a long list of errors involving *.d files), then you'll need to create a Makefile.foo patterned after Makefile.storm, which uses different rules that do not involve dependency files. </P> <P>(3) The "system-specific settings" section has 4 parts. </P> <P>(3.a) The LMP_INC variable is used to include options that turn on system-dependent ifdefs within the LAMMPS code. </P> <P>The read_data and dump commands will read/write gzipped files if you compile with -DLAMMPS_GZIP. It requires that your Unix support the "popen" command. Using one of the -DPACK_ARRAY, -DPACK_POINTER, and -DPACK_MEMCPY options can make for faster parallel FFTs (in the PPPM solver) on some platforms. The -DPACK_ARRAY setting is the default. If you use -DLAMMPS_XDR, the build will include XDR compatibility files for doing particle dumps in XTC format. This is only necessary if your platform does have its own XDR files available. See the Restrictions section of the <A HREF = "dump.html">dump</A> command for details. </P> <P>(3.b) The 3 MPI variables are used to specify an MPI library to build LAMMPS with. </P> <P>If you want LAMMPS to run in parallel, you must have an MPI library installed on your platform. If you use an MPI-wrapped compiler, such as "mpicc" to build LAMMPS, you can probably leave these 3 variables blank. If you do not use "mpicc" as your compiler/linker, then you need to specify where the mpi.h file (MPI_INC) and the MPI library (MPI_PATH) is found and its name (MPI_LIB). </P> <P>If you are installing MPI yourself, we recommend Argonne's MPICH 1.2 or 2.0 which can be downloaded from the <A HREF = "http://www-unix.mcs.anl.gov/mpi">Argonne MPI site</A>. LAM MPI should also work. If you are running on a big parallel platform, your system people or the vendor should have already installed a version of MPI, which will be faster than MPICH or LAM, so find out how to build and link with it. If you use MPICH or LAM, you will have to configure and build it for your platform. The MPI configure script should have compiler options to enable you to use the same compiler you are using for the LAMMPS build, which can avoid problems that can arise when linking LAMMPS to the MPI library. </P> <P>If you just want LAMMPS to run on a single processor, you can use the STUBS library in place of MPI, since you don't need an MPI library installed on your system. See the Makefile.serial file for how to specify the 3 MPI variables. You will also need to build the STUBS library for your platform before making LAMMPS itself. From the STUBS dir, type "make" and it will hopefully create a libmpi.a suitable for linking to LAMMPS. If this build fails, you will need to edit the STUBS/Makefile for your platform. </P> <P>The file STUBS/mpi.cpp has a CPU timer function MPI_Wtime() that calls gettimeofday() . If your system doesn't support gettimeofday() , you'll need to insert code to call another timer. Note that the ANSI-standard function clock() rolls over after an hour or so, and is therefore insufficient for timing long LAMMPS simulations. </P> <P>(3.c) The 3 FFT variables are used to specify an FFT library which LAMMPS uses when using the particle-particle particle-mesh (PPPM) option in LAMMPS for long-range Coulombics via the <A HREF = "kspace_style.html">kspace_style</A> command. </P> <P>To use this option, you must have a 1d FFT library installed on your platform. This is specified by a switch of the form -DFFT_XXX where XXX = INTEL, DEC, SGI, SCSL, or FFTW. All but the last one are native vendor-provided libraries. FFTW is a fast, portable library that should work on any platform. You can download it from <A HREF = "http://www.fftw.org">www.fftw.org</A>. Use version 2.1.X, not the newer 3.0.X. Building FFTW for your box should be as simple as ./configure; make. Whichever FFT library you have on your platform, you'll need to set the appropriate FFT_INC, FFT_PATH, and FFT_LIB variables in Makefile.foo. </P> <P>If you examine src/fft3d.c and src.fft3d.h you'll see it's possible to add other vendor FFT libraries via #ifdef statements in the appropriate places. If you successfully add a new FFT option, like -DFFT_IBM, please send the LAMMPS developers an email; we'd like to add it to LAMMPS. </P> <P>If you don't plan to use PPPM, you don't need an FFT library. In this case you can set FFT_INC to -DFFT_NONE and leave the other 2 FFT variables blank. Or you can exclude the KSPACE package when you build LAMMPS (see below). </P> <P>(3.d) The several SYSLIB and SYSPATH variables can be ignored unless you are building LAMMPS with one or more of the LAMMPS packages that require these extra system libraries. The names of these packages are the prefixes on the SYSLIB and SYSPATH variables. See the <A HREF = "#2_3_4">section below</A> for more details. The SYSLIB variables list the system libraries. The SYSPATH variables are where they are located on your machine, which is typically only needed if they are in some non-standard place, that is not in your library search path. </P> <P>That's it. Once you have a correct Makefile.foo and you have pre-built any other libraries it will use (e.g. MPI, FFT, package libraries), all you need to do from the src directory is type one of these 2 commands: </P> <PRE>make foo gmake foo </PRE> <P>You should get the executable lmp_foo when the build is complete. </P> <HR> <A NAME = "2_2_5"></A><B><I>Additional build tips:</I></B> <P>(1) Building LAMMPS for multiple platforms. </P> <P>You can make LAMMPS for multiple platforms from the same src directory. Each target creates its own object sub-directory called Obj_name where it stores the system-specific *.o files. </P> <P>(2) Cleaning up. </P> <P>Typing "make clean-all" or "make clean-foo" will delete *.o object files created when LAMMPS is built, for either all builds or for a particular machine. </P> <P>(3) Building for a Mac. </P> <P>OS X is BSD Unix, so it should just work. See the Makefile.mac file. </P> <P>(4) Building for MicroSoft Windows. </P> <P>The LAMMPS download page has an option to download a pre-built Windows exeutable. See below for instructions for running this executable on a Windows box. </P> <P>If the pre-built executable doesn't have the options you want, then you should be able to build LAMMPS from source files on a Windows box. I've never done this, but LAMMPS is just standard C++ with MPI and FFT calls. You can use cygwin to build LAMMPS with a Unix make; see Makefile.cygwin. Or you should be able to pull all the source files into Visual C++ (ugh) or some similar development environment and build it. In the src/MAKE/Windows directory are some notes from users on how they built LAMMPS under Windows, so you can look at their instructions for tips. Good luck - we can't help you on this one. </P> +<P>(5) Changing the size limits in src/lmptype.h +</P> +<P>If you are running a very large problem (billions of atoms or more) +and get a run-time error about the system being too big, either on a +per-processor basis or in total size, then you may need to change one +or more settings in src/lmptype.h and re-compile LAMMPS. +</P> +<P>As the documentation in that file explains, you have basically +two choices to make: +</P> +<UL><LI>set the data type size of integer atom IDs to 4 or 8 bytes +<LI>set the data type size of integers that store the total system size to 4 or 8 bytes +</UL> +<P>The default for atom IDs is 4-byte integers since there is a memory +and communication cost for 8-byte integers. Non-molecular problems do +not need atom IDs so this does not restrict their size. Molecular +problems (which use IDs to define molecular topology), are limited to +about 2 billion atoms (2^31) with 4-byte IDs. With 8-byte IDs they +are effectively unlimited in size (2^63). +</P> +<P>The default for total system size quantities (like the number of atoms +or timesteps) is 8-byte integers by default which is effectively +unlimited in size (2^63). If your system does not support 8-byte +integers, an error will be generated, and you will need to set +"bigint" to 4-byte integers. This restricts your total system size to +about 2 billion atoms or timesteps (2^31). +</P> +<P>Note that in src/lmptype.h there are also settings for the MPI data +types associated with the integers that store atom IDs and total +system sizes, which need to be set consistent with the associated C +data types. +</P> +<P>In all cases, the size of problem that can be run on a per-processor +basis is limited by 4-byte integer storage to about 2 billion atoms +per processor (2^31), which should not normally be a restriction since +such a problem would have a huge per-processor memory footprint due to +neighbor lists and would run very slowly in terms of CPU +secs/timestep. +</P> <HR> <H4><A NAME = "2_3"></A>2.3 Making LAMMPS with optional packages </H4> <P>This section has the following sub-sections: </P> <UL><LI><A HREF = "#2_3_1">Package basics</A> <LI><A HREF = "#2_3_2">Including/excluding packages</A> <LI><A HREF = "#2_3_3">Packages that require extra LAMMPS libraries</A> <LI><A HREF = "#2_3_4">Additional Makefile settings for extra libraries</A> </UL> <HR> <A NAME = "2_3_1"></A><B><I>Package basics:</I></B> <P>The source code for LAMMPS is structured as a large set of core files which are always included, plus optional packages. Packages are groups of files that enable a specific set of features. For example, force fields for molecular systems or granular systems are in packages. You can see the list of all packages by typing "make package". </P> <P>The current list of standard packages is as follows: </P> <DIV ALIGN=center><TABLE BORDER=1 > <TR><TD >asphere </TD><TD > aspherical particles and force fields</TD></TR> <TR><TD >class2 </TD><TD > class 2 force fields</TD></TR> <TR><TD >colloid </TD><TD > colloidal particle force fields</TD></TR> <TR><TD >dipole </TD><TD > point dipole particles and force fields</TD></TR> <TR><TD >dsmc </TD><TD > Direct Simulation Monte Carlo (DMSC) pair style</TD></TR> <TR><TD >gpu </TD><TD > GPU-enabled force field styles</TD></TR> <TR><TD >granular </TD><TD > force fields and boundary conditions for granular systems</TD></TR> <TR><TD >kspace </TD><TD > long-range Ewald and particle-mesh (PPPM) solvers</TD></TR> <TR><TD >manybody </TD><TD > metal, 3-body, bond-order potentials</TD></TR> <TR><TD >meam </TD><TD > modified embedded atom method (MEAM) potential</TD></TR> <TR><TD >molecule </TD><TD > force fields for molecular systems</TD></TR> <TR><TD >opt </TD><TD > optimized versions of a few pair potentials</TD></TR> <TR><TD >peri </TD><TD > Peridynamics model and potential</TD></TR> <TR><TD >poems </TD><TD > coupled rigid body motion</TD></TR> <TR><TD >reax </TD><TD > ReaxFF potential</TD></TR> <TR><TD >replica </TD><TD > multi-replica methods</TD></TR> <TR><TD >shock </TD><TD > methods for MD simulations of shock loading</TD></TR> <TR><TD >srd </TD><TD > stochastic rotation dynamics (SRD)</TD></TR> <TR><TD >xtc </TD><TD > dump atom snapshots in XTC format </TD></TR></TABLE></DIV> <P>There are also user-contributed packages which may be as simple as a single additional file or many files grouped together which add a specific functionality to the code. </P> <P>The difference between a <I>standard</I> package versus a <I>user</I> package is as follows. </P> <P>Standard packages are supported by the LAMMPS developers and are written in a syntax and style consistent with the rest of LAMMPS. This means we will answer questions about them, debug and fix them if necessary, and keep them compatible with future changes to LAMMPS. </P> <P>User packages don't necessarily meet these requirements. If you have problems using a feature provided in a user package, you will likely need to contact the contributor directly to get help. Information on how to submit additions you make to LAMMPS as a user-contributed package is given in <A HREF = "Section_modify.html#package">this section</A> of the documentation. </P> <HR> <A NAME = "2_3_2"></A><B><I>Including/excluding packages:</I></B> <P>Any or all packages can be included or excluded independently BEFORE LAMMPS is built. </P> <P>The two exceptions to this are the "gpu" and "opt" packages. Some of the files in these packages require other packages to also be included. If this is not the case, then those subsidiary files in "gpu" and "opt" will not be installed either. To install all the files in package "gpu", the "asphere" and "kspace" packages must also be installed. To install all the files in package "opt", the "kspace" and "manybody" packages must also be installed. </P> <P>You may wish to exclude certain packages if you will never run certain kinds of simulations. This will keep you from having to build auxiliary libraries (see below) and will produce a smaller executable which may run a bit faster. </P> <P>By default, LAMMPS includes only the "kspace", "manybody", and "molecule" packages. </P> <P>Packages are included or excluded by typing "make yes-name" or "make no-name", where "name" is the name of the package. You can also type "make yes-standard", "make no-standard", "make yes-user", "make no-user", "make yes-all" or "make no-all" to include/exclude various sets of packages. Type "make package" to see the various options. </P> <P>IMPORTANT NOTE: These make commands work by simply moving files back and forth between the main src directory and sub-directories with the package name, so that the files are seen or not seen when LAMMPS is built. After you have included or excluded a package, you must re-build LAMMPS. </P> <P>Additional make options exist to help manage LAMMPS files that exist in both the src directory and in package sub-directories. You do not normally need to use these commands unless you are editing LAMMPS files or have downloaded a patch from the LAMMPS WWW site. </P> <P>Typing "make package-update" will overwrite src files with files from the package directories if the package has been included. It should be used after a patch is installed, since patches only update the master package version of a file. Typing "make package-overwrite" will overwrite files in the package directories with src files. Typing "make package-check" will list differences between src and package versions of the same files. Again, type "make package" to see the various options. </P> <HR> <A NAME = "2_3_3"></A><B><I>Packages that require extra LAMMPS libraries:</I></B> <P>A few packages (standard or user) require that additional libraries be compiled first, which LAMMPS will link to when it builds. The source code for these libraries are included in the LAMMPS distribution under the "lib" directory. Look at the README files in the lib directories (e.g. lib/reax/README) for instructions on how to build each library. </P> <P>IMPORTANT NOTE: If you are including a package in your LAMMPS build that uses one of these libraries, then you must build the library BEFORE building LAMMPS itself, since the LAMMPS build will attempt to link with the library file. </P> <P>Here is a bit of information about each library: </P> <P>The "atc" library in lib/atc is used by the user-atc package. It provides continuum field estimation and molecular dynamics-finite element coupling methods. It was written primarily by Reese Jones, Jeremy Templeton and Jonathan Zimmerman at Sandia. </P> <P>The "gpu" library in lib/gpu is used by the gpu package. It contains code to enable portions of LAMMPS to run on a GPU chip associated with your CPU. Currently, only NVIDIA GPUs are supported. Building this library requires NVIDIA Cuda tools to be installed on your system. See the <A HREF = "#2_8">Running on GPUs</A> section below for more info about installing and using Cuda. </P> <P>The "meam" library in lib/meam is used by the meam package. computes the modified embedded atom method potential, which is a generalization of EAM potentials that can be used to model a wider variety of materials. This MEAM implementation was written by Greg Wagner at Sandia. It requires a F90 compiler to build. The C++ to FORTRAN function calls in pair_meam.cpp assumes that FORTRAN object names are converted to C object names by appending an underscore character. This is generally the case, but on machines that do not conform to this convention, you will need to modify either the C++ code or your compiler settings. </P> <P>The "poems" library in lib/poems is used by the poems package. computes the constrained rigid-body motion of articulated (jointed) multibody systems. POEMS was written and is distributed by Prof Kurt Anderson's group at Rensselaer Polytechnic Institute (RPI). </P> <P>The "reax" library in lib/reax is used by the reax package. It computes the Reactive Force Field (ReaxFF) potential, developed by Adri van Duin in Bill Goddard's group at CalTech. This implementation in LAMMPS uses many of Adri's files and was developed by Aidan Thompson at Sandia and Hansohl Cho at MIT. It requires a F77 or F90 compiler to build. The C++ to FORTRAN function calls in pair_reax.cpp assume that FORTRAN object names are converted to C object names by appending an underscore character. This is generally the case, but on machines that do not conform to this convention, you will need to modify either the C++ code or your compiler settings. The name conversion is handled by the preprocessor macro called FORTRAN in pair_reax_fortran.h. Different definitions of this macro can be obtained by adding a machine-specific macro definition to the CCFLAGS variable in your Makefile e.g. -D_IBM. See pair_reax_fortran.h for more info. </P> <P>As described in its README file, each library is built by typing something like </P> <PRE>make -f Makefile.g++ </PRE> <P>in the appropriate directory, e.g. in lib/reax. </P> <P>You must use a Makefile that is a match for your system. If one of the provided Makefiles is not appropriate for your system you will need to edit or add one. For example, in the case of Fotran-based libraries, your system must have a Fortran compiler, the settings for which will be in the Makefile. </P> <HR> <A NAME = "2_3_4"></A><B><I>Additional Makefile settings for extra libraries:</I></B> <P>After the desired library or libraries are built, and the package has been included, you can build LAMMPS itself. For example, from the lammps/src directory you would type this, to build LAMMPS with ReaxFF. Note that as discussed in the preceding section, the package library itself, namely lib/reax/libreax.a, must already have been built, for the LAMMPS build to be successful. </P> <PRE>make yes-reax make g++ </PRE> <P>Also note that simply building the library is not sufficient to use it from LAMMPS. As in this example, you must also include the package that uses and wraps the library before you build LAMMPS itself. </P> <P>As discussed in point (2.4) of <A HREF = "#2_2_4">this section</A> above, there are settings in the low-level Makefile that specify additional system libraries needed by individual LAMMPS add-on libraries. These are the settings you must specify correctly in your low-level Makefile in lammps/src/MAKE, such as Makefile.foo: </P> <P>To use the gpu package and library, the settings for gpu_SYSLIB and gpu_SYSPATH must be correct. These are specific to the NVIDIA CUDA software which must be installed on your system. </P> <P>To use the meam or reax packages and their libraries which are Fortran based, the settings for meam_SYSLIB, reax_SYSLIB, meam_SYSPATH, and reax_SYSPATH must be correct. This is so that the C++ compiler can perform a cross-language link using the appropriate system Fortran libraries. </P> <P>To use the user-atc package and library, the settings for user-atc_SYSLIB and user-atc_SYSPATH must be correct. This is so that the appropriate BLAS and LAPACK libs, used by the user-atc library, can be found. </P> <HR> <H4><A NAME = "2_4"></A>2.4 Building LAMMPS as a library </H4> <P>LAMMPS can be built as a library, which can then be called from another application or a scripting language. See <A HREF = "Section_howto.html#4_10">this section</A> for more info on coupling LAMMPS to other codes. Building LAMMPS as a library is done by typing </P> <PRE>make makelib make -f Makefile.lib foo </PRE> <P>where foo is the machine name. The first "make" command will create a current Makefile.lib with all the file names in your src dir. The 2nd "make" command will use it to build LAMMPS as a library. This requires that Makefile.foo have a library target (lib) and system-specific settings for ARCHIVE and ARFLAGS. See Makefile.linux for an example. The build will create the file liblmp_foo.a which another application can link to. </P> <P>When used from a C++ program, the library allows one or more LAMMPS objects to be instantiated. All of LAMMPS is wrapped in a LAMMPS_NS namespace; you can safely use any of its classes and methods from within your application code, as needed. </P> <P>When used from a C or Fortran program or a scripting language, the library has a simple function-style interface, provided in src/library.cpp and src/library.h. </P> <P>See the sample codes couple/simple/simple.cpp and simple.c as examples of C++ and C codes that invoke LAMMPS thru its library interface. There are other examples as well in the couple directory which are discussed in <A HREF = "Section_howto.html#4_10">this section</A> of the manual. See <A HREF = "Section_python.html">this section</A> of the manual for a description of the Python wrapper provided with LAMMPS that operates through the LAMMPS library interface. </P> <P>The files src/library.cpp and library.h contain the C-style interface to LAMMPS. See <A HREF = "Section_howto.html#4_19">this section</A> of the manual for a description of the interface and how to extend it for your needs. </P> <HR> <H4><A NAME = "2_5"></A>2.5 Running LAMMPS </H4> <P>By default, LAMMPS runs by reading commands from stdin; e.g. lmp_linux < in.file. This means you first create an input script (e.g. in.file) containing the desired commands. <A HREF = "Section_commands.html">This section</A> describes how input scripts are structured and what commands they contain. </P> <P>You can test LAMMPS on any of the sample inputs provided in the examples directory. Input scripts are named in.* and sample outputs are named log.*.name.P where name is a machine and P is the number of processors it was run on. </P> <P>Here is how you might run one of the Lennard-Jones tests on a Linux box, using mpirun to launch a parallel job: </P> <PRE>cd src make linux cp lmp_linux ../examples/lj cd ../examples/lj mpirun -np 4 lmp_linux < in.lj.nve </PRE> <HR> <P>On a Windows machine, you can skip making LAMMPS and simply download an executable. But note that not all packages are available. The following packages are available: asphere, class2, colloid, dipole, dsmc, granular, kspace, manybody, molecule, peri, poems, replica, shock, user-ackland, user-cd-eam, user-cg-cmm, user-ewaldn, user-smd. But these packages are not available: gpu, meam, opt, reax, xtc, user-atc, user-imd. </P> <P>To run the LAMMPS executable on a Windows machine, first decide whether you want to download the non-MPI (serial) or the MPI (parallel) version of the executable. Download and save the version you have chosen. </P> <P>For the non-MPI version, follow these steps: </P> <UL><LI>Get a command prompt by going to Start->Run... , then typing "cmd". <LI>Move to the directory where you have saved lmp_win_no-mpi.exe (e.g. by typing: cd "Documents"). <LI>At the command prompt, type "lmp_win_no-mpi -in in.lj", replacing in.lj with the name of your LAMMPS input script. </UL> <P>For the MPI version, which allows you to run LAMMPS under Windows on multiple processors, follow these steps: </P> <UL><LI>Download and install <A HREF = "http://www.mcs.anl.gov/research/projects/mpich2/downloads/index.php?s=downloads">MPICH2</A> for Windows. <LI>You'll need to use the mpiexec.exe and smpd.exe files from the MPICH2 package. Put them in same directory (or path) as the LAMMPS Windows executable. <LI>Get a command prompt by going to Start->Run... , then typing "cmd". <LI>Move to the directory where you have saved lmp_win_mpi.exe (e.g. by typing: cd "Documents"). <LI>Then type something like this: "mpiexec -np 4 -localonly lmp_win_mpi -in in.lj", replacing in.lj with the name of your LAMMPS input script. <LI>Note that you may need to provide smpd with a passphrase --- it doesn't matter what you type. <LI>In this mode, output may not immediately show up on the screen, so if your input script takes a long time to execute, you may need to be patient before the output shows up. <LI>Alternatively, you can still use this executable to run on a single processor by typing something like: "lmp_win_mpi -in in.lj". </UL> <HR> <P>The screen output from LAMMPS is described in the next section. As it runs, LAMMPS also writes a log.lammps file with the same information. </P> <P>Note that this sequence of commands copies the LAMMPS executable (lmp_linux) to the directory with the input files. This may not be necessary, but some versions of MPI reset the working directory to where the executable is, rather than leave it as the directory where you launch mpirun from (if you launch lmp_linux on its own and not under mpirun). If that happens, LAMMPS will look for additional input files and write its output files to the executable directory, rather than your working directory, which is probably not what you want. </P> <P>If LAMMPS encounters errors in the input script or while running a simulation it will print an ERROR message and stop or a WARNING message and continue. See <A HREF = "Section_errors.html">this section</A> for a discussion of the various kinds of errors LAMMPS can or can't detect, a list of all ERROR and WARNING messages, and what to do about them. </P> <P>LAMMPS can run a problem on any number of processors, including a single processor. In theory you should get identical answers on any number of processors and on any machine. In practice, numerical round-off can cause slight differences and eventual divergence of molecular dynamics phase space trajectories. </P> <P>LAMMPS can run as large a problem as will fit in the physical memory of one or more processors. If you run out of memory, you must run on more processors or setup a smaller problem. </P> <HR> <H4><A NAME = "2_6"></A>2.6 Command-line options </H4> <P>At run time, LAMMPS recognizes several optional command-line switches which may be used in any order. For example, lmp_ibm might be launched as follows: </P> <PRE>mpirun -np 16 lmp_ibm -var f tmp.out -log my.log -screen none < in.alloy </PRE> <P>These are the command-line options: </P> <PRE>-echo style </PRE> <P>Set the style of command echoing. The style can be <I>none</I> or <I>screen</I> or <I>log</I> or <I>both</I>. Depending on the style, each command read from the input script will be echoed to the screen and/or logfile. This can be useful to figure out which line of your script is causing an input error. The default value is <I>log</I>. The echo style can also be set by using the <A HREF = "echo.html">echo</A> command in the input script itself. </P> <PRE>-partition 8x2 4 5 ... </PRE> <P>Invoke LAMMPS in multi-partition mode. When LAMMPS is run on P processors and this switch is not used, LAMMPS runs in one partition, i.e. all P processors run a single simulation. If this switch is used, the P processors are split into separate partitions and each partition runs its own simulation. The arguments to the switch specify the number of processors in each partition. Arguments of the form MxN mean M partitions, each with N processors. Arguments of the form N mean a single partition with N processors. The sum of processors in all partitions must equal P. Thus the command "-partition 8x2 4 5" has 10 partitions and runs on a total of 25 processors. </P> <P>Note that with MPI installed on a machine (e.g. your desktop), you can run on more (virtual) processors than you have physical processors. This can be useful for running <A HREF = "Section_howto.html#4_5">multi-replica simulations</A>, on one or a few processors. </P> <P>The input script specifies what simulation is run on which partition; see the <A HREF = "variable.html">variable</A> and <A HREF = "next.html">next</A> commands. This <A HREF = "Section_howto.html#4_4">howto section</A> gives examples of how to use these commands in this way. Simulations running on different partitions can also communicate with each other; see the <A HREF = "temper.html">temper</A> command. </P> <PRE>-in file </PRE> <P>Specify a file to use as an input script. This is an optional switch when running LAMMPS in one-partition mode. If it is not specified, LAMMPS reads its input script from stdin - e.g. lmp_linux < in.run. This is a required switch when running LAMMPS in multi-partition mode, since multiple processors cannot all read from stdin. </P> <PRE>-log file </PRE> <P>Specify a log file for LAMMPS to write status information to. In one-partition mode, if the switch is not used, LAMMPS writes to the file log.lammps. If this switch is used, LAMMPS writes to the specified file. In multi-partition mode, if the switch is not used, a log.lammps file is created with hi-level status information. Each partition also writes to a log.lammps.N file where N is the partition ID. If the switch is specified in multi-partition mode, the hi-level logfile is named "file" and each partition also logs information to a file.N. For both one-partition and multi-partition mode, if the specified file is "none", then no log files are created. Using a <A HREF = "log.html">log</A> command in the input script will override this setting. </P> <PRE>-screen file </PRE> <P>Specify a file for LAMMPS to write its screen information to. In one-partition mode, if the switch is not used, LAMMPS writes to the screen. If this switch is used, LAMMPS writes to the specified file instead and you will see no screen output. In multi-partition mode, if the switch is not used, hi-level status information is written to the screen. Each partition also writes to a screen.N file where N is the partition ID. If the switch is specified in multi-partition mode, the hi-level screen dump is named "file" and each partition also writes screen information to a file.N. For both one-partition and multi-partition mode, if the specified file is "none", then no screen output is performed. </P> <PRE>-var name value </PRE> <P>Specify a variable that will be defined for substitution purposes when the input script is read. "Name" is the variable name which can be a single character (referenced as $x in the input script) or a full string (referenced as ${abc}). The value can be any string. Using this command-line option is equivalent to putting the line "variable name index value" at the beginning of the input script. Defining an index variable as a command-line argument overrides any setting for the same index variable in the input script, since index variables cannot be re-defined. See the <A HREF = "variable.html">variable</A> command for more info on defining index and other kinds of variables and <A HREF = "Section_commands.html#3_2">this section</A> for more info on using variables in input scripts. </P> <HR> <H4><A NAME = "2_7"></A>2.7 LAMMPS screen output </H4> <P>As LAMMPS reads an input script, it prints information to both the screen and a log file about significant actions it takes to setup a simulation. When the simulation is ready to begin, LAMMPS performs various initializations and prints the amount of memory (in MBytes per processor) that the simulation requires. It also prints details of the initial thermodynamic state of the system. During the run itself, thermodynamic information is printed periodically, every few timesteps. When the run concludes, LAMMPS prints the final thermodynamic state and a total run time for the simulation. It then appends statistics about the CPU time and storage requirements for the simulation. An example set of statistics is shown here: </P> <PRE>Loop time of 49.002 on 2 procs for 2004 atoms </PRE> <PRE>Pair time (%) = 35.0495 (71.5267) Bond time (%) = 0.092046 (0.187841) Kspce time (%) = 6.42073 (13.103) Neigh time (%) = 2.73485 (5.5811) Comm time (%) = 1.50291 (3.06703) Outpt time (%) = 0.013799 (0.0281601) Other time (%) = 2.13669 (4.36041) </PRE> <PRE>Nlocal: 1002 ave, 1015 max, 989 min Histogram: 1 0 0 0 0 0 0 0 0 1 Nghost: 8720 ave, 8724 max, 8716 min Histogram: 1 0 0 0 0 0 0 0 0 1 Neighs: 354141 ave, 361422 max, 346860 min Histogram: 1 0 0 0 0 0 0 0 0 1 </PRE> <PRE>Total # of neighbors = 708282 Ave neighs/atom = 353.434 Ave special neighs/atom = 2.34032 Number of reneighborings = 42 Dangerous reneighborings = 2 </PRE> <P>The first section gives the breakdown of the CPU run time (in seconds) into major categories. The second section lists the number of owned atoms (Nlocal), ghost atoms (Nghost), and pair-wise neighbors stored per processor. The max and min values give the spread of these values across processors with a 10-bin histogram showing the distribution. The total number of histogram counts is equal to the number of processors. </P> <P>The last section gives aggregate statistics for pair-wise neighbors and special neighbors that LAMMPS keeps track of (see the <A HREF = "special_bonds.html">special_bonds</A> command). The number of times neighbor lists were rebuilt during the run is given as well as the number of potentially "dangerous" rebuilds. If atom movement triggered neighbor list rebuilding (see the <A HREF = "neigh_modify.html">neigh_modify</A> command), then dangerous reneighborings are those that were triggered on the first timestep atom movement was checked for. If this count is non-zero you may wish to reduce the delay factor to insure no force interactions are missed by atoms moving beyond the neighbor skin distance before a rebuild takes place. </P> <P>If an energy minimization was performed via the <A HREF = "minimize.html">minimize</A> command, additional information is printed, e.g. </P> <PRE>Minimization stats: E initial, next-to-last, final = -0.895962 -2.94193 -2.94342 Gradient 2-norm init/final= 1920.78 20.9992 Gradient inf-norm init/final= 304.283 9.61216 Iterations = 36 Force evaluations = 177 </PRE> <P>The first line lists the initial and final energy, as well as the energy on the next-to-last iteration. The next 2 lines give a measure of the gradient of the energy (force on all atoms). The 2-norm is the "length" of this force vector; the inf-norm is the largest component. The last 2 lines are statistics on how many iterations and force-evaluations the minimizer required. Multiple force evaluations are typically done at each iteration to perform a 1d line minimization in the search direction. </P> <P>If a <A HREF = "kspace_style.html">kspace_style</A> long-range Coulombics solve was performed during the run (PPPM, Ewald), then additional information is printed, e.g. </P> <PRE>FFT time (% of Kspce) = 0.200313 (8.34477) FFT Gflps 3d 1d-only = 2.31074 9.19989 </PRE> <P>The first line gives the time spent doing 3d FFTs (4 per timestep) and the fraction it represents of the total KSpace time (listed above). Each 3d FFT requires computation (3 sets of 1d FFTs) and communication (transposes). The total flops performed is 5Nlog_2(N), where N is the number of points in the 3d grid. The FFTs are timed with and without the communication and a Gflop rate is computed. The 3d rate is with communication; the 1d rate is without (just the 1d FFTs). Thus you can estimate what fraction of your FFT time was spent in communication, roughly 75% in the example above. </P> <HR> <H4><A NAME = "2_8"></A>2.8 Running on GPUs </H4> <P>A few LAMMPS <A HREF = "pair_style.html">pair styles</A> can be run on graphical processing units (GPUs). We plan to add more over time. Currently, they only support NVIDIA GPU cards. To use them you need to install certain NVIDIA CUDA software on your system: </P> <UL><LI>Check if you have an NVIDIA card: cat /proc/driver/nvidia/cards/0 <LI>Go to http://www.nvidia.com/object/cuda_get.html <LI>Install a driver and toolkit appropriate for your system (SDK is not necessary) <LI>Follow the instructions in README in lammps/lib/gpu to build the library. <LI>Run lammps/lib/gpu/nvc_get_devices to list supported devices and properties </UL> <H4>GPU configuration </H4> <P>When using GPUs, you are restricted to one physical GPU per LAMMPS process. Multiple processes can share a single GPU and in many cases it will be more efficient to run with multiple processes per GPU. Any GPU accelerated style requires that <A HREF = "fix_gpu.html">fix gpu</A> be used in the input script to select and initialize the GPUs. The format for the fix is: </P> <PRE>fix <I>name</I> all gpu <I>mode</I> <I>first</I> <I>last</I> <I>split</I> </PRE> <P>where <I>name</I> is the name for the fix. The gpu fix must be the first fix specified for a given run, otherwise the program will exit with an error. The gpu fix will not have any effect on runs that do not use GPU acceleration; there should be no problem with specifying the fix first in any input script. </P> <P><I>mode</I> can be either "force" or "force/neigh". In the former, neighbor list calculation is performed on the CPU using the standard LAMMPS routines. In the latter, the neighbor list calculation is performed on the GPU. The GPU neighbor list can be used for better performance, however, it should not be used with a triclinic box. </P> <P>There are cases when it might be more efficient to select the CPU for neighbor list builds. If a non-GPU enabled style requires a neighbor list, it will also be built using CPU routines. Redundant CPU and GPU neighbor list calculations will typically be less efficient. For <A HREF = "pair_hybrid.html">hybrid</A> pair styles, GPU calculated neighbor lists might be less efficient because no particles will be skipped in a given neighbor list. </P> <P><I>first</I> is the ID (as reported by lammps/lib/gpu/nvc_get_devices) of the first GPU that will be used on each node. <I>last</I> is the ID of the last GPU that will be used on each node. If you have only one GPU per node, <I>first</I> and <I>last</I> will typically both be 0. Selecting a non-sequential set of GPU IDs (e.g. 0,1,3) is not currently supported. </P> <P><I>split</I> is the fraction of particles whose forces, torques, energies, and/or virials will be calculated on the GPU. This can be used to perform CPU and GPU force calculations simultaneously. If <I>split</I> is negative, the software will attempt to calculate the optimal fraction automatically every 25 timesteps based on CPU and GPU timings. Because the GPU speedups are dependent on the number of particles, automatic calculation of the split can be less efficient, but typically results in loop times within 20% of an optimal fixed split. </P> <P>If you have two GPUs per node, 8 CPU cores per node, and would like to run on 4 nodes with dynamic balancing of force calculation across CPU and GPU cores, the fix might be </P> <PRE>fix 0 all gpu force/neigh 0 1 -1 </PRE> <P>with LAMMPS run on 32 processes. In this case, all CPU cores and GPU devices on the nodes would be utilized. Each GPU device would be shared by 4 CPU cores. The CPU cores would perform force calculations for some fraction of the particles at the same time the GPUs performed force calculation for the other particles. </P> <P>Because of the large number of cores on each GPU device, it might be more efficient to run on fewer processes per GPU when the number of particles per process is small (100's of particles); this can be necessary to keep the GPU cores busy. </P> <H4>GPU input script </H4> <P>In order to use GPU acceleration in LAMMPS, <A HREF = "fix_gpu.html">fix_gpu</A> should be used in order to initialize and configure the GPUs for use. Additionally, GPU enabled styles must be selected in the input script. Currently, this is limited to a few <A HREF = "pair_style.html">pair styles</A>. Some GPU-enabled styles have additional restrictions listed in their documentation. </P> <H4>GPU asynchronous pair computation </H4> <P>The GPU accelerated pair styles can be used to perform pair style force calculation on the GPU while other calculations are performed on the CPU. One method to do this is to specify a <I>split</I> in the gpu fix as described above. In this case, force calculation for the pair style will also be performed on the CPU. </P> <P>When the CPU work in a GPU pair style has finished, the next force computation will begin, possibly before the GPU has finished. If <I>split</I> is 1.0 in the gpu fix, the next force computation will begin almost immediately. This can be used to run a <A HREF = "pair_hybrid.html">hybrid</A> GPU pair style at the same time as a hybrid CPU pair style. In this case, the GPU pair style should be first in the hybrid command in order to perform simultaneous calculations. This also allows <A HREF = "bond_style.html">bond</A>, <A HREF = "angle_style.html">angle</A>, <A HREF = "dihedral_style.html">dihedral</A>, <A HREF = "improper_style.html">improper</A>, and <A HREF = "kspace_style.html">long-range</A> force computations to be run simultaneously with the GPU pair style. Once all CPU force computations have completed, the gpu fix will block until the GPU has finished all work before continuing the run. </P> <H4>GPU timing </H4> <P>GPU accelerated pair styles can perform computations asynchronously with CPU computations. The "Pair" time reported by LAMMPS will be the maximum of the time required to complete the CPU pair style computations and the time required to complete the GPU pair style computations. Any time spent for GPU-enabled pair styles for computations that run simultaneously with <A HREF = "bond_style.html">bond</A>, <A HREF = "angle_style.html">angle</A>, <A HREF = "dihedral_style.html">dihedral</A>, <A HREF = "improper_style.html">improper</A>, and <A HREF = "kspace_style.html">long-range</A> calculations will not be included in the "Pair" time. </P> <P>When <I>mode</I> for the gpu fix is force/neigh, the time for neighbor list calculations on the GPU will be added into the "Pair" time, not the "Neigh" time. A breakdown of the times required for various tasks on the GPU (data copy, neighbor calculations, force computations, etc.) are output only with the LAMMPS screen output at the end of each run. These timings represent total time spent on the GPU for each routine, regardless of asynchronous CPU calculations. </P> <H4>GPU single vs double precision </H4> <P>See the lammps/lib/gpu/README file for instructions on how to build the LAMMPS gpu library for single, mixed, and double precision. The latter requires that your GPU card supports double precision. </P> <HR> <H4><A NAME = "2_9"></A>2.9 Tips for users of previous LAMMPS versions </H4> <P>The current C++ began with a complete rewrite of LAMMPS 2001, which was written in F90. Features of earlier versions of LAMMPS are listed in <A HREF = "Section_history.html">this section</A>. The F90 and F77 versions (2001 and 99) are also freely distributed as open-source codes; check the <A HREF = "http://lammps.sandia.gov">LAMMPS WWW Site</A> for distribution information if you prefer those versions. The 99 and 2001 versions are no longer under active development; they do not have all the features of C++ LAMMPS. </P> <P>If you are a previous user of LAMMPS 2001, these are the most significant changes you will notice in C++ LAMMPS: </P> <P>(1) The names and arguments of many input script commands have changed. All commands are now a single word (e.g. read_data instead of read data). </P> <P>(2) All the functionality of LAMMPS 2001 is included in C++ LAMMPS, but you may need to specify the relevant commands in different ways. </P> <P>(3) The format of the data file can be streamlined for some problems. See the <A HREF = "read_data.html">read_data</A> command for details. The data file section "Nonbond Coeff" has been renamed to "Pair Coeff" in C++ LAMMPS. </P> <P>(4) Binary restart files written by LAMMPS 2001 cannot be read by C++ LAMMPS with a <A HREF = "read_restart.html">read_restart</A> command. This is because they were output by F90 which writes in a different binary format than C or C++ writes or reads. Use the <I>restart2data</I> tool provided with LAMMPS 2001 to convert the 2001 restart file to a text data file. Then edit the data file as necessary before using the C++ LAMMPS <A HREF = "read_data.html">read_data</A> command to read it in. </P> <P>(5) There are numerous small numerical changes in C++ LAMMPS that mean you will not get identical answers when comparing to a 2001 run. However, your initial thermodynamic energy and MD trajectory should be close if you have setup the problem for both codes the same. </P> </HTML> diff --git a/doc/Section_start.txt b/doc/Section_start.txt index ae747ded6..4faa06931 100644 --- a/doc/Section_start.txt +++ b/doc/Section_start.txt @@ -1,1075 +1,1114 @@ "Previous Section"_Section_intro.html - "LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc - "Next Section"_Section_commands.html :c :link(lws,http://lammps.sandia.gov) :link(ld,Manual.html) :link(lc,Section_commands.html#comm) :line 2. Getting Started :h3 This section describes how to build and run LAMMPS, for both new and experienced users. 2.1 "What's in the LAMMPS distribution"_#2_1 2.2 "Making LAMMPS"_#2_2 2.3 "Making LAMMPS with optional packages"_#2_3 2.4 "Building LAMMPS as a library"_#2_4 2.5 "Running LAMMPS"_#2_5 2.6 "Command-line options"_#2_6 2.7 "Screen output"_#2_7 2.8 "Running on GPUs"_#2_8 2.9 "Tips for users of previous versions"_#2_9 :all(b) :line 2.1 What's in the LAMMPS distribution :h4,link(2_1) When you download LAMMPS you will need to unzip and untar the downloaded file with the following commands, after placing the file in an appropriate directory. gunzip lammps*.tar.gz tar xvf lammps*.tar :pre This will create a LAMMPS directory containing two files and several sub-directories: README: text file LICENSE: the GNU General Public License (GPL) bench: benchmark problems couple: code coupling examples, using LAMMPS as a library doc: documentation examples: simple test problems potentials: embedded atom method (EAM) potential files src: source files tools: pre- and post-processing tools :tb(s=:) If you download the Windows executable from the download page, then you just get a single file: lmp_windows.exe :pre Skip to the "Running LAMMPS"_#2_5 section, to learn how to launch this executable on a Windows box. The Windows executable also only includes certain packages and bug-fixes/upgrades listed on "this page"_http://lammps.sandia.gov/bug.html up to a certain date, as stated on the download page. If you want something with more packages or that is more current, you'll have to download the source tarball and build it yourself, as described in the next section. :line 2.2 Making LAMMPS :h4,link(2_2) This section has the following sub-sections: "Read this first"_#2_2_1 "Building a LAMMPS executable"_#2_2_2 "Common errors that can occur when making LAMMPS"_#2_2_3 "Editing a new low-level Makefile"_#2_2_4 "Additional build tips"_#2_2_5 :ul :line [{Read this first:}] :link(2_2_1) Building LAMMPS can be non-trivial. You will likely need to edit a makefile, there are compiler options, additional libraries can be used (MPI, FFT), etc. Please read this section carefully. If you are not comfortable with makefiles, or building codes on a Unix platform, or running an MPI job on your machine, please find a local expert to help you. Many compiling, linking, and run problems that users are not really LAMMPS issues - they are peculiar to the user's system, compilers, libraries, etc. Such questions are better answered by a local expert. If you have a build problem that you are convinced is a LAMMPS issue (e.g. the compiler complains about a line of LAMMPS source code), then please send an email to the "developers"_http://lammps.sandia.gov/authors.html. If you succeed in building LAMMPS on a new kind of machine, for which there isn't a similar Makefile for in the src/MAKE directory, send it to the developers and we'll include it in future LAMMPS releases. :line [{Building a LAMMPS executable:}] :link(2_2_2) The src directory contains the C++ source and header files for LAMMPS. It also contains a top-level Makefile and a MAKE sub-directory with low-level Makefile.* files for several machines. From within the src directory, type "make" or "gmake". You should see a list of available choices. If one of those is the machine and options you want, you can type a command like: make linux gmake mac :pre Note that on a multi-processor or multi-core platform you can launch a parallel make, by using the "-j" switch with the make command, which will build LAMMPS more quickly. If you get no errors and an executable like lmp_linux or lmp_mac is produced, you're done; it's your lucky day. :line [{Common errors that can occur when making LAMMPS:}] :link(2_2_3) (1) If the make command breaks immediately with errors that indicate it can't find files with a "*" in their names, this can be because your machine's make doesn't support wildcard expansion in a makefile. Try gmake instead of make. If that doesn't work, try using a -f switch with your make command to use Makefile.list which explicitly lists all the needed files, e.g. make makelist make -f Makefile.list linux gmake -f Makefile.list mac :pre The first "make" command will create a current Makefile.list with all the file names in your src dir. The 2nd "make" command (make or gmake) will use it to build LAMMPS. (2) Other errors typically occur because the low-level Makefile isn't setup correctly for your machine. If your platform is named "foo", you will need to create a Makefile.foo in the MAKE sub-directory. Use whatever existing file is closest to your platform as a starting point. See the next section for more instructions. (3) If you get a link-time error about missing libraries or missing dependencies, then it can be because: you are including a package that needs an extra library, but have not pre-built the necessary "package library"_#2_3_3 you are linking to a library that doesn't exist on your system you are not linking to the necessary system library :ul The first issue is discussed below. The other two issue mean you need to edit your low-level Makefile.foo, as discussed in the next sub-section. :line [{Editing a new low-level Makefile.foo:}] :link(2_2_4) These are the issues you need to address when editing a low-level Makefile for your machine. The portions of the file you typically need to edit are the first line, the "compiler/linker settings" section, and the "system-specific settings" section. (1) Change the first line of Makefile.foo to list the word "foo" after the "#", and whatever other options you set. This is the line you will see if you just type "make". (3) The "compiler/linker settings" section lists compiler and linker settings for your C++ compiler, including optimization flags. You can use g++, the open-source GNU compiler, which is available on all Unix systems. You can also use mpicc which will typically be available if MPI is installed on your system, though you should check which actual compiler it wraps. Vendor compilers often produce faster code. On boxes with Intel CPUs, we suggest using the free Intel icc compiler, which you can download from "Intel's compiler site"_intel. :link(intel,http://www.intel.com/software/products/noncom) If building a C++ code on your machine requires additional libraries, then you should list them as part of the LIB variable. The DEPFLAGS setting is what triggers the C++ compiler to create a dependency list for a source file. This speeds re-compilation when source (*.cpp) or header (*.h) files are edited. Some compilers do not support dependency file creation, or may use a different switch than -D. GNU g++ works with -D. If your compiler can't create dependency files (a long list of errors involving *.d files), then you'll need to create a Makefile.foo patterned after Makefile.storm, which uses different rules that do not involve dependency files. (3) The "system-specific settings" section has 4 parts. (3.a) The LMP_INC variable is used to include options that turn on system-dependent ifdefs within the LAMMPS code. The read_data and dump commands will read/write gzipped files if you compile with -DLAMMPS_GZIP. It requires that your Unix support the "popen" command. Using one of the -DPACK_ARRAY, -DPACK_POINTER, and -DPACK_MEMCPY options can make for faster parallel FFTs (in the PPPM solver) on some platforms. The -DPACK_ARRAY setting is the default. If you use -DLAMMPS_XDR, the build will include XDR compatibility files for doing particle dumps in XTC format. This is only necessary if your platform does have its own XDR files available. See the Restrictions section of the "dump"_dump.html command for details. (3.b) The 3 MPI variables are used to specify an MPI library to build LAMMPS with. If you want LAMMPS to run in parallel, you must have an MPI library installed on your platform. If you use an MPI-wrapped compiler, such as "mpicc" to build LAMMPS, you can probably leave these 3 variables blank. If you do not use "mpicc" as your compiler/linker, then you need to specify where the mpi.h file (MPI_INC) and the MPI library (MPI_PATH) is found and its name (MPI_LIB). If you are installing MPI yourself, we recommend Argonne's MPICH 1.2 or 2.0 which can be downloaded from the "Argonne MPI site"_http://www-unix.mcs.anl.gov/mpi. LAM MPI should also work. If you are running on a big parallel platform, your system people or the vendor should have already installed a version of MPI, which will be faster than MPICH or LAM, so find out how to build and link with it. If you use MPICH or LAM, you will have to configure and build it for your platform. The MPI configure script should have compiler options to enable you to use the same compiler you are using for the LAMMPS build, which can avoid problems that can arise when linking LAMMPS to the MPI library. If you just want LAMMPS to run on a single processor, you can use the STUBS library in place of MPI, since you don't need an MPI library installed on your system. See the Makefile.serial file for how to specify the 3 MPI variables. You will also need to build the STUBS library for your platform before making LAMMPS itself. From the STUBS dir, type "make" and it will hopefully create a libmpi.a suitable for linking to LAMMPS. If this build fails, you will need to edit the STUBS/Makefile for your platform. The file STUBS/mpi.cpp has a CPU timer function MPI_Wtime() that calls gettimeofday() . If your system doesn't support gettimeofday() , you'll need to insert code to call another timer. Note that the ANSI-standard function clock() rolls over after an hour or so, and is therefore insufficient for timing long LAMMPS simulations. (3.c) The 3 FFT variables are used to specify an FFT library which LAMMPS uses when using the particle-particle particle-mesh (PPPM) option in LAMMPS for long-range Coulombics via the "kspace_style"_kspace_style.html command. To use this option, you must have a 1d FFT library installed on your platform. This is specified by a switch of the form -DFFT_XXX where XXX = INTEL, DEC, SGI, SCSL, or FFTW. All but the last one are native vendor-provided libraries. FFTW is a fast, portable library that should work on any platform. You can download it from "www.fftw.org"_http://www.fftw.org. Use version 2.1.X, not the newer 3.0.X. Building FFTW for your box should be as simple as ./configure; make. Whichever FFT library you have on your platform, you'll need to set the appropriate FFT_INC, FFT_PATH, and FFT_LIB variables in Makefile.foo. If you examine src/fft3d.c and src.fft3d.h you'll see it's possible to add other vendor FFT libraries via #ifdef statements in the appropriate places. If you successfully add a new FFT option, like -DFFT_IBM, please send the LAMMPS developers an email; we'd like to add it to LAMMPS. If you don't plan to use PPPM, you don't need an FFT library. In this case you can set FFT_INC to -DFFT_NONE and leave the other 2 FFT variables blank. Or you can exclude the KSPACE package when you build LAMMPS (see below). (3.d) The several SYSLIB and SYSPATH variables can be ignored unless you are building LAMMPS with one or more of the LAMMPS packages that require these extra system libraries. The names of these packages are the prefixes on the SYSLIB and SYSPATH variables. See the "section below"_#2_3_4 for more details. The SYSLIB variables list the system libraries. The SYSPATH variables are where they are located on your machine, which is typically only needed if they are in some non-standard place, that is not in your library search path. That's it. Once you have a correct Makefile.foo and you have pre-built any other libraries it will use (e.g. MPI, FFT, package libraries), all you need to do from the src directory is type one of these 2 commands: make foo gmake foo :pre You should get the executable lmp_foo when the build is complete. :line [{Additional build tips:}] :link(2_2_5) (1) Building LAMMPS for multiple platforms. You can make LAMMPS for multiple platforms from the same src directory. Each target creates its own object sub-directory called Obj_name where it stores the system-specific *.o files. (2) Cleaning up. Typing "make clean-all" or "make clean-foo" will delete *.o object files created when LAMMPS is built, for either all builds or for a particular machine. (3) Building for a Mac. OS X is BSD Unix, so it should just work. See the Makefile.mac file. (4) Building for MicroSoft Windows. The LAMMPS download page has an option to download a pre-built Windows exeutable. See below for instructions for running this executable on a Windows box. If the pre-built executable doesn't have the options you want, then you should be able to build LAMMPS from source files on a Windows box. I've never done this, but LAMMPS is just standard C++ with MPI and FFT calls. You can use cygwin to build LAMMPS with a Unix make; see Makefile.cygwin. Or you should be able to pull all the source files into Visual C++ (ugh) or some similar development environment and build it. In the src/MAKE/Windows directory are some notes from users on how they built LAMMPS under Windows, so you can look at their instructions for tips. Good luck - we can't help you on this one. +(5) Changing the size limits in src/lmptype.h + +If you are running a very large problem (billions of atoms or more) +and get a run-time error about the system being too big, either on a +per-processor basis or in total size, then you may need to change one +or more settings in src/lmptype.h and re-compile LAMMPS. + +As the documentation in that file explains, you have basically +two choices to make: + +set the data type size of integer atom IDs to 4 or 8 bytes +set the data type size of integers that store the total system size to 4 or 8 bytes :ul + +The default for atom IDs is 4-byte integers since there is a memory +and communication cost for 8-byte integers. Non-molecular problems do +not need atom IDs so this does not restrict their size. Molecular +problems (which use IDs to define molecular topology), are limited to +about 2 billion atoms (2^31) with 4-byte IDs. With 8-byte IDs they +are effectively unlimited in size (2^63). + +The default for total system size quantities (like the number of atoms +or timesteps) is 8-byte integers by default which is effectively +unlimited in size (2^63). If your system does not support 8-byte +integers, an error will be generated, and you will need to set +"bigint" to 4-byte integers. This restricts your total system size to +about 2 billion atoms or timesteps (2^31). + +Note that in src/lmptype.h there are also settings for the MPI data +types associated with the integers that store atom IDs and total +system sizes, which need to be set consistent with the associated C +data types. + +In all cases, the size of problem that can be run on a per-processor +basis is limited by 4-byte integer storage to about 2 billion atoms +per processor (2^31), which should not normally be a restriction since +such a problem would have a huge per-processor memory footprint due to +neighbor lists and would run very slowly in terms of CPU +secs/timestep. + :line 2.3 Making LAMMPS with optional packages :h4,link(2_3) This section has the following sub-sections: "Package basics"_#2_3_1 "Including/excluding packages"_#2_3_2 "Packages that require extra LAMMPS libraries"_#2_3_3 "Additional Makefile settings for extra libraries"_#2_3_4 :ul :line [{Package basics:}] :link(2_3_1) The source code for LAMMPS is structured as a large set of core files which are always included, plus optional packages. Packages are groups of files that enable a specific set of features. For example, force fields for molecular systems or granular systems are in packages. You can see the list of all packages by typing "make package". The current list of standard packages is as follows: asphere : aspherical particles and force fields class2 : class 2 force fields colloid : colloidal particle force fields dipole : point dipole particles and force fields dsmc : Direct Simulation Monte Carlo (DMSC) pair style gpu : GPU-enabled force field styles granular : force fields and boundary conditions for granular systems kspace : long-range Ewald and particle-mesh (PPPM) solvers manybody : metal, 3-body, bond-order potentials meam : modified embedded atom method (MEAM) potential molecule : force fields for molecular systems opt : optimized versions of a few pair potentials peri : Peridynamics model and potential poems : coupled rigid body motion reax : ReaxFF potential replica : multi-replica methods shock : methods for MD simulations of shock loading srd : stochastic rotation dynamics (SRD) xtc : dump atom snapshots in XTC format :tb(s=:) There are also user-contributed packages which may be as simple as a single additional file or many files grouped together which add a specific functionality to the code. The difference between a {standard} package versus a {user} package is as follows. Standard packages are supported by the LAMMPS developers and are written in a syntax and style consistent with the rest of LAMMPS. This means we will answer questions about them, debug and fix them if necessary, and keep them compatible with future changes to LAMMPS. User packages don't necessarily meet these requirements. If you have problems using a feature provided in a user package, you will likely need to contact the contributor directly to get help. Information on how to submit additions you make to LAMMPS as a user-contributed package is given in "this section"_Section_modify.html#package of the documentation. :line [{Including/excluding packages:}] :link(2_3_2) Any or all packages can be included or excluded independently BEFORE LAMMPS is built. The two exceptions to this are the "gpu" and "opt" packages. Some of the files in these packages require other packages to also be included. If this is not the case, then those subsidiary files in "gpu" and "opt" will not be installed either. To install all the files in package "gpu", the "asphere" and "kspace" packages must also be installed. To install all the files in package "opt", the "kspace" and "manybody" packages must also be installed. You may wish to exclude certain packages if you will never run certain kinds of simulations. This will keep you from having to build auxiliary libraries (see below) and will produce a smaller executable which may run a bit faster. By default, LAMMPS includes only the "kspace", "manybody", and "molecule" packages. Packages are included or excluded by typing "make yes-name" or "make no-name", where "name" is the name of the package. You can also type "make yes-standard", "make no-standard", "make yes-user", "make no-user", "make yes-all" or "make no-all" to include/exclude various sets of packages. Type "make package" to see the various options. IMPORTANT NOTE: These make commands work by simply moving files back and forth between the main src directory and sub-directories with the package name, so that the files are seen or not seen when LAMMPS is built. After you have included or excluded a package, you must re-build LAMMPS. Additional make options exist to help manage LAMMPS files that exist in both the src directory and in package sub-directories. You do not normally need to use these commands unless you are editing LAMMPS files or have downloaded a patch from the LAMMPS WWW site. Typing "make package-update" will overwrite src files with files from the package directories if the package has been included. It should be used after a patch is installed, since patches only update the master package version of a file. Typing "make package-overwrite" will overwrite files in the package directories with src files. Typing "make package-check" will list differences between src and package versions of the same files. Again, type "make package" to see the various options. :line [{Packages that require extra LAMMPS libraries:}] :link(2_3_3) A few packages (standard or user) require that additional libraries be compiled first, which LAMMPS will link to when it builds. The source code for these libraries are included in the LAMMPS distribution under the "lib" directory. Look at the README files in the lib directories (e.g. lib/reax/README) for instructions on how to build each library. IMPORTANT NOTE: If you are including a package in your LAMMPS build that uses one of these libraries, then you must build the library BEFORE building LAMMPS itself, since the LAMMPS build will attempt to link with the library file. Here is a bit of information about each library: The "atc" library in lib/atc is used by the user-atc package. It provides continuum field estimation and molecular dynamics-finite element coupling methods. It was written primarily by Reese Jones, Jeremy Templeton and Jonathan Zimmerman at Sandia. The "gpu" library in lib/gpu is used by the gpu package. It contains code to enable portions of LAMMPS to run on a GPU chip associated with your CPU. Currently, only NVIDIA GPUs are supported. Building this library requires NVIDIA Cuda tools to be installed on your system. See the "Running on GPUs"_#2_8 section below for more info about installing and using Cuda. The "meam" library in lib/meam is used by the meam package. computes the modified embedded atom method potential, which is a generalization of EAM potentials that can be used to model a wider variety of materials. This MEAM implementation was written by Greg Wagner at Sandia. It requires a F90 compiler to build. The C++ to FORTRAN function calls in pair_meam.cpp assumes that FORTRAN object names are converted to C object names by appending an underscore character. This is generally the case, but on machines that do not conform to this convention, you will need to modify either the C++ code or your compiler settings. The "poems" library in lib/poems is used by the poems package. computes the constrained rigid-body motion of articulated (jointed) multibody systems. POEMS was written and is distributed by Prof Kurt Anderson's group at Rensselaer Polytechnic Institute (RPI). The "reax" library in lib/reax is used by the reax package. It computes the Reactive Force Field (ReaxFF) potential, developed by Adri van Duin in Bill Goddard's group at CalTech. This implementation in LAMMPS uses many of Adri's files and was developed by Aidan Thompson at Sandia and Hansohl Cho at MIT. It requires a F77 or F90 compiler to build. The C++ to FORTRAN function calls in pair_reax.cpp assume that FORTRAN object names are converted to C object names by appending an underscore character. This is generally the case, but on machines that do not conform to this convention, you will need to modify either the C++ code or your compiler settings. The name conversion is handled by the preprocessor macro called FORTRAN in pair_reax_fortran.h. Different definitions of this macro can be obtained by adding a machine-specific macro definition to the CCFLAGS variable in your Makefile e.g. -D_IBM. See pair_reax_fortran.h for more info. As described in its README file, each library is built by typing something like make -f Makefile.g++ :pre in the appropriate directory, e.g. in lib/reax. You must use a Makefile that is a match for your system. If one of the provided Makefiles is not appropriate for your system you will need to edit or add one. For example, in the case of Fotran-based libraries, your system must have a Fortran compiler, the settings for which will be in the Makefile. :line [{Additional Makefile settings for extra libraries:}] :link(2_3_4) After the desired library or libraries are built, and the package has been included, you can build LAMMPS itself. For example, from the lammps/src directory you would type this, to build LAMMPS with ReaxFF. Note that as discussed in the preceding section, the package library itself, namely lib/reax/libreax.a, must already have been built, for the LAMMPS build to be successful. make yes-reax make g++ :pre Also note that simply building the library is not sufficient to use it from LAMMPS. As in this example, you must also include the package that uses and wraps the library before you build LAMMPS itself. As discussed in point (2.4) of "this section"_#2_2_4 above, there are settings in the low-level Makefile that specify additional system libraries needed by individual LAMMPS add-on libraries. These are the settings you must specify correctly in your low-level Makefile in lammps/src/MAKE, such as Makefile.foo: To use the gpu package and library, the settings for gpu_SYSLIB and gpu_SYSPATH must be correct. These are specific to the NVIDIA CUDA software which must be installed on your system. To use the meam or reax packages and their libraries which are Fortran based, the settings for meam_SYSLIB, reax_SYSLIB, meam_SYSPATH, and reax_SYSPATH must be correct. This is so that the C++ compiler can perform a cross-language link using the appropriate system Fortran libraries. To use the user-atc package and library, the settings for user-atc_SYSLIB and user-atc_SYSPATH must be correct. This is so that the appropriate BLAS and LAPACK libs, used by the user-atc library, can be found. :line 2.4 Building LAMMPS as a library :h4,link(2_4) LAMMPS can be built as a library, which can then be called from another application or a scripting language. See "this section"_Section_howto.html#4_10 for more info on coupling LAMMPS to other codes. Building LAMMPS as a library is done by typing make makelib make -f Makefile.lib foo :pre where foo is the machine name. The first "make" command will create a current Makefile.lib with all the file names in your src dir. The 2nd "make" command will use it to build LAMMPS as a library. This requires that Makefile.foo have a library target (lib) and system-specific settings for ARCHIVE and ARFLAGS. See Makefile.linux for an example. The build will create the file liblmp_foo.a which another application can link to. When used from a C++ program, the library allows one or more LAMMPS objects to be instantiated. All of LAMMPS is wrapped in a LAMMPS_NS namespace; you can safely use any of its classes and methods from within your application code, as needed. When used from a C or Fortran program or a scripting language, the library has a simple function-style interface, provided in src/library.cpp and src/library.h. See the sample codes couple/simple/simple.cpp and simple.c as examples of C++ and C codes that invoke LAMMPS thru its library interface. There are other examples as well in the couple directory which are discussed in "this section"_Section_howto.html#4_10 of the manual. See "this section"_Section_python.html of the manual for a description of the Python wrapper provided with LAMMPS that operates through the LAMMPS library interface. The files src/library.cpp and library.h contain the C-style interface to LAMMPS. See "this section"_Section_howto.html#4_19 of the manual for a description of the interface and how to extend it for your needs. :line 2.5 Running LAMMPS :h4,link(2_5) By default, LAMMPS runs by reading commands from stdin; e.g. lmp_linux < in.file. This means you first create an input script (e.g. in.file) containing the desired commands. "This section"_Section_commands.html describes how input scripts are structured and what commands they contain. You can test LAMMPS on any of the sample inputs provided in the examples directory. Input scripts are named in.* and sample outputs are named log.*.name.P where name is a machine and P is the number of processors it was run on. Here is how you might run one of the Lennard-Jones tests on a Linux box, using mpirun to launch a parallel job: cd src make linux cp lmp_linux ../examples/lj cd ../examples/lj mpirun -np 4 lmp_linux < in.lj.nve :pre :line On a Windows machine, you can skip making LAMMPS and simply download an executable. But note that not all packages are available. The following packages are available: asphere, class2, colloid, dipole, dsmc, granular, kspace, manybody, molecule, peri, poems, replica, shock, user-ackland, user-cd-eam, user-cg-cmm, user-ewaldn, user-smd. But these packages are not available: gpu, meam, opt, reax, xtc, user-atc, user-imd. To run the LAMMPS executable on a Windows machine, first decide whether you want to download the non-MPI (serial) or the MPI (parallel) version of the executable. Download and save the version you have chosen. For the non-MPI version, follow these steps: Get a command prompt by going to Start->Run... , then typing "cmd". :ulb,l Move to the directory where you have saved lmp_win_no-mpi.exe (e.g. by typing: cd "Documents"). :l At the command prompt, type "lmp_win_no-mpi -in in.lj", replacing in.lj with the name of your LAMMPS input script. :l,ule For the MPI version, which allows you to run LAMMPS under Windows on multiple processors, follow these steps: Download and install "MPICH2"_http://www.mcs.anl.gov/research/projects/mpich2/downloads/index.php?s=downloads for Windows. :ulb,l You'll need to use the mpiexec.exe and smpd.exe files from the MPICH2 package. Put them in same directory (or path) as the LAMMPS Windows executable. :l Get a command prompt by going to Start->Run... , then typing "cmd". :l Move to the directory where you have saved lmp_win_mpi.exe (e.g. by typing: cd "Documents"). :l Then type something like this: "mpiexec -np 4 -localonly lmp_win_mpi -in in.lj", replacing in.lj with the name of your LAMMPS input script. :l Note that you may need to provide smpd with a passphrase --- it doesn't matter what you type. :l In this mode, output may not immediately show up on the screen, so if your input script takes a long time to execute, you may need to be patient before the output shows up. :l Alternatively, you can still use this executable to run on a single processor by typing something like: "lmp_win_mpi -in in.lj". :l,ule :line The screen output from LAMMPS is described in the next section. As it runs, LAMMPS also writes a log.lammps file with the same information. Note that this sequence of commands copies the LAMMPS executable (lmp_linux) to the directory with the input files. This may not be necessary, but some versions of MPI reset the working directory to where the executable is, rather than leave it as the directory where you launch mpirun from (if you launch lmp_linux on its own and not under mpirun). If that happens, LAMMPS will look for additional input files and write its output files to the executable directory, rather than your working directory, which is probably not what you want. If LAMMPS encounters errors in the input script or while running a simulation it will print an ERROR message and stop or a WARNING message and continue. See "this section"_Section_errors.html for a discussion of the various kinds of errors LAMMPS can or can't detect, a list of all ERROR and WARNING messages, and what to do about them. LAMMPS can run a problem on any number of processors, including a single processor. In theory you should get identical answers on any number of processors and on any machine. In practice, numerical round-off can cause slight differences and eventual divergence of molecular dynamics phase space trajectories. LAMMPS can run as large a problem as will fit in the physical memory of one or more processors. If you run out of memory, you must run on more processors or setup a smaller problem. :line 2.6 Command-line options :h4,link(2_6) At run time, LAMMPS recognizes several optional command-line switches which may be used in any order. For example, lmp_ibm might be launched as follows: mpirun -np 16 lmp_ibm -var f tmp.out -log my.log -screen none < in.alloy :pre These are the command-line options: -echo style :pre Set the style of command echoing. The style can be {none} or {screen} or {log} or {both}. Depending on the style, each command read from the input script will be echoed to the screen and/or logfile. This can be useful to figure out which line of your script is causing an input error. The default value is {log}. The echo style can also be set by using the "echo"_echo.html command in the input script itself. -partition 8x2 4 5 ... :pre Invoke LAMMPS in multi-partition mode. When LAMMPS is run on P processors and this switch is not used, LAMMPS runs in one partition, i.e. all P processors run a single simulation. If this switch is used, the P processors are split into separate partitions and each partition runs its own simulation. The arguments to the switch specify the number of processors in each partition. Arguments of the form MxN mean M partitions, each with N processors. Arguments of the form N mean a single partition with N processors. The sum of processors in all partitions must equal P. Thus the command "-partition 8x2 4 5" has 10 partitions and runs on a total of 25 processors. Note that with MPI installed on a machine (e.g. your desktop), you can run on more (virtual) processors than you have physical processors. This can be useful for running "multi-replica simulations"_Section_howto.html#4_5, on one or a few processors. The input script specifies what simulation is run on which partition; see the "variable"_variable.html and "next"_next.html commands. This "howto section"_Section_howto.html#4_4 gives examples of how to use these commands in this way. Simulations running on different partitions can also communicate with each other; see the "temper"_temper.html command. -in file :pre Specify a file to use as an input script. This is an optional switch when running LAMMPS in one-partition mode. If it is not specified, LAMMPS reads its input script from stdin - e.g. lmp_linux < in.run. This is a required switch when running LAMMPS in multi-partition mode, since multiple processors cannot all read from stdin. -log file :pre Specify a log file for LAMMPS to write status information to. In one-partition mode, if the switch is not used, LAMMPS writes to the file log.lammps. If this switch is used, LAMMPS writes to the specified file. In multi-partition mode, if the switch is not used, a log.lammps file is created with hi-level status information. Each partition also writes to a log.lammps.N file where N is the partition ID. If the switch is specified in multi-partition mode, the hi-level logfile is named "file" and each partition also logs information to a file.N. For both one-partition and multi-partition mode, if the specified file is "none", then no log files are created. Using a "log"_log.html command in the input script will override this setting. -screen file :pre Specify a file for LAMMPS to write its screen information to. In one-partition mode, if the switch is not used, LAMMPS writes to the screen. If this switch is used, LAMMPS writes to the specified file instead and you will see no screen output. In multi-partition mode, if the switch is not used, hi-level status information is written to the screen. Each partition also writes to a screen.N file where N is the partition ID. If the switch is specified in multi-partition mode, the hi-level screen dump is named "file" and each partition also writes screen information to a file.N. For both one-partition and multi-partition mode, if the specified file is "none", then no screen output is performed. -var name value :pre Specify a variable that will be defined for substitution purposes when the input script is read. "Name" is the variable name which can be a single character (referenced as $x in the input script) or a full string (referenced as $\{abc\}). The value can be any string. Using this command-line option is equivalent to putting the line "variable name index value" at the beginning of the input script. Defining an index variable as a command-line argument overrides any setting for the same index variable in the input script, since index variables cannot be re-defined. See the "variable"_variable.html command for more info on defining index and other kinds of variables and "this section"_Section_commands.html#3_2 for more info on using variables in input scripts. :line 2.7 LAMMPS screen output :h4,link(2_7) As LAMMPS reads an input script, it prints information to both the screen and a log file about significant actions it takes to setup a simulation. When the simulation is ready to begin, LAMMPS performs various initializations and prints the amount of memory (in MBytes per processor) that the simulation requires. It also prints details of the initial thermodynamic state of the system. During the run itself, thermodynamic information is printed periodically, every few timesteps. When the run concludes, LAMMPS prints the final thermodynamic state and a total run time for the simulation. It then appends statistics about the CPU time and storage requirements for the simulation. An example set of statistics is shown here: Loop time of 49.002 on 2 procs for 2004 atoms :pre Pair time (%) = 35.0495 (71.5267) Bond time (%) = 0.092046 (0.187841) Kspce time (%) = 6.42073 (13.103) Neigh time (%) = 2.73485 (5.5811) Comm time (%) = 1.50291 (3.06703) Outpt time (%) = 0.013799 (0.0281601) Other time (%) = 2.13669 (4.36041) :pre Nlocal: 1002 ave, 1015 max, 989 min Histogram: 1 0 0 0 0 0 0 0 0 1 Nghost: 8720 ave, 8724 max, 8716 min Histogram: 1 0 0 0 0 0 0 0 0 1 Neighs: 354141 ave, 361422 max, 346860 min Histogram: 1 0 0 0 0 0 0 0 0 1 :pre Total # of neighbors = 708282 Ave neighs/atom = 353.434 Ave special neighs/atom = 2.34032 Number of reneighborings = 42 Dangerous reneighborings = 2 :pre The first section gives the breakdown of the CPU run time (in seconds) into major categories. The second section lists the number of owned atoms (Nlocal), ghost atoms (Nghost), and pair-wise neighbors stored per processor. The max and min values give the spread of these values across processors with a 10-bin histogram showing the distribution. The total number of histogram counts is equal to the number of processors. The last section gives aggregate statistics for pair-wise neighbors and special neighbors that LAMMPS keeps track of (see the "special_bonds"_special_bonds.html command). The number of times neighbor lists were rebuilt during the run is given as well as the number of potentially "dangerous" rebuilds. If atom movement triggered neighbor list rebuilding (see the "neigh_modify"_neigh_modify.html command), then dangerous reneighborings are those that were triggered on the first timestep atom movement was checked for. If this count is non-zero you may wish to reduce the delay factor to insure no force interactions are missed by atoms moving beyond the neighbor skin distance before a rebuild takes place. If an energy minimization was performed via the "minimize"_minimize.html command, additional information is printed, e.g. Minimization stats: E initial, next-to-last, final = -0.895962 -2.94193 -2.94342 Gradient 2-norm init/final= 1920.78 20.9992 Gradient inf-norm init/final= 304.283 9.61216 Iterations = 36 Force evaluations = 177 :pre The first line lists the initial and final energy, as well as the energy on the next-to-last iteration. The next 2 lines give a measure of the gradient of the energy (force on all atoms). The 2-norm is the "length" of this force vector; the inf-norm is the largest component. The last 2 lines are statistics on how many iterations and force-evaluations the minimizer required. Multiple force evaluations are typically done at each iteration to perform a 1d line minimization in the search direction. If a "kspace_style"_kspace_style.html long-range Coulombics solve was performed during the run (PPPM, Ewald), then additional information is printed, e.g. FFT time (% of Kspce) = 0.200313 (8.34477) FFT Gflps 3d 1d-only = 2.31074 9.19989 :pre The first line gives the time spent doing 3d FFTs (4 per timestep) and the fraction it represents of the total KSpace time (listed above). Each 3d FFT requires computation (3 sets of 1d FFTs) and communication (transposes). The total flops performed is 5Nlog_2(N), where N is the number of points in the 3d grid. The FFTs are timed with and without the communication and a Gflop rate is computed. The 3d rate is with communication; the 1d rate is without (just the 1d FFTs). Thus you can estimate what fraction of your FFT time was spent in communication, roughly 75% in the example above. :line 2.8 Running on GPUs :h4,link(2_8) A few LAMMPS "pair styles"_pair_style.html can be run on graphical processing units (GPUs). We plan to add more over time. Currently, they only support NVIDIA GPU cards. To use them you need to install certain NVIDIA CUDA software on your system: Check if you have an NVIDIA card: cat /proc/driver/nvidia/cards/0 Go to http://www.nvidia.com/object/cuda_get.html Install a driver and toolkit appropriate for your system (SDK is not necessary) Follow the instructions in README in lammps/lib/gpu to build the library. Run lammps/lib/gpu/nvc_get_devices to list supported devices and properties :ul GPU configuration :h4 When using GPUs, you are restricted to one physical GPU per LAMMPS process. Multiple processes can share a single GPU and in many cases it will be more efficient to run with multiple processes per GPU. Any GPU accelerated style requires that "fix gpu"_fix_gpu.html be used in the input script to select and initialize the GPUs. The format for the fix is: fix {name} all gpu {mode} {first} {last} {split} :pre where {name} is the name for the fix. The gpu fix must be the first fix specified for a given run, otherwise the program will exit with an error. The gpu fix will not have any effect on runs that do not use GPU acceleration; there should be no problem with specifying the fix first in any input script. {mode} can be either "force" or "force/neigh". In the former, neighbor list calculation is performed on the CPU using the standard LAMMPS routines. In the latter, the neighbor list calculation is performed on the GPU. The GPU neighbor list can be used for better performance, however, it should not be used with a triclinic box. There are cases when it might be more efficient to select the CPU for neighbor list builds. If a non-GPU enabled style requires a neighbor list, it will also be built using CPU routines. Redundant CPU and GPU neighbor list calculations will typically be less efficient. For "hybrid"_pair_hybrid.html pair styles, GPU calculated neighbor lists might be less efficient because no particles will be skipped in a given neighbor list. {first} is the ID (as reported by lammps/lib/gpu/nvc_get_devices) of the first GPU that will be used on each node. {last} is the ID of the last GPU that will be used on each node. If you have only one GPU per node, {first} and {last} will typically both be 0. Selecting a non-sequential set of GPU IDs (e.g. 0,1,3) is not currently supported. {split} is the fraction of particles whose forces, torques, energies, and/or virials will be calculated on the GPU. This can be used to perform CPU and GPU force calculations simultaneously. If {split} is negative, the software will attempt to calculate the optimal fraction automatically every 25 timesteps based on CPU and GPU timings. Because the GPU speedups are dependent on the number of particles, automatic calculation of the split can be less efficient, but typically results in loop times within 20% of an optimal fixed split. If you have two GPUs per node, 8 CPU cores per node, and would like to run on 4 nodes with dynamic balancing of force calculation across CPU and GPU cores, the fix might be fix 0 all gpu force/neigh 0 1 -1 :pre with LAMMPS run on 32 processes. In this case, all CPU cores and GPU devices on the nodes would be utilized. Each GPU device would be shared by 4 CPU cores. The CPU cores would perform force calculations for some fraction of the particles at the same time the GPUs performed force calculation for the other particles. Because of the large number of cores on each GPU device, it might be more efficient to run on fewer processes per GPU when the number of particles per process is small (100's of particles); this can be necessary to keep the GPU cores busy. GPU input script :h4 In order to use GPU acceleration in LAMMPS, "fix_gpu"_fix_gpu.html should be used in order to initialize and configure the GPUs for use. Additionally, GPU enabled styles must be selected in the input script. Currently, this is limited to a few "pair styles"_pair_style.html. Some GPU-enabled styles have additional restrictions listed in their documentation. GPU asynchronous pair computation :h4 The GPU accelerated pair styles can be used to perform pair style force calculation on the GPU while other calculations are performed on the CPU. One method to do this is to specify a {split} in the gpu fix as described above. In this case, force calculation for the pair style will also be performed on the CPU. When the CPU work in a GPU pair style has finished, the next force computation will begin, possibly before the GPU has finished. If {split} is 1.0 in the gpu fix, the next force computation will begin almost immediately. This can be used to run a "hybrid"_pair_hybrid.html GPU pair style at the same time as a hybrid CPU pair style. In this case, the GPU pair style should be first in the hybrid command in order to perform simultaneous calculations. This also allows "bond"_bond_style.html, "angle"_angle_style.html, "dihedral"_dihedral_style.html, "improper"_improper_style.html, and "long-range"_kspace_style.html force computations to be run simultaneously with the GPU pair style. Once all CPU force computations have completed, the gpu fix will block until the GPU has finished all work before continuing the run. GPU timing :h4 GPU accelerated pair styles can perform computations asynchronously with CPU computations. The "Pair" time reported by LAMMPS will be the maximum of the time required to complete the CPU pair style computations and the time required to complete the GPU pair style computations. Any time spent for GPU-enabled pair styles for computations that run simultaneously with "bond"_bond_style.html, "angle"_angle_style.html, "dihedral"_dihedral_style.html, "improper"_improper_style.html, and "long-range"_kspace_style.html calculations will not be included in the "Pair" time. When {mode} for the gpu fix is force/neigh, the time for neighbor list calculations on the GPU will be added into the "Pair" time, not the "Neigh" time. A breakdown of the times required for various tasks on the GPU (data copy, neighbor calculations, force computations, etc.) are output only with the LAMMPS screen output at the end of each run. These timings represent total time spent on the GPU for each routine, regardless of asynchronous CPU calculations. GPU single vs double precision :h4 See the lammps/lib/gpu/README file for instructions on how to build the LAMMPS gpu library for single, mixed, and double precision. The latter requires that your GPU card supports double precision. :line 2.9 Tips for users of previous LAMMPS versions :h4,link(2_9) The current C++ began with a complete rewrite of LAMMPS 2001, which was written in F90. Features of earlier versions of LAMMPS are listed in "this section"_Section_history.html. The F90 and F77 versions (2001 and 99) are also freely distributed as open-source codes; check the "LAMMPS WWW Site"_lws for distribution information if you prefer those versions. The 99 and 2001 versions are no longer under active development; they do not have all the features of C++ LAMMPS. If you are a previous user of LAMMPS 2001, these are the most significant changes you will notice in C++ LAMMPS: (1) The names and arguments of many input script commands have changed. All commands are now a single word (e.g. read_data instead of read data). (2) All the functionality of LAMMPS 2001 is included in C++ LAMMPS, but you may need to specify the relevant commands in different ways. (3) The format of the data file can be streamlined for some problems. See the "read_data"_read_data.html command for details. The data file section "Nonbond Coeff" has been renamed to "Pair Coeff" in C++ LAMMPS. (4) Binary restart files written by LAMMPS 2001 cannot be read by C++ LAMMPS with a "read_restart"_read_restart.html command. This is because they were output by F90 which writes in a different binary format than C or C++ writes or reads. Use the {restart2data} tool provided with LAMMPS 2001 to convert the 2001 restart file to a text data file. Then edit the data file as necessary before using the C++ LAMMPS "read_data"_read_data.html command to read it in. (5) There are numerous small numerical changes in C++ LAMMPS that mean you will not get identical answers when comparing to a 2001 run. However, your initial thermodynamic energy and MD trajectory should be close if you have setup the problem for both codes the same. diff --git a/doc/run.html b/doc/run.html index d3ac108fb..da99cd1fb 100644 --- a/doc/run.html +++ b/doc/run.html @@ -1,189 +1,194 @@ <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>run command </H3> <P><B>Syntax:</B> </P> <PRE>run N keyword values ... </PRE> <UL><LI>N = # of timesteps <LI>zero or more keyword/value pairs may be appended <LI>keyword = <I>upto</I> or <I>start</I> or <I>stop</I> or <I>pre</I> or <I>post</I> or <I>every</I> <PRE> <I>upto</I> value = none <I>start</I> value = N1 N1 = timestep at which 1st run started <I>stop</I> value = N2 N2 = timestep at which last run will end <I>pre</I> value = <I>no</I> or <I>yes</I> <I>post</I> value = <I>no</I> or <I>yes</I> <I>every</I> values = M c1 c2 ... M = break the run into M-timestep segments and invoke one or more commands between each segment c1,c2,...,cN = one or more LAMMPS commands, each enclosed in quotes c1 = NULL means no command will be invoked </PRE> </UL> <P><B>Examples:</B> </P> <PRE>run 10000 run 1000000 upto run 100 start 0 stop 1000 run 1000 pre no post yes run 100000 start 0 stop 1000000 every 1000 "print 'Protein Rg = $r'" run 100000 every 1000 NULL </PRE> <P><B>Description:</B> </P> <P>Run or continue dynamics for a specified number of timesteps. </P> <P>When the <A HREF = "run_style.html">run style</A> is <I>respa</I>, N refers to outer loop (largest) timesteps. </P> <P>A value of N = 0 is acceptable; only the thermodynamics of the system are computed and printed without taking a timestep. </P> <P>The <I>upto</I> keyword means to perform a run starting at the current timestep up to the specified timestep. E.g. if the current timestep is 10,000 and "run 100000 upto" is used, then an additional 90,000 timesteps will be run. This can be useful for very long runs on a machine that allocates chunks of time and terminate your job when time is exceeded. If you need to restart your script multiple times (reading in the last restart file), you can keep restarting your script with the same run command until the simulation finally completes. </P> <P>The <I>start</I> or <I>stop</I> keywords can be used if multiple runs are being performed and you want a <A HREF = "fix.html">fix</A> command that changes some value over time (e.g. temperature) to make the change across the entire set of runs and not just a single run. See the doc page for individual fixes to see which ones can be used with the <I>start/stop</I> keywords. </P> <P>For example, consider this fix followed by 10 run commands: </P> <PRE>fix 1 all nvt 200.0 300.0 1.0 run 1000 start 0 stop 10000 run 1000 start 0 stop 10000 ... run 1000 start 0 stop 10000 </PRE> <P>The NVT fix ramps the target temperature from 200.0 to 300.0 during a run. If the run commands did not have the start/stop keywords (just "run 1000"), then the temperature would ramp from 200.0 to 300.0 during the 1000 steps of each run. With the start/stop keywords, the ramping takes place over the 10000 steps of all runs together. </P> <P>The <I>pre</I> and <I>post</I> keywords can be used to streamline the setup, clean-up, and associated output to the screen that happens before and after a run. This can be useful if you wish to do many short runs in succession (e.g. LAMMPS is being called as a library which is doing other computations between successive short LAMMPS runs). </P> <P>By default (pre and post = yes), LAMMPS creates neighbor lists, computes forces, and imposes fix constraints before every run. And after every run it gathers and prints timings statistics. If a run is just a continuation of a previous run (i.e. no settings are changed), the initial computation is not necessary; the old neighbor list is still valid as are the forces. So if <I>pre</I> is specified as "no" then the initial setup is skipped, except for printing thermodynamic info. Note that if <I>pre</I> is set to "no" for the very 1st run LAMMPS performs, then it is overridden, since the initial setup computations must be done. </P> <P>IMPORTANT NOTE: If your input script changes settings between 2 runs (e.g. adds a <A HREF = "fix.html">fix</A> or <A HREF = "dump.html">dump</A> or <A HREF = "compute.html">compute</A> or changes a <A HREF = "neigh_modify.html">neighbor</A> list parameter), then the initial setup must be performed. LAMMPS does not check for this, but it would be an error to use the <I>pre no</I> option in this case. </P> <P>If <I>post</I> is specified as "no", the full timing summary is skipped; only a one-line summary timing is printed. </P> <P>The <I>every</I> keyword provides a means of breaking a LAMMPS run into a series of shorter runs. Optionally, one or more LAMMPS commands (c1, c2, ..., cN) will be executed in between the short runs. If used, the <I>every</I> keyword must be the last keyword, since it has a variable number of arguments. Each of the trailing arguments is a single LAMMPS command, and each command should be enclosed in quotes, so that the entire command will be treated as a single argument. This will also prevent any variables in the command from being evaluated until it is executed multiple times during the run. Note that if a command itself needs one of its arguments quoted (e.g. the <A HREF = "print.html">print</A> command), then you can use a combination of single and double quotes, as in the example above or below. </P> <P>The <I>every</I> keyword is a means to avoid listing a long series of runs and interleaving commands in your input script. For example, a <A HREF = "print.html">print</A> command could be invoked or a <A HREF = "fix.html">fix</A> could be redefined, e.g. to reset a thermostat temperature. Or this could be useful for invoking a command you have added to LAMMPS that wraps some other code (e.g. as a library) to perform a computation periodically during a long LAMMPS run. See <A HREF = "Section_modify.html">this section</A> of the documentation for info about how to add new commands to LAMMPS. See <A HREF = "Section_howto.html#4_10">this section</A> of the documentation for ideas about how to couple LAMMPS to other codes. </P> <P>With the <I>every</I> option, N total steps are simulated, in shorter runs of M steps each. After each M-length run, the specified commands are invoked. If only a single command is specified as NULL, then no command is invoked. Thus these lines: </P> <PRE>variable q equal x[100] run 6000 every 2000 "print Coord = $q" </PRE> <P>are the equivalent of: </P> <PRE>variable q equal x[100] run 2000 print Coord = $q run 2000 print Coord = $q run 2000 print Coord = $q </PRE> <P>which does 3 runs of 2000 steps and prints the x-coordinate of a particular atom between runs. Note that the variable "$q" will be evaluated afresh each time the print command is executed. </P> <P>Note that by using the line continuation character "&", the run every command can be spread across many lines, though it is still a single command: </P> <PRE>run 100000 every 1000 & "print 'Minimum value = $a'" & "print 'Maximum value = $b'" & "print 'Temp = $c'" & "print 'Press = $d'" </PRE> <P>If the <I>pre</I> and <I>post</I> options are set to "no" when used with the <I>every</I> keyword, then the 1st run will do the full setup and the last run will print the full timing summary, but these operations will be skipped for intermediate runs. </P> -<P><B>Restrictions:</B> none +<P><B>Restrictions:</B> +</P> +<P>The number of specified timesteps N must fit in a signed 32-bit +integer, so you are limited to slightly more than 2 billion steps +(2^31) in a single run. However, you can perform successive runs to +run a simulation for any number of steps (ok, up to 2^63 steps). </P> <P><B>Related commands:</B> </P> <P><A HREF = "minimize.html">minimize</A>, <A HREF = "run_style.html">run_style</A>, <A HREF = "temper.html">temper</A> </P> <P><B>Default:</B> </P> <P>The option defaults are start = the current timestep, stop = current timestep + N, pre = yes, and post = yes. </P> </HTML> diff --git a/doc/run.txt b/doc/run.txt index 7561559c2..febf22777 100644 --- a/doc/run.txt +++ b/doc/run.txt @@ -1,180 +1,185 @@ "LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c :link(lws,http://lammps.sandia.gov) :link(ld,Manual.html) :link(lc,Section_commands.html#comm) :line run command :h3 [Syntax:] run N keyword values ... :pre N = # of timesteps :ulb,l zero or more keyword/value pairs may be appended :l keyword = {upto} or {start} or {stop} or {pre} or {post} or {every} :l {upto} value = none {start} value = N1 N1 = timestep at which 1st run started {stop} value = N2 N2 = timestep at which last run will end {pre} value = {no} or {yes} {post} value = {no} or {yes} {every} values = M c1 c2 ... M = break the run into M-timestep segments and invoke one or more commands between each segment c1,c2,...,cN = one or more LAMMPS commands, each enclosed in quotes c1 = NULL means no command will be invoked :pre :ule [Examples:] run 10000 run 1000000 upto run 100 start 0 stop 1000 run 1000 pre no post yes run 100000 start 0 stop 1000000 every 1000 "print 'Protein Rg = $r'" run 100000 every 1000 NULL :pre [Description:] Run or continue dynamics for a specified number of timesteps. When the "run style"_run_style.html is {respa}, N refers to outer loop (largest) timesteps. A value of N = 0 is acceptable; only the thermodynamics of the system are computed and printed without taking a timestep. The {upto} keyword means to perform a run starting at the current timestep up to the specified timestep. E.g. if the current timestep is 10,000 and "run 100000 upto" is used, then an additional 90,000 timesteps will be run. This can be useful for very long runs on a machine that allocates chunks of time and terminate your job when time is exceeded. If you need to restart your script multiple times (reading in the last restart file), you can keep restarting your script with the same run command until the simulation finally completes. The {start} or {stop} keywords can be used if multiple runs are being performed and you want a "fix"_fix.html command that changes some value over time (e.g. temperature) to make the change across the entire set of runs and not just a single run. See the doc page for individual fixes to see which ones can be used with the {start/stop} keywords. For example, consider this fix followed by 10 run commands: fix 1 all nvt 200.0 300.0 1.0 run 1000 start 0 stop 10000 run 1000 start 0 stop 10000 ... run 1000 start 0 stop 10000 :pre The NVT fix ramps the target temperature from 200.0 to 300.0 during a run. If the run commands did not have the start/stop keywords (just "run 1000"), then the temperature would ramp from 200.0 to 300.0 during the 1000 steps of each run. With the start/stop keywords, the ramping takes place over the 10000 steps of all runs together. The {pre} and {post} keywords can be used to streamline the setup, clean-up, and associated output to the screen that happens before and after a run. This can be useful if you wish to do many short runs in succession (e.g. LAMMPS is being called as a library which is doing other computations between successive short LAMMPS runs). By default (pre and post = yes), LAMMPS creates neighbor lists, computes forces, and imposes fix constraints before every run. And after every run it gathers and prints timings statistics. If a run is just a continuation of a previous run (i.e. no settings are changed), the initial computation is not necessary; the old neighbor list is still valid as are the forces. So if {pre} is specified as "no" then the initial setup is skipped, except for printing thermodynamic info. Note that if {pre} is set to "no" for the very 1st run LAMMPS performs, then it is overridden, since the initial setup computations must be done. IMPORTANT NOTE: If your input script changes settings between 2 runs (e.g. adds a "fix"_fix.html or "dump"_dump.html or "compute"_compute.html or changes a "neighbor"_neigh_modify.html list parameter), then the initial setup must be performed. LAMMPS does not check for this, but it would be an error to use the {pre no} option in this case. If {post} is specified as "no", the full timing summary is skipped; only a one-line summary timing is printed. The {every} keyword provides a means of breaking a LAMMPS run into a series of shorter runs. Optionally, one or more LAMMPS commands (c1, c2, ..., cN) will be executed in between the short runs. If used, the {every} keyword must be the last keyword, since it has a variable number of arguments. Each of the trailing arguments is a single LAMMPS command, and each command should be enclosed in quotes, so that the entire command will be treated as a single argument. This will also prevent any variables in the command from being evaluated until it is executed multiple times during the run. Note that if a command itself needs one of its arguments quoted (e.g. the "print"_print.html command), then you can use a combination of single and double quotes, as in the example above or below. The {every} keyword is a means to avoid listing a long series of runs and interleaving commands in your input script. For example, a "print"_print.html command could be invoked or a "fix"_fix.html could be redefined, e.g. to reset a thermostat temperature. Or this could be useful for invoking a command you have added to LAMMPS that wraps some other code (e.g. as a library) to perform a computation periodically during a long LAMMPS run. See "this section"_Section_modify.html of the documentation for info about how to add new commands to LAMMPS. See "this section"_Section_howto.html#4_10 of the documentation for ideas about how to couple LAMMPS to other codes. With the {every} option, N total steps are simulated, in shorter runs of M steps each. After each M-length run, the specified commands are invoked. If only a single command is specified as NULL, then no command is invoked. Thus these lines: variable q equal x\[100\] run 6000 every 2000 "print Coord = $q" :pre are the equivalent of: variable q equal x\[100\] run 2000 print Coord = $q run 2000 print Coord = $q run 2000 print Coord = $q :pre which does 3 runs of 2000 steps and prints the x-coordinate of a particular atom between runs. Note that the variable "$q" will be evaluated afresh each time the print command is executed. Note that by using the line continuation character "&", the run every command can be spread across many lines, though it is still a single command: run 100000 every 1000 & "print 'Minimum value = $a'" & "print 'Maximum value = $b'" & "print 'Temp = $c'" & "print 'Press = $d'" :pre If the {pre} and {post} options are set to "no" when used with the {every} keyword, then the 1st run will do the full setup and the last run will print the full timing summary, but these operations will be skipped for intermediate runs. -[Restrictions:] none +[Restrictions:] + +The number of specified timesteps N must fit in a signed 32-bit +integer, so you are limited to slightly more than 2 billion steps +(2^31) in a single run. However, you can perform successive runs to +run a simulation for any number of steps (ok, up to 2^63 steps). [Related commands:] "minimize"_minimize.html, "run_style"_run_style.html, "temper"_temper.html [Default:] The option defaults are start = the current timestep, stop = current timestep + N, pre = yes, and post = yes. diff --git a/src/ASPHERE/atom_vec_ellipsoid.cpp b/src/ASPHERE/atom_vec_ellipsoid.cpp index ddf95831a..e48e7ae30 100755 --- a/src/ASPHERE/atom_vec_ellipsoid.cpp +++ b/src/ASPHERE/atom_vec_ellipsoid.cpp @@ -1,847 +1,850 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- Contributing author: Mike Brown (SNL) ------------------------------------------------------------------------- */ #include "stdlib.h" #include "atom_vec_ellipsoid.h" +#include "lmptype.h" #include "math_extra.h" #include "atom.h" #include "force.h" #include "domain.h" #include "modify.h" #include "fix.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; #define DELTA 10000 /* ---------------------------------------------------------------------- */ AtomVecEllipsoid::AtomVecEllipsoid(LAMMPS *lmp, int narg, char **arg) : AtomVec(lmp, narg, arg) { molecular = 0; mass_type = 1; shape_type = 1; comm_x_only = comm_f_only = 0; size_forward = 7; size_reverse = 6; size_border = 10; size_velocity = 6; size_data_atom = 9; size_data_vel = 7; xcol_data = 3; atom->angmom_flag = atom->torque_flag = atom->quat_flag = 1; } /* ---------------------------------------------------------------------- grow atom arrays n = 0 grows arrays by DELTA n > 0 allocates arrays to size n ------------------------------------------------------------------------- */ void AtomVecEllipsoid::grow(int n) { if (n == 0) nmax += DELTA; else nmax = n; atom->nmax = nmax; + if (nmax < 0 || nmax > MAXSMALLINT) + error->one("Per-processor system is too big"); tag = atom->tag = (int *) memory->srealloc(atom->tag,nmax*sizeof(int),"atom:tag"); type = atom->type = (int *) memory->srealloc(atom->type,nmax*sizeof(int),"atom:type"); mask = atom->mask = (int *) memory->srealloc(atom->mask,nmax*sizeof(int),"atom:mask"); image = atom->image = (int *) memory->srealloc(atom->image,nmax*sizeof(int),"atom:image"); x = atom->x = memory->grow_2d_double_array(atom->x,nmax,3,"atom:x"); v = atom->v = memory->grow_2d_double_array(atom->v,nmax,3,"atom:v"); f = atom->f = memory->grow_2d_double_array(atom->f,nmax,3,"atom:f"); quat = atom->quat = memory->grow_2d_double_array(atom->quat,nmax,4,"atom:quat"); angmom = atom->angmom = memory->grow_2d_double_array(atom->angmom,nmax,3,"atom:angmom"); torque = atom->torque = memory->grow_2d_double_array(atom->torque,nmax,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 AtomVecEllipsoid::grow_reset() { tag = atom->tag; type = atom->type; mask = atom->mask; image = atom->image; x = atom->x; v = atom->v; f = atom->f; quat = atom->quat; angmom = atom->angmom; torque = atom->torque; } /* ---------------------------------------------------------------------- */ void AtomVecEllipsoid::copy(int i, int j) { 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]; quat[j][0] = quat[i][0]; quat[j][1] = quat[i][1]; quat[j][2] = quat[i][2]; quat[j][3] = quat[i][3]; angmom[j][0] = angmom[i][0]; angmom[j][1] = angmom[i][1]; angmom[j][2] = angmom[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); } /* ---------------------------------------------------------------------- */ int AtomVecEllipsoid::pack_comm(int n, int *list, double *buf, int pbc_flag, int *pbc) { int i,j,m; double dx,dy,dz; m = 0; if (pbc_flag == 0) { for (i = 0; i < n; i++) { j = list[i]; buf[m++] = x[j][0]; buf[m++] = x[j][1]; buf[m++] = x[j][2]; buf[m++] = quat[j][0]; buf[m++] = quat[j][1]; buf[m++] = quat[j][2]; buf[m++] = quat[j][3]; } } else { if (domain->triclinic == 0) { dx = pbc[0]*domain->xprd; dy = pbc[1]*domain->yprd; dz = pbc[2]*domain->zprd; } else { dx = pbc[0]*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++] = quat[j][0]; buf[m++] = quat[j][1]; buf[m++] = quat[j][2]; buf[m++] = quat[j][3]; } } return m; } /* ---------------------------------------------------------------------- */ int AtomVecEllipsoid::pack_comm_vel(int n, int *list, double *buf, int pbc_flag, int *pbc) { int i,j,m; double dx,dy,dz; 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++] = quat[j][0]; buf[m++] = quat[j][1]; buf[m++] = quat[j][2]; buf[m++] = quat[j][3]; buf[m++] = v[j][0]; buf[m++] = v[j][1]; buf[m++] = v[j][2]; buf[m++] = angmom[j][0]; buf[m++] = angmom[j][1]; buf[m++] = angmom[j][2]; } } else { if (domain->triclinic == 0) { dx = pbc[0]*domain->xprd; dy = pbc[1]*domain->yprd; dz = pbc[2]*domain->zprd; } else { dx = pbc[0]*domain->xprd + pbc[5]*domain->xy + pbc[4]*domain->xz; dy = pbc[1]*domain->yprd + pbc[3]*domain->yz; dz = pbc[2]*domain->zprd; } 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++] = quat[j][0]; buf[m++] = quat[j][1]; buf[m++] = quat[j][2]; buf[m++] = quat[j][3]; buf[m++] = v[j][0]; buf[m++] = v[j][1]; buf[m++] = v[j][2]; buf[m++] = angmom[j][0]; buf[m++] = angmom[j][1]; buf[m++] = angmom[j][2]; } } return m; } /* ---------------------------------------------------------------------- */ int AtomVecEllipsoid::pack_comm_one(int i, double *buf) { buf[0] = quat[i][0]; buf[1] = quat[i][1]; buf[2] = quat[i][2]; buf[3] = quat[i][3]; return 4; } /* ---------------------------------------------------------------------- */ void AtomVecEllipsoid::unpack_comm(int n, int first, double *buf) { int i,m,last; m = 0; last = first + n; for (i = first; i < last; i++) { x[i][0] = buf[m++]; x[i][1] = buf[m++]; x[i][2] = buf[m++]; quat[i][0] = buf[m++]; quat[i][1] = buf[m++]; quat[i][2] = buf[m++]; quat[i][3] = buf[m++]; } } /* ---------------------------------------------------------------------- */ void AtomVecEllipsoid::unpack_comm_vel(int n, int first, double *buf) { int i,m,last; m = 0; last = first + n; for (i = first; i < last; i++) { x[i][0] = buf[m++]; x[i][1] = buf[m++]; x[i][2] = buf[m++]; quat[i][0] = buf[m++]; quat[i][1] = buf[m++]; quat[i][2] = buf[m++]; quat[i][3] = buf[m++]; v[i][0] = buf[m++]; v[i][1] = buf[m++]; v[i][2] = buf[m++]; angmom[i][0] = buf[m++]; angmom[i][1] = buf[m++]; angmom[i][2] = buf[m++]; } } /* ---------------------------------------------------------------------- */ int AtomVecEllipsoid::unpack_comm_one(int i, double *buf) { quat[i][0] = buf[0]; quat[i][1] = buf[1]; quat[i][2] = buf[2]; quat[i][3] = buf[3]; return 4; } /* ---------------------------------------------------------------------- */ int AtomVecEllipsoid::pack_reverse(int n, int first, double *buf) { int i,m,last; m = 0; last = first + n; for (i = first; i < last; i++) { buf[m++] = f[i][0]; buf[m++] = f[i][1]; buf[m++] = f[i][2]; buf[m++] = torque[i][0]; buf[m++] = torque[i][1]; buf[m++] = torque[i][2]; } return m; } /* ---------------------------------------------------------------------- */ int AtomVecEllipsoid::pack_reverse_one(int i, double *buf) { buf[0] = torque[i][0]; buf[1] = torque[i][1]; buf[2] = torque[i][2]; return 3; } /* ---------------------------------------------------------------------- */ void AtomVecEllipsoid::unpack_reverse(int n, int *list, double *buf) { int i,j,m; m = 0; for (i = 0; i < n; i++) { j = list[i]; f[j][0] += buf[m++]; f[j][1] += buf[m++]; f[j][2] += buf[m++]; torque[j][0] += buf[m++]; torque[j][1] += buf[m++]; torque[j][2] += buf[m++]; } } /* ---------------------------------------------------------------------- */ int AtomVecEllipsoid::unpack_reverse_one(int i, double *buf) { torque[i][0] += buf[0]; torque[i][1] += buf[1]; torque[i][2] += buf[2]; return 3; } /* ---------------------------------------------------------------------- */ int AtomVecEllipsoid::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++] = quat[j][0]; buf[m++] = quat[j][1]; buf[m++] = quat[j][2]; buf[m++] = quat[j][3]; } } else { if (domain->triclinic == 0) { dx = pbc[0]*domain->xprd; dy = pbc[1]*domain->yprd; dz = pbc[2]*domain->zprd; } else { dx = pbc[0]; dy = pbc[1]; dz = pbc[2]; } for (i = 0; i < n; i++) { j = list[i]; buf[m++] = x[j][0] + dx; buf[m++] = x[j][1] + dy; buf[m++] = x[j][2] + dz; buf[m++] = tag[j]; buf[m++] = type[j]; buf[m++] = mask[j]; buf[m++] = quat[j][0]; buf[m++] = quat[j][1]; buf[m++] = quat[j][2]; buf[m++] = quat[j][3]; } } return m; } /* ---------------------------------------------------------------------- */ int AtomVecEllipsoid::pack_border_vel(int n, int *list, double *buf, int pbc_flag, int *pbc) { int i,j,m; double dx,dy,dz; 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++] = quat[j][0]; buf[m++] = quat[j][1]; buf[m++] = quat[j][2]; buf[m++] = quat[j][3]; buf[m++] = v[j][0]; buf[m++] = v[j][1]; buf[m++] = v[j][2]; buf[m++] = angmom[j][0]; buf[m++] = angmom[j][1]; buf[m++] = angmom[j][2]; } } else { if (domain->triclinic == 0) { dx = pbc[0]*domain->xprd; dy = pbc[1]*domain->yprd; dz = pbc[2]*domain->zprd; } else { dx = pbc[0]; dy = pbc[1]; dz = pbc[2]; } 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++] = quat[j][0]; buf[m++] = quat[j][1]; buf[m++] = quat[j][2]; buf[m++] = quat[j][3]; buf[m++] = v[j][0]; buf[m++] = v[j][1]; buf[m++] = v[j][2]; buf[m++] = angmom[j][0]; buf[m++] = angmom[j][1]; buf[m++] = angmom[j][2]; } } return m; } /* ---------------------------------------------------------------------- */ int AtomVecEllipsoid::pack_border_one(int i, double *buf) { buf[0] = quat[i][0]; buf[1] = quat[i][1]; buf[2] = quat[i][2]; buf[3] = quat[i][3]; return 4; } /* ---------------------------------------------------------------------- */ void AtomVecEllipsoid::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++]); quat[i][0] = buf[m++]; quat[i][1] = buf[m++]; quat[i][2] = buf[m++]; quat[i][3] = buf[m++]; } } /* ---------------------------------------------------------------------- */ void AtomVecEllipsoid::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++]); quat[i][0] = buf[m++]; quat[i][1] = buf[m++]; quat[i][2] = buf[m++]; quat[i][3] = buf[m++]; v[i][0] = buf[m++]; v[i][1] = buf[m++]; v[i][2] = buf[m++]; angmom[i][0] = buf[m++]; angmom[i][1] = buf[m++]; angmom[i][2] = buf[m++]; } } /* ---------------------------------------------------------------------- */ int AtomVecEllipsoid::unpack_border_one(int i, double *buf) { quat[i][0] = buf[0]; quat[i][1] = buf[1]; quat[i][2] = buf[2]; quat[i][3] = buf[3]; return 4; } /* ---------------------------------------------------------------------- pack data for atom I for sending to another proc xyz must be 1st 3 values, so comm::exchange() can test on them ------------------------------------------------------------------------- */ int AtomVecEllipsoid::pack_exchange(int i, double *buf) { int m = 1; buf[m++] = x[i][0]; buf[m++] = x[i][1]; buf[m++] = x[i][2]; buf[m++] = v[i][0]; buf[m++] = v[i][1]; buf[m++] = v[i][2]; buf[m++] = tag[i]; buf[m++] = type[i]; buf[m++] = mask[i]; buf[m++] = image[i]; buf[m++] = quat[i][0]; buf[m++] = quat[i][1]; buf[m++] = quat[i][2]; buf[m++] = quat[i][3]; buf[m++] = angmom[i][0]; buf[m++] = angmom[i][1]; buf[m++] = angmom[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 AtomVecEllipsoid::unpack_exchange(double *buf) { int nlocal = atom->nlocal; if (nlocal == nmax) grow(0); int m = 1; x[nlocal][0] = buf[m++]; x[nlocal][1] = buf[m++]; x[nlocal][2] = buf[m++]; v[nlocal][0] = buf[m++]; v[nlocal][1] = buf[m++]; v[nlocal][2] = buf[m++]; tag[nlocal] = static_cast<int> (buf[m++]); type[nlocal] = static_cast<int> (buf[m++]); mask[nlocal] = static_cast<int> (buf[m++]); image[nlocal] = static_cast<int> (buf[m++]); quat[nlocal][0] = buf[m++]; quat[nlocal][1] = buf[m++]; quat[nlocal][2] = buf[m++]; quat[nlocal][3] = buf[m++]; angmom[nlocal][0] = buf[m++]; angmom[nlocal][1] = buf[m++]; angmom[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 AtomVecEllipsoid::size_restart() { int i; int nlocal = atom->nlocal; int n = 18 * 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 AtomVecEllipsoid::pack_restart(int i, double *buf) { int m = 1; buf[m++] = x[i][0]; buf[m++] = x[i][1]; buf[m++] = x[i][2]; buf[m++] = tag[i]; buf[m++] = type[i]; buf[m++] = mask[i]; buf[m++] = image[i]; buf[m++] = v[i][0]; buf[m++] = v[i][1]; buf[m++] = v[i][2]; buf[m++] = quat[i][0]; buf[m++] = quat[i][1]; buf[m++] = quat[i][2]; buf[m++] = quat[i][3]; buf[m++] = angmom[i][0]; buf[m++] = angmom[i][1]; buf[m++] = angmom[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 AtomVecEllipsoid::unpack_restart(double *buf) { int nlocal = atom->nlocal; if (nlocal == nmax) { grow(0); if (atom->nextra_store) atom->extra = memory->grow_2d_double_array(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] = static_cast<int> (buf[m++]); v[nlocal][0] = buf[m++]; v[nlocal][1] = buf[m++]; v[nlocal][2] = buf[m++]; quat[nlocal][0] = buf[m++]; quat[nlocal][1] = buf[m++]; quat[nlocal][2] = buf[m++]; quat[nlocal][3] = buf[m++]; angmom[nlocal][0] = buf[m++]; angmom[nlocal][1] = buf[m++]; angmom[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 AtomVecEllipsoid::create_atom(int itype, double *coord) { int nlocal = atom->nlocal; if (nlocal == nmax) grow(0); tag[nlocal] = 0; type[nlocal] = itype; x[nlocal][0] = coord[0]; x[nlocal][1] = coord[1]; x[nlocal][2] = coord[2]; mask[nlocal] = 1; image[nlocal] = (512 << 20) | (512 << 10) | 512; v[nlocal][0] = 0.0; v[nlocal][1] = 0.0; v[nlocal][2] = 0.0; quat[nlocal][0] = 1.0; quat[nlocal][1] = 0.0; quat[nlocal][2] = 0.0; quat[nlocal][3] = 0.0; angmom[nlocal][0] = 0.0; angmom[nlocal][1] = 0.0; angmom[nlocal][2] = 0.0; atom->nlocal++; } /* ---------------------------------------------------------------------- unpack one line from Atoms section of data file initialize other atom quantities ------------------------------------------------------------------------- */ void AtomVecEllipsoid::data_atom(double *coord, int imagetmp, char **values) { int nlocal = atom->nlocal; if (nlocal == nmax) grow(0); tag[nlocal] = atoi(values[0]); if (tag[nlocal] <= 0) error->one("Invalid atom ID in Atoms section of data file"); type[nlocal] = atoi(values[1]); if (type[nlocal] <= 0 || type[nlocal] > atom->ntypes) error->one("Invalid atom type in Atoms section of data file"); x[nlocal][0] = coord[0]; x[nlocal][1] = coord[1]; x[nlocal][2] = coord[2]; quat[nlocal][0] = atof(values[5]); quat[nlocal][1] = atof(values[6]); quat[nlocal][2] = atof(values[7]); quat[nlocal][3] = atof(values[8]); MathExtra::normalize4(quat[nlocal]); image[nlocal] = imagetmp; mask[nlocal] = 1; v[nlocal][0] = 0.0; v[nlocal][1] = 0.0; v[nlocal][2] = 0.0; angmom[nlocal][0] = 0.0; angmom[nlocal][1] = 0.0; angmom[nlocal][2] = 0.0; atom->nlocal++; } /* ---------------------------------------------------------------------- unpack hybrid quantities from one line in Atoms section of data file initialize other atom quantities for this sub-style ------------------------------------------------------------------------- */ int AtomVecEllipsoid::data_atom_hybrid(int nlocal, char **values) { quat[nlocal][0] = atof(values[0]); quat[nlocal][1] = atof(values[1]); quat[nlocal][2] = atof(values[2]); quat[nlocal][3] = atof(values[3]); MathExtra::normalize4(quat[nlocal]); return 4; } /* ---------------------------------------------------------------------- unpack one line from Velocities section of data file ------------------------------------------------------------------------- */ void AtomVecEllipsoid::data_vel(int m, char **values) { v[m][0] = atof(values[0]); v[m][1] = atof(values[1]); v[m][2] = atof(values[2]); angmom[m][0] = atof(values[3]); angmom[m][1] = atof(values[4]); angmom[m][2] = atof(values[5]); } /* ---------------------------------------------------------------------- unpack hybrid quantities from one line in Velocities section of data file ------------------------------------------------------------------------- */ int AtomVecEllipsoid::data_vel_hybrid(int m, char **values) { angmom[m][0] = atof(values[0]); angmom[m][1] = atof(values[1]); angmom[m][2] = atof(values[2]); return 3; } /* ---------------------------------------------------------------------- return # of bytes of allocated memory ------------------------------------------------------------------------- */ double AtomVecEllipsoid::memory_usage() { double bytes = 0.0; if (atom->memcheck("tag")) bytes += nmax * sizeof(int); if (atom->memcheck("type")) bytes += nmax * sizeof(int); if (atom->memcheck("mask")) bytes += nmax * sizeof(int); if (atom->memcheck("image")) bytes += nmax * sizeof(int); if (atom->memcheck("x")) bytes += nmax*3 * sizeof(double); if (atom->memcheck("v")) bytes += nmax*3 * sizeof(double); if (atom->memcheck("f")) bytes += nmax*3 * sizeof(double); if (atom->memcheck("quat")) bytes += nmax*4 * sizeof(double); if (atom->memcheck("angmom")) bytes += nmax*3 * sizeof(double); if (atom->memcheck("torque")) bytes += nmax*3 * sizeof(double); return bytes; } diff --git a/src/CLASS2/dihedral_class2.cpp b/src/CLASS2/dihedral_class2.cpp index e4a42b18f..bf29f6457 100644 --- a/src/CLASS2/dihedral_class2.cpp +++ b/src/CLASS2/dihedral_class2.cpp @@ -1,937 +1,938 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- Contributing author: Eric Simon (Cray) ------------------------------------------------------------------------- */ #include "math.h" #include "string.h" #include "stdlib.h" #include "dihedral_class2.h" +#include "lmptype.h" #include "atom.h" #include "neighbor.h" #include "update.h" #include "domain.h" #include "comm.h" #include "force.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; #define MIN(A,B) ((A) < (B)) ? (A) : (B) #define MAX(A,B) ((A) > (B)) ? (A) : (B) #define TOLERANCE 0.05 #define SMALL 0.0000001 /* ---------------------------------------------------------------------- */ DihedralClass2::DihedralClass2(LAMMPS *lmp) : Dihedral(lmp) { PI = 4.0*atan(1.0); } /* ---------------------------------------------------------------------- */ DihedralClass2::~DihedralClass2() { if (allocated) { memory->sfree(setflag); memory->sfree(setflag_d); memory->sfree(setflag_mbt); memory->sfree(setflag_ebt); memory->sfree(setflag_at); memory->sfree(setflag_aat); memory->sfree(setflag_bb13t); memory->sfree(k1); memory->sfree(k2); memory->sfree(k3); memory->sfree(phi1); memory->sfree(phi2); memory->sfree(phi3); memory->sfree(mbt_f1); memory->sfree(mbt_f2); memory->sfree(mbt_f3); memory->sfree(mbt_r0); memory->sfree(ebt_f1_1); memory->sfree(ebt_f2_1); memory->sfree(ebt_f3_1); memory->sfree(ebt_r0_1); memory->sfree(ebt_f1_2); memory->sfree(ebt_f2_2); memory->sfree(ebt_f3_2); memory->sfree(ebt_r0_2); memory->sfree(at_f1_1); memory->sfree(at_f2_1); memory->sfree(at_f3_1); memory->sfree(at_theta0_1); memory->sfree(at_f1_2); memory->sfree(at_f2_2); memory->sfree(at_f3_2); memory->sfree(at_theta0_2); memory->sfree(aat_k); memory->sfree(aat_theta0_1); memory->sfree(aat_theta0_2); memory->sfree(bb13t_k); memory->sfree(bb13t_r10); memory->sfree(bb13t_r30); } } /* ---------------------------------------------------------------------- */ void DihedralClass2::compute(int eflag, int vflag) { int i1,i2,i3,i4,i,j,k,n,type; double vb1x,vb1y,vb1z,vb2x,vb2y,vb2z,vb3x,vb3y,vb3z,vb2xm,vb2ym,vb2zm; double edihedral; double r1mag2,r1,r2mag2,r2,r3mag2,r3; double sb1,rb1,sb2,rb2,sb3,rb3,c0,r12c1; double r12c2,costh12,costh13,costh23,sc1,sc2,s1,s2,c; double cosphi,phi,sinphi,a11,a22,a33,a12,a13,a23,sx1,sx2; double sx12,sy1,sy2,sy12,sz1,sz2,sz12,dphi1,dphi2,dphi3; double de_dihedral,t1,t2,t3,t4,cos2phi,cos3phi,bt1,bt2; double bt3,sumbte,db,sumbtf,at1,at2,at3,da,da1,da2,r1_0; double r3_0,dr1,dr2,tk1,tk2,s12,sin2; double dcosphidr[4][3],dphidr[4][3],dbonddr[3][4][3],dthetadr[2][4][3]; double fabcd[4][3]; edihedral = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = 0; double **x = atom->x; double **f = atom->f; int **dihedrallist = neighbor->dihedrallist; int ndihedrallist = neighbor->ndihedrallist; int nlocal = atom->nlocal; int newton_bond = force->newton_bond; for (n = 0; n < ndihedrallist; n++) { i1 = dihedrallist[n][0]; i2 = dihedrallist[n][1]; i3 = dihedrallist[n][2]; i4 = dihedrallist[n][3]; type = dihedrallist[n][4]; // 1st bond vb1x = x[i1][0] - x[i2][0]; vb1y = x[i1][1] - x[i2][1]; vb1z = x[i1][2] - x[i2][2]; domain->minimum_image(vb1x,vb1y,vb1z); // 2nd bond vb2x = x[i3][0] - x[i2][0]; vb2y = x[i3][1] - x[i2][1]; vb2z = x[i3][2] - x[i2][2]; domain->minimum_image(vb2x,vb2y,vb2z); vb2xm = -vb2x; vb2ym = -vb2y; vb2zm = -vb2z; domain->minimum_image(vb2xm,vb2ym,vb2zm); // 3rd bond vb3x = x[i4][0] - x[i3][0]; vb3y = x[i4][1] - x[i3][1]; vb3z = x[i4][2] - x[i3][2]; domain->minimum_image(vb3x,vb3y,vb3z); // distances r1mag2 = vb1x*vb1x + vb1y*vb1y + vb1z*vb1z; r1 = sqrt(r1mag2); r2mag2 = vb2x*vb2x + vb2y*vb2y + vb2z*vb2z; r2 = sqrt(r2mag2); r3mag2 = vb3x*vb3x + vb3y*vb3y + vb3z*vb3z; r3 = sqrt(r3mag2); sb1 = 1.0/r1mag2; rb1 = 1.0/r1; sb2 = 1.0/r2mag2; rb2 = 1.0/r2; sb3 = 1.0/r3mag2; rb3 = 1.0/r3; c0 = (vb1x*vb3x + vb1y*vb3y + vb1z*vb3z) * rb1*rb3; // angles r12c1 = rb1*rb2; r12c2 = rb2*rb3; costh12 = (vb1x*vb2x + vb1y*vb2y + vb1z*vb2z) * r12c1; costh13 = c0; costh23 = (vb2xm*vb3x + vb2ym*vb3y + vb2zm*vb3z) * r12c2; // cos and sin of 2 angles and final c sin2 = MAX(1.0 - costh12*costh12,0.0); sc1 = sqrt(sin2); if (sc1 < SMALL) sc1 = SMALL; sc1 = 1.0/sc1; sin2 = MAX(1.0 - costh23*costh23,0.0); sc2 = sqrt(sin2); if (sc2 < SMALL) sc2 = SMALL; sc2 = 1.0/sc2; s1 = sc1 * sc1; s2 = sc2 * sc2; s12 = sc1 * sc2; c = (c0 + costh12*costh23) * s12; // error check if (c > 1.0 + TOLERANCE || c < (-1.0 - TOLERANCE)) { int me; MPI_Comm_rank(world,&me); if (screen) { - char str[128]; - sprintf(str,"Dihedral problem: %d %d %d %d %d %d", - me,update->ntimestep, + char str[128],fstr[64]; + sprintf(fstr,"Dihedral problem: %%d %s %%d %%d %%d %%d",BIGINT_FORMAT); + sprintf(str,fstr,me,update->ntimestep, atom->tag[i1],atom->tag[i2],atom->tag[i3],atom->tag[i4]); error->warning(str,0); fprintf(screen," 1st atom: %d %g %g %g\n", me,x[i1][0],x[i1][1],x[i1][2]); fprintf(screen," 2nd atom: %d %g %g %g\n", me,x[i2][0],x[i2][1],x[i2][2]); fprintf(screen," 3rd atom: %d %g %g %g\n", me,x[i3][0],x[i3][1],x[i3][2]); fprintf(screen," 4th atom: %d %g %g %g\n", me,x[i4][0],x[i4][1],x[i4][2]); } } if (c > 1.0) c = 1.0; if (c < -1.0) c = -1.0; cosphi = c; phi = acos(c); sinphi = sqrt(1.0 - c*c); sinphi = MAX(sinphi,SMALL); a11 = -c*sb1*s1; a22 = sb2 * (2.0*costh13*s12 - c*(s1+s2)); a33 = -c*sb3*s2; a12 = r12c1 * (costh12*c*s1 + costh23*s12); a13 = rb1*rb3*s12; a23 = r12c2 * (-costh23*c*s2 - costh12*s12); sx1 = a11*vb1x + a12*vb2x + a13*vb3x; sx2 = a12*vb1x + a22*vb2x + a23*vb3x; sx12 = a13*vb1x + a23*vb2x + a33*vb3x; sy1 = a11*vb1y + a12*vb2y + a13*vb3y; sy2 = a12*vb1y + a22*vb2y + a23*vb3y; sy12 = a13*vb1y + a23*vb2y + a33*vb3y; sz1 = a11*vb1z + a12*vb2z + a13*vb3z; sz2 = a12*vb1z + a22*vb2z + a23*vb3z; sz12 = a13*vb1z + a23*vb2z + a33*vb3z; // set up d(cos(phi))/d(r) and dphi/dr arrays dcosphidr[0][0] = -sx1; dcosphidr[0][1] = -sy1; dcosphidr[0][2] = -sz1; dcosphidr[1][0] = sx2 + sx1; dcosphidr[1][1] = sy2 + sy1; dcosphidr[1][2] = sz2 + sz1; dcosphidr[2][0] = sx12 - sx2; dcosphidr[2][1] = sy12 - sy2; dcosphidr[2][2] = sz12 - sz2; dcosphidr[3][0] = -sx12; dcosphidr[3][1] = -sy12; dcosphidr[3][2] = -sz12; for (i = 0; i < 4; i++) for (j = 0; j < 3; j++) dphidr[i][j] = -dcosphidr[i][j] / sinphi; // energy dphi1 = phi - phi1[type]; dphi2 = 2.0*phi - phi2[type]; dphi3 = 3.0*phi - phi3[type]; if (eflag) edihedral = k1[type]*(1.0 - cos(dphi1)) + k2[type]*(1.0 - cos(dphi2)) + k3[type]*(1.0 - cos(dphi3)); de_dihedral = k1[type]*sin(dphi1) + 2.0*k2[type]*sin(dphi2) + 3.0*k3[type]*sin(dphi3); // torsion forces on all 4 atoms for (i = 0; i < 4; i++) for (j = 0; j < 3; j++) fabcd[i][j] = de_dihedral*dphidr[i][j]; // set up d(bond)/d(r) array // dbonddr(i,j,k) = bond i, atom j, coordinate k for (i = 0; i < 3; i++) for (j = 0; j < 4; j++) for (k = 0; k < 3; k++) dbonddr[i][j][k] = 0.0; // bond1 dbonddr[0][0][0] = vb1x / r1; dbonddr[0][0][1] = vb1y / r1; dbonddr[0][0][2] = vb1z / r1; dbonddr[0][1][0] = -vb1x / r1; dbonddr[0][1][1] = -vb1y / r1; dbonddr[0][1][2] = -vb1z / r1; // bond2 dbonddr[1][1][0] = vb2x / r2; dbonddr[1][1][1] = vb2y / r2; dbonddr[1][1][2] = vb2z / r2; dbonddr[1][2][0] = -vb2x / r2; dbonddr[1][2][1] = -vb2y / r2; dbonddr[1][2][2] = -vb2z / r2; // bond3 dbonddr[2][2][0] = vb3x / r3; dbonddr[2][2][1] = vb3y / r3; dbonddr[2][2][2] = vb3z / r3; dbonddr[2][3][0] = -vb3x / r3; dbonddr[2][3][1] = -vb3y / r3; dbonddr[2][3][2] = -vb3z / r3; // set up d(theta)/d(r) array // dthetadr(i,j,k) = angle i, atom j, coordinate k for (i = 0; i < 2; i++) for (j = 0; j < 4; j++) for (k = 0; k < 3; k++) dthetadr[i][j][k] = 0.0; t1 = costh12 / r1mag2; t2 = costh23 / r2mag2; t3 = costh12 / r2mag2; t4 = costh23 / r3mag2; // angle12 dthetadr[0][0][0] = sc1 * ((t1 * vb1x) - (vb2x * r12c1)); dthetadr[0][0][1] = sc1 * ((t1 * vb1y) - (vb2y * r12c1)); dthetadr[0][0][2] = sc1 * ((t1 * vb1z) - (vb2z * r12c1)); dthetadr[0][1][0] = sc1 * ((-t1 * vb1x) + (vb2x * r12c1) + (-t3 * vb2x) + (vb1x * r12c1)); dthetadr[0][1][1] = sc1 * ((-t1 * vb1y) + (vb2y * r12c1) + (-t3 * vb2y) + (vb1y * r12c1)); dthetadr[0][1][2] = sc1 * ((-t1 * vb1z) + (vb2z * r12c1) + (-t3 * vb2z) + (vb1z * r12c1)); dthetadr[0][2][0] = sc1 * ((t3 * vb2x) - (vb1x * r12c1)); dthetadr[0][2][1] = sc1 * ((t3 * vb2y) - (vb1y * r12c1)); dthetadr[0][2][2] = sc1 * ((t3 * vb2z) - (vb1z * r12c1)); // angle23 dthetadr[1][1][0] = sc2 * ((t2 * vb2x) + (vb3x * r12c2)); dthetadr[1][1][1] = sc2 * ((t2 * vb2y) + (vb3y * r12c2)); dthetadr[1][1][2] = sc2 * ((t2 * vb2z) + (vb3z * r12c2)); dthetadr[1][2][0] = sc2 * ((-t2 * vb2x) - (vb3x * r12c2) + (t4 * vb3x) + (vb2x * r12c2)); dthetadr[1][2][1] = sc2 * ((-t2 * vb2y) - (vb3y * r12c2) + (t4 * vb3y) + (vb2y * r12c2)); dthetadr[1][2][2] = sc2 * ((-t2 * vb2z) - (vb3z * r12c2) + (t4 * vb3z) + (vb2z * r12c2)); dthetadr[1][3][0] = -sc2 * ((t4 * vb3x) + (vb2x * r12c2)); dthetadr[1][3][1] = -sc2 * ((t4 * vb3y) + (vb2y * r12c2)); dthetadr[1][3][2] = -sc2 * ((t4 * vb3z) + (vb2z * r12c2)); // mid-bond/torsion coupling // energy on bond2 (middle bond) cos2phi = cos(2.0*phi); cos3phi = cos(3.0*phi); bt1 = mbt_f1[type] * cosphi; bt2 = mbt_f2[type] * cos2phi; bt3 = mbt_f3[type] * cos3phi; sumbte = bt1 + bt2 + bt3; db = r2 - mbt_r0[type]; if (eflag) edihedral += db * sumbte; // force on bond2 bt1 = -mbt_f1[type] * sinphi; bt2 = -2.0 * mbt_f2[type] * sin(2.0*phi); bt3 = -3.0 * mbt_f3[type] * sin(3.0*phi); sumbtf = bt1 + bt2 + bt3; for (i = 0; i < 4; i++) for (j = 0; j < 3; j++) fabcd[i][j] += db*sumbtf*dphidr[i][j] + sumbte*dbonddr[1][i][j]; // end-bond/torsion coupling // energy on bond1 (first bond) bt1 = ebt_f1_1[type] * cosphi; bt2 = ebt_f2_1[type] * cos2phi; bt3 = ebt_f3_1[type] * cos3phi; sumbte = bt1 + bt2 + bt3; db = r1 - ebt_r0_1[type]; if (eflag) edihedral += db * (bt1+bt2+bt3); // force on bond1 bt1 = ebt_f1_1[type] * sinphi; bt2 = 2.0 * ebt_f2_1[type] * sin(2.0*phi); bt3 = 3.0 * ebt_f3_1[type] * sin(3.0*phi); sumbtf = bt1 + bt2 + bt3; for (i = 0; i < 4; i++) for (j = 0; j < 3; j++) fabcd[i][j] -= db*sumbtf*dphidr[i][j] + sumbte*dbonddr[0][i][j]; // end-bond/torsion coupling // energy on bond3 (last bond) bt1 = ebt_f1_2[type] * cosphi; bt2 = ebt_f2_2[type] * cos2phi; bt3 = ebt_f3_2[type] * cos3phi; sumbte = bt1 + bt2 + bt3; db = r3 - ebt_r0_2[type]; if (eflag) edihedral += db * (bt1+bt2+bt3); // force on bond3 bt1 = -ebt_f1_2[type] * sinphi; bt2 = -2.0 * ebt_f2_2[type] * sin(2.0*phi); bt3 = -3.0 * ebt_f3_2[type] * sin(3.0*phi); sumbtf = bt1 + bt2 + bt3; for (i = 0; i < 4; i++) for (j = 0; j < 3; j++) fabcd[i][j] += db*sumbtf*dphidr[i][j] + sumbte*dbonddr[2][i][j]; // angle/torsion coupling // energy on angle1 at1 = at_f1_1[type] * cosphi; at2 = at_f2_1[type] * cos2phi; at3 = at_f3_1[type] * cos3phi; sumbte = at1 + at2 + at3; da = acos(costh12) - at_theta0_1[type]; if (eflag) edihedral += da * (at1+at2+at3); // force on angle1 bt1 = at_f1_1[type] * sinphi; bt2 = 2.0 * at_f2_1[type] * sin(2.0*phi); bt3 = 3.0 * at_f3_1[type] * sin(3.0*phi); sumbtf = bt1 + bt2 + bt3; for (i = 0; i < 4; i++) for (j = 0; j < 3; j++) fabcd[i][j] -= da*sumbtf*dphidr[i][j] + sumbte*dthetadr[0][i][j]; // energy on angle2 at1 = at_f1_2[type] * cosphi; at2 = at_f2_2[type] * cos2phi; at3 = at_f3_2[type] * cos3phi; sumbte = at1 + at2 + at3; da = acos(costh23) - at_theta0_2[type]; if (eflag) edihedral += da * (at1+at2+at3); // force on angle2 bt1 = -at_f1_2[type] * sinphi; bt2 = -2.0 * at_f2_2[type] * sin(2.0*phi); bt3 = -3.0 * at_f3_2[type] * sin(3.0*phi); sumbtf = bt1 + bt2 + bt3; for (i = 0; i < 4; i++) for (j = 0; j < 3; j++) fabcd[i][j] += da*sumbtf*dphidr[i][j] + sumbte*dthetadr[1][i][j]; // angle/angle/torsion coupling da1 = acos(costh12) - aat_theta0_1[type]; da2 = acos(costh23) - aat_theta0_2[type]; if (eflag) edihedral += aat_k[type]*da1*da2*cosphi; for (i = 0; i < 4; i++) for (j = 0; j < 3; j++) fabcd[i][j] -= aat_k[type] * (cosphi * (da2*dthetadr[0][i][j] - da1*dthetadr[1][i][j]) + sinphi * da1*da2*dphidr[i][j]); // bond1/bond3 coupling if (fabs(bb13t_k[type]) > SMALL) { r1_0 = bb13t_r10[type]; r3_0 = bb13t_r30[type]; dr1 = r1 - r1_0; dr2 = r3 - r3_0; tk1 = -bb13t_k[type] * dr1 / r3; tk2 = -bb13t_k[type] * dr2 / r1; if (eflag) edihedral += bb13t_k[type]*dr1*dr2; fabcd[0][0] += tk2 * vb1x; fabcd[0][1] += tk2 * vb1y; fabcd[0][2] += tk2 * vb1z; fabcd[1][0] -= tk2 * vb1x; fabcd[1][1] -= tk2 * vb1y; fabcd[1][2] -= tk2 * vb1z; fabcd[2][0] -= tk1 * vb3x; fabcd[2][1] -= tk1 * vb3y; fabcd[2][2] -= tk1 * vb3z; fabcd[3][0] += tk1 * vb3x; fabcd[3][1] += tk1 * vb3y; fabcd[3][2] += tk1 * vb3z; } // apply force to each of 4 atoms if (newton_bond || i1 < nlocal) { f[i1][0] += fabcd[0][0]; f[i1][1] += fabcd[0][1]; f[i1][2] += fabcd[0][2]; } if (newton_bond || i2 < nlocal) { f[i2][0] += fabcd[1][0]; f[i2][1] += fabcd[1][1]; f[i2][2] += fabcd[1][2]; } if (newton_bond || i3 < nlocal) { f[i3][0] += fabcd[2][0]; f[i3][1] += fabcd[2][1]; f[i3][2] += fabcd[2][2]; } if (newton_bond || i4 < nlocal) { f[i4][0] += fabcd[3][0]; f[i4][1] += fabcd[3][1]; f[i4][2] += fabcd[3][2]; } if (evflag) ev_tally(i1,i2,i3,i4,nlocal,newton_bond,edihedral, fabcd[0],fabcd[2],fabcd[3], vb1x,vb1y,vb1z,vb2x,vb2y,vb2z,vb3x,vb3y,vb3z); } } /* ---------------------------------------------------------------------- */ void DihedralClass2::allocate() { allocated = 1; int n = atom->ndihedraltypes; k1 = (double *) memory->smalloc((n+1)*sizeof(double),"dihedral:k1"); k2 = (double *) memory->smalloc((n+1)*sizeof(double),"dihedral:k2"); k3 = (double *) memory->smalloc((n+1)*sizeof(double),"dihedral:k3"); phi1 = (double *) memory->smalloc((n+1)*sizeof(double),"dihedral:phi1"); phi2 = (double *) memory->smalloc((n+1)*sizeof(double),"dihedral:phi2"); phi3 = (double *) memory->smalloc((n+1)*sizeof(double),"dihedral:phi3"); mbt_f1 = (double *) memory->smalloc((n+1)*sizeof(double),"dihedral:mbt_f1"); mbt_f2 = (double *) memory->smalloc((n+1)*sizeof(double),"dihedral:mbt_f2"); mbt_f3 = (double *) memory->smalloc((n+1)*sizeof(double),"dihedral:mbt_f3"); mbt_r0 = (double *) memory->smalloc((n+1)*sizeof(double),"dihedral:mbt_r0"); ebt_f1_1 = (double *) memory->smalloc((n+1)*sizeof(double),"dihedral:ebt_f1_1"); ebt_f2_1 = (double *) memory->smalloc((n+1)*sizeof(double),"dihedral:ebt_f2_1"); ebt_f3_1 = (double *) memory->smalloc((n+1)*sizeof(double),"dihedral:ebt_f3_1"); ebt_r0_1 = (double *) memory->smalloc((n+1)*sizeof(double),"dihedral:ebt_r0_1"); ebt_f1_2 = (double *) memory->smalloc((n+1)*sizeof(double),"dihedral:ebt_f1_2"); ebt_f2_2 = (double *) memory->smalloc((n+1)*sizeof(double),"dihedral:ebt_f2_2"); ebt_f3_2 = (double *) memory->smalloc((n+1)*sizeof(double),"dihedral:ebt_f3_2"); ebt_r0_2 = (double *) memory->smalloc((n+1)*sizeof(double),"dihedral:ebt_r0_2"); at_f1_1 = (double *) memory->smalloc((n+1)*sizeof(double),"dihedral:at_f1_1"); at_f2_1 = (double *) memory->smalloc((n+1)*sizeof(double),"dihedral:at_f2_1"); at_f3_1 = (double *) memory->smalloc((n+1)*sizeof(double),"dihedral:at_f3_1"); at_theta0_1 = (double *) memory->smalloc((n+1)*sizeof(double),"dihedral:at_theta0_1"); at_f1_2 = (double *) memory->smalloc((n+1)*sizeof(double),"dihedral:at_f1_2"); at_f2_2 = (double *) memory->smalloc((n+1)*sizeof(double),"dihedral:at_f2_2"); at_f3_2 = (double *) memory->smalloc((n+1)*sizeof(double),"dihedral:at_f3_2"); at_theta0_2 = (double *) memory->smalloc((n+1)*sizeof(double),"dihedral:at_theta0_2"); aat_k = (double *) memory->smalloc((n+1)*sizeof(double),"dihedral:aat_k"); aat_theta0_1 = (double *) memory->smalloc((n+1)*sizeof(double),"dihedral:aat_theta0_1"); aat_theta0_2 = (double *) memory->smalloc((n+1)*sizeof(double),"dihedral:aat_theta0_2"); bb13t_k = (double *) memory->smalloc((n+1)*sizeof(double),"dihedral:bb13t_k"); bb13t_r10 = (double *) memory->smalloc((n+1)*sizeof(double),"dihedral:bb13t_r10"); bb13t_r30 = (double *) memory->smalloc((n+1)*sizeof(double),"dihedral:bb13t_r30"); setflag = (int *) memory->smalloc((n+1)*sizeof(int),"dihedral:setflag"); setflag_d = (int *) memory->smalloc((n+1)*sizeof(int),"dihedral:setflag_d"); setflag_mbt = (int *) memory->smalloc((n+1)*sizeof(int),"dihedral:setflag_mbt"); setflag_ebt = (int *) memory->smalloc((n+1)*sizeof(int),"dihedral:setflag_ebt"); setflag_at = (int *) memory->smalloc((n+1)*sizeof(int),"dihedral:setflag_at"); setflag_aat = (int *) memory->smalloc((n+1)*sizeof(int),"dihedral:setflag_aat"); setflag_bb13t = (int *) memory->smalloc((n+1)*sizeof(int),"dihedral:setflag_bb13t"); for (int i = 1; i <= n; i++) setflag[i] = setflag_d[i] = setflag_mbt[i] = setflag_ebt[i] = setflag_at[i] = setflag_aat[i] = setflag_bb13t[i] = 0; } /* ---------------------------------------------------------------------- set coeffs for one or more types arg1 = "mbt" -> MiddleBondTorsion coeffs arg1 = "ebt" -> EndBondTorsion coeffs arg1 = "at" -> AngleTorsion coeffs arg1 = "aat" -> AngleAngleTorsion coeffs arg1 = "bb13" -> BondBond13Torsion coeffs arg1 -> Dihedral coeffs ------------------------------------------------------------------------- */ void DihedralClass2::coeff(int narg, char **arg) { if (narg < 2) error->all("Invalid coeffs for this dihedral style"); if (!allocated) allocate(); int ilo,ihi; force->bounds(arg[0],atom->ndihedraltypes,ilo,ihi); int count = 0; if (strcmp(arg[1],"mbt") == 0) { if (narg != 6) error->all("Incorrect args for dihedral coefficients"); double f1_one = force->numeric(arg[2]); double f2_one = force->numeric(arg[3]); double f3_one = force->numeric(arg[4]); double r0_one = force->numeric(arg[5]); for (int i = ilo; i <= ihi; i++) { mbt_f1[i] = f1_one; mbt_f2[i] = f2_one; mbt_f3[i] = f3_one; mbt_r0[i] = r0_one; setflag_mbt[i] = 1; count++; } } else if (strcmp(arg[1],"ebt") == 0) { if (narg != 10) error->all("Incorrect args for dihedral coefficients"); double f1_1_one = force->numeric(arg[2]); double f2_1_one = force->numeric(arg[3]); double f3_1_one = force->numeric(arg[4]); double f1_2_one = force->numeric(arg[5]); double f2_2_one = force->numeric(arg[6]); double f3_2_one = force->numeric(arg[7]); double r0_1_one = force->numeric(arg[8]); double r0_2_one = force->numeric(arg[9]); for (int i = ilo; i <= ihi; i++) { ebt_f1_1[i] = f1_1_one; ebt_f2_1[i] = f2_1_one; ebt_f3_1[i] = f3_1_one; ebt_f1_2[i] = f1_2_one; ebt_f2_2[i] = f2_2_one; ebt_f3_2[i] = f3_2_one; ebt_r0_1[i] = r0_1_one; ebt_r0_2[i] = r0_2_one; setflag_ebt[i] = 1; count++; } } else if (strcmp(arg[1],"at") == 0) { if (narg != 10) error->all("Incorrect args for dihedral coefficients"); double f1_1_one = force->numeric(arg[2]); double f2_1_one = force->numeric(arg[3]); double f3_1_one = force->numeric(arg[4]); double f1_2_one = force->numeric(arg[5]); double f2_2_one = force->numeric(arg[6]); double f3_2_one = force->numeric(arg[7]); double theta0_1_one = force->numeric(arg[8]); double theta0_2_one = force->numeric(arg[9]); // convert theta0's from degrees to radians for (int i = ilo; i <= ihi; i++) { at_f1_1[i] = f1_1_one; at_f2_1[i] = f2_1_one; at_f3_1[i] = f3_1_one; at_f1_2[i] = f1_2_one; at_f2_2[i] = f2_2_one; at_f3_2[i] = f3_2_one; at_theta0_1[i] = theta0_1_one/180.0 * PI; at_theta0_2[i] = theta0_2_one/180.0 * PI; setflag_at[i] = 1; count++; } } else if (strcmp(arg[1],"aat") == 0) { if (narg != 5) error->all("Incorrect args for dihedral coefficients"); double k_one = force->numeric(arg[2]); double theta0_1_one = force->numeric(arg[3]); double theta0_2_one = force->numeric(arg[4]); // convert theta0's from degrees to radians for (int i = ilo; i <= ihi; i++) { aat_k[i] = k_one; aat_theta0_1[i] = theta0_1_one/180.0 * PI; aat_theta0_2[i] = theta0_2_one/180.0 * PI; setflag_aat[i] = 1; count++; } } else if (strcmp(arg[1],"bb13") == 0) { if (narg != 5) error->all("Incorrect args for dihedral coefficients"); double k_one = force->numeric(arg[2]); double r10_one = force->numeric(arg[3]); double r30_one = force->numeric(arg[4]); for (int i = ilo; i <= ihi; i++) { bb13t_k[i] = k_one; bb13t_r10[i] = r10_one; bb13t_r30[i] = r30_one; setflag_bb13t[i] = 1; count++; } } else { if (narg != 7) error->all("Incorrect args for dihedral coefficients"); double k1_one = force->numeric(arg[1]); double phi1_one = force->numeric(arg[2]); double k2_one = force->numeric(arg[3]); double phi2_one = force->numeric(arg[4]); double k3_one = force->numeric(arg[5]); double phi3_one = force->numeric(arg[6]); // convert phi's from degrees to radians for (int i = ilo; i <= ihi; i++) { k1[i] = k1_one; phi1[i] = phi1_one/180.0 * PI; k2[i] = k2_one; phi2[i] = phi2_one/180.0 * PI; k3[i] = k3_one; phi3[i] = phi3_one/180.0 * PI; setflag_d[i] = 1; count++; } } if (count == 0) error->all("Incorrect args for dihedral coefficients"); for (int i = ilo; i <= ihi; i++) if (setflag_d[i] == 1 && setflag_mbt[i] == 1 && setflag_ebt[i] == 1 && setflag_at[i] == 1 && setflag_aat[i] == 1 && setflag_bb13t[i] == 1) setflag[i] = 1; } /* ---------------------------------------------------------------------- proc 0 writes out coeffs to restart file ------------------------------------------------------------------------- */ void DihedralClass2::write_restart(FILE *fp) { fwrite(&k1[1],sizeof(double),atom->ndihedraltypes,fp); fwrite(&k2[1],sizeof(double),atom->ndihedraltypes,fp); fwrite(&k3[1],sizeof(double),atom->ndihedraltypes,fp); fwrite(&phi1[1],sizeof(double),atom->ndihedraltypes,fp); fwrite(&phi2[1],sizeof(double),atom->ndihedraltypes,fp); fwrite(&phi3[1],sizeof(double),atom->ndihedraltypes,fp); fwrite(&mbt_f1[1],sizeof(double),atom->ndihedraltypes,fp); fwrite(&mbt_f2[1],sizeof(double),atom->ndihedraltypes,fp); fwrite(&mbt_f3[1],sizeof(double),atom->ndihedraltypes,fp); fwrite(&mbt_r0[1],sizeof(double),atom->ndihedraltypes,fp); fwrite(&ebt_f1_1[1],sizeof(double),atom->ndihedraltypes,fp); fwrite(&ebt_f2_1[1],sizeof(double),atom->ndihedraltypes,fp); fwrite(&ebt_f3_1[1],sizeof(double),atom->ndihedraltypes,fp); fwrite(&ebt_r0_1[1],sizeof(double),atom->ndihedraltypes,fp); fwrite(&ebt_f1_2[1],sizeof(double),atom->ndihedraltypes,fp); fwrite(&ebt_f2_2[1],sizeof(double),atom->ndihedraltypes,fp); fwrite(&ebt_f3_2[1],sizeof(double),atom->ndihedraltypes,fp); fwrite(&ebt_r0_2[1],sizeof(double),atom->ndihedraltypes,fp); fwrite(&at_f1_1[1],sizeof(double),atom->ndihedraltypes,fp); fwrite(&at_f2_1[1],sizeof(double),atom->ndihedraltypes,fp); fwrite(&at_f3_1[1],sizeof(double),atom->ndihedraltypes,fp); fwrite(&at_theta0_1[1],sizeof(double),atom->ndihedraltypes,fp); fwrite(&at_f1_2[1],sizeof(double),atom->ndihedraltypes,fp); fwrite(&at_f2_2[1],sizeof(double),atom->ndihedraltypes,fp); fwrite(&at_f3_2[1],sizeof(double),atom->ndihedraltypes,fp); fwrite(&at_theta0_2[1],sizeof(double),atom->ndihedraltypes,fp); fwrite(&aat_k[1],sizeof(double),atom->ndihedraltypes,fp); fwrite(&aat_theta0_1[1],sizeof(double),atom->ndihedraltypes,fp); fwrite(&aat_theta0_2[1],sizeof(double),atom->ndihedraltypes,fp); fwrite(&bb13t_k[1],sizeof(double),atom->ndihedraltypes,fp); fwrite(&bb13t_r10[1],sizeof(double),atom->ndihedraltypes,fp); fwrite(&bb13t_r30[1],sizeof(double),atom->ndihedraltypes,fp); } /* ---------------------------------------------------------------------- proc 0 reads coeffs from restart file, bcasts them ------------------------------------------------------------------------- */ void DihedralClass2::read_restart(FILE *fp) { allocate(); if (comm->me == 0) { fread(&k1[1],sizeof(double),atom->ndihedraltypes,fp); fread(&k2[1],sizeof(double),atom->ndihedraltypes,fp); fread(&k3[1],sizeof(double),atom->ndihedraltypes,fp); fread(&phi1[1],sizeof(double),atom->ndihedraltypes,fp); fread(&phi2[1],sizeof(double),atom->ndihedraltypes,fp); fread(&phi3[1],sizeof(double),atom->ndihedraltypes,fp); fread(&mbt_f1[1],sizeof(double),atom->ndihedraltypes,fp); fread(&mbt_f2[1],sizeof(double),atom->ndihedraltypes,fp); fread(&mbt_f3[1],sizeof(double),atom->ndihedraltypes,fp); fread(&mbt_r0[1],sizeof(double),atom->ndihedraltypes,fp); fread(&ebt_f1_1[1],sizeof(double),atom->ndihedraltypes,fp); fread(&ebt_f2_1[1],sizeof(double),atom->ndihedraltypes,fp); fread(&ebt_f3_1[1],sizeof(double),atom->ndihedraltypes,fp); fread(&ebt_r0_1[1],sizeof(double),atom->ndihedraltypes,fp); fread(&ebt_f1_2[1],sizeof(double),atom->ndihedraltypes,fp); fread(&ebt_f2_2[1],sizeof(double),atom->ndihedraltypes,fp); fread(&ebt_f3_2[1],sizeof(double),atom->ndihedraltypes,fp); fread(&ebt_r0_2[1],sizeof(double),atom->ndihedraltypes,fp); fread(&at_f1_1[1],sizeof(double),atom->ndihedraltypes,fp); fread(&at_f2_1[1],sizeof(double),atom->ndihedraltypes,fp); fread(&at_f3_1[1],sizeof(double),atom->ndihedraltypes,fp); fread(&at_theta0_1[1],sizeof(double),atom->ndihedraltypes,fp); fread(&at_f1_2[1],sizeof(double),atom->ndihedraltypes,fp); fread(&at_f2_2[1],sizeof(double),atom->ndihedraltypes,fp); fread(&at_f3_2[1],sizeof(double),atom->ndihedraltypes,fp); fread(&at_theta0_2[1],sizeof(double),atom->ndihedraltypes,fp); fread(&aat_k[1],sizeof(double),atom->ndihedraltypes,fp); fread(&aat_theta0_1[1],sizeof(double),atom->ndihedraltypes,fp); fread(&aat_theta0_2[1],sizeof(double),atom->ndihedraltypes,fp); fread(&bb13t_k[1],sizeof(double),atom->ndihedraltypes,fp); fread(&bb13t_r10[1],sizeof(double),atom->ndihedraltypes,fp); fread(&bb13t_r30[1],sizeof(double),atom->ndihedraltypes,fp); } MPI_Bcast(&k1[1],atom->ndihedraltypes,MPI_DOUBLE,0,world); MPI_Bcast(&k2[1],atom->ndihedraltypes,MPI_DOUBLE,0,world); MPI_Bcast(&k3[1],atom->ndihedraltypes,MPI_DOUBLE,0,world); MPI_Bcast(&phi1[1],atom->ndihedraltypes,MPI_DOUBLE,0,world); MPI_Bcast(&phi2[1],atom->ndihedraltypes,MPI_DOUBLE,0,world); MPI_Bcast(&phi3[1],atom->ndihedraltypes,MPI_DOUBLE,0,world); MPI_Bcast(&mbt_f1[1],atom->ndihedraltypes,MPI_DOUBLE,0,world); MPI_Bcast(&mbt_f2[1],atom->ndihedraltypes,MPI_DOUBLE,0,world); MPI_Bcast(&mbt_f3[1],atom->ndihedraltypes,MPI_DOUBLE,0,world); MPI_Bcast(&mbt_r0[1],atom->ndihedraltypes,MPI_DOUBLE,0,world); MPI_Bcast(&ebt_f1_1[1],atom->ndihedraltypes,MPI_DOUBLE,0,world); MPI_Bcast(&ebt_f2_1[1],atom->ndihedraltypes,MPI_DOUBLE,0,world); MPI_Bcast(&ebt_f3_1[1],atom->ndihedraltypes,MPI_DOUBLE,0,world); MPI_Bcast(&ebt_r0_1[1],atom->ndihedraltypes,MPI_DOUBLE,0,world); MPI_Bcast(&ebt_f1_2[1],atom->ndihedraltypes,MPI_DOUBLE,0,world); MPI_Bcast(&ebt_f2_2[1],atom->ndihedraltypes,MPI_DOUBLE,0,world); MPI_Bcast(&ebt_f3_2[1],atom->ndihedraltypes,MPI_DOUBLE,0,world); MPI_Bcast(&ebt_r0_2[1],atom->ndihedraltypes,MPI_DOUBLE,0,world); MPI_Bcast(&at_f1_1[1],atom->ndihedraltypes,MPI_DOUBLE,0,world); MPI_Bcast(&at_f2_1[1],atom->ndihedraltypes,MPI_DOUBLE,0,world); MPI_Bcast(&at_f3_1[1],atom->ndihedraltypes,MPI_DOUBLE,0,world); MPI_Bcast(&at_theta0_1[1],atom->ndihedraltypes,MPI_DOUBLE,0,world); MPI_Bcast(&at_f1_2[1],atom->ndihedraltypes,MPI_DOUBLE,0,world); MPI_Bcast(&at_f2_2[1],atom->ndihedraltypes,MPI_DOUBLE,0,world); MPI_Bcast(&at_f3_2[1],atom->ndihedraltypes,MPI_DOUBLE,0,world); MPI_Bcast(&at_theta0_2[1],atom->ndihedraltypes,MPI_DOUBLE,0,world); MPI_Bcast(&aat_k[1],atom->ndihedraltypes,MPI_DOUBLE,0,world); MPI_Bcast(&aat_theta0_1[1],atom->ndihedraltypes,MPI_DOUBLE,0,world); MPI_Bcast(&aat_theta0_2[1],atom->ndihedraltypes,MPI_DOUBLE,0,world); MPI_Bcast(&bb13t_k[1],atom->ndihedraltypes,MPI_DOUBLE,0,world); MPI_Bcast(&bb13t_r10[1],atom->ndihedraltypes,MPI_DOUBLE,0,world); MPI_Bcast(&bb13t_r30[1],atom->ndihedraltypes,MPI_DOUBLE,0,world); for (int i = 1; i <= atom->ndihedraltypes; i++) setflag[i] = 1; } diff --git a/src/CLASS2/improper_class2.cpp b/src/CLASS2/improper_class2.cpp index ff24cb55f..716ced12f 100644 --- a/src/CLASS2/improper_class2.cpp +++ b/src/CLASS2/improper_class2.cpp @@ -1,848 +1,851 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- Contributing author: Eric Simon (Cray) ------------------------------------------------------------------------- */ #include "math.h" #include "string.h" #include "stdlib.h" #include "improper_class2.h" +#include "lmptype.h" #include "atom.h" #include "neighbor.h" #include "update.h" #include "domain.h" #include "comm.h" #include "force.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; #define SMALL 0.001 /* ---------------------------------------------------------------------- */ ImproperClass2::ImproperClass2(LAMMPS *lmp) : Improper(lmp) { PI = 4.0*atan(1.0); } /* ---------------------------------------------------------------------- */ ImproperClass2::~ImproperClass2() { if (allocated) { memory->sfree(setflag); memory->sfree(setflag_i); memory->sfree(setflag_aa); memory->sfree(k0); memory->sfree(chi0); memory->sfree(aa_k1); memory->sfree(aa_k2); memory->sfree(aa_k3); memory->sfree(aa_theta0_1); memory->sfree(aa_theta0_2); memory->sfree(aa_theta0_3); } } /* ---------------------------------------------------------------------- */ void ImproperClass2::compute(int eflag, int vflag) { int i1,i2,i3,i4,i,j,k,n,type; double eimproper; double delr[3][3],rmag[3],rinvmag[3],rmag2[3]; double theta[3],costheta[3],sintheta[3]; double cossqtheta[3],sinsqtheta[3],invstheta[3]; double rABxrCB[3],rDBxrAB[3],rCBxrDB[3]; double ddelr[3][4],dr[3][4][3],dinvr[3][4][3]; double dthetadr[3][4][3],dinvsth[3][4][3]; double dinv3r[4][3],dinvs3r[3][4][3]; double drCBxrDB[3],rCBxdrDB[3],drDBxrAB[3],rDBxdrAB[3]; double drABxrCB[3],rABxdrCB[3]; double dot1,dot2,dd[3]; double fdot[3][4][3],ftmp,invs3r[3],inv3r; double t,tt1,tt3,sc1; double dotCBDBAB,dotDBABCB,dotABCBDB; double chi,deltachi,d2chi,cossin2; double drAB[3][4][3],drCB[3][4][3],drDB[3][4][3]; double dchi[3][4][3],dtotalchi[4][3]; double schiABCD,chiABCD,schiCBDA,chiCBDA,schiDBAC,chiDBAC; double fabcd[4][3]; eimproper = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = 0; for (i = 0; i < 3; i++) for (j = 0; j < 4; j++) for (k = 0; k < 3; k++) { dthetadr[i][j][k] = 0.0; drAB[i][j][k] = 0.0; drCB[i][j][k] = 0.0; drDB[i][j][k] = 0.0; } double **x = atom->x; double **f = atom->f; int **improperlist = neighbor->improperlist; int nimproperlist = neighbor->nimproperlist; int nlocal = atom->nlocal; int newton_bond = force->newton_bond; for (n = 0; n < nimproperlist; n++) { i1 = improperlist[n][0]; i2 = improperlist[n][1]; i3 = improperlist[n][2]; i4 = improperlist[n][3]; type = improperlist[n][4]; if (k0[type] == 0.0) continue; // difference vectors delr[0][0] = x[i1][0] - x[i2][0]; delr[0][1] = x[i1][1] - x[i2][1]; delr[0][2] = x[i1][2] - x[i2][2]; domain->minimum_image(delr[0]); delr[1][0] = x[i3][0] - x[i2][0]; delr[1][1] = x[i3][1] - x[i2][1]; delr[1][2] = x[i3][2] - x[i2][2]; domain->minimum_image(delr[1]); delr[2][0] = x[i4][0] - x[i2][0]; delr[2][1] = x[i4][1] - x[i2][1]; delr[2][2] = x[i4][2] - x[i2][2]; domain->minimum_image(delr[2]); // bond lengths and associated values for (i = 0; i < 3; i++) { rmag2[i] = delr[i][0]*delr[i][0] + delr[i][1]*delr[i][1] + delr[i][2]*delr[i][2]; rmag[i] = sqrt(rmag2[i]); rinvmag[i] = 1.0/rmag[i]; } // angle ABC, CBD, ABD costheta[0] = (delr[0][0]*delr[1][0] + delr[0][1]*delr[1][1] + delr[0][2]*delr[1][2]) / (rmag[0]*rmag[1]); costheta[1] = (delr[1][0]*delr[2][0] + delr[1][1]*delr[2][1] + delr[1][2]*delr[2][2]) / (rmag[1]*rmag[2]); costheta[2] = (delr[0][0]*delr[2][0] + delr[0][1]*delr[2][1] + delr[0][2]*delr[2][2]) / (rmag[0]*rmag[2]); // angle error check for (i = 0; i < 3; i++) { if (costheta[i] == -1.0) { int me; MPI_Comm_rank(world,&me); if (screen) { - char str[128]; - sprintf(str,"Improper problem: %d %d %d %d %d %d", - me,update->ntimestep, + char str[128],fstr[64]; + sprintf(fstr,"Improper problem: %%d %s %%d %%d %%d %%d", + BIGINT_FORMAT); + sprintf(str,fstr,me,update->ntimestep, atom->tag[i1],atom->tag[i2],atom->tag[i3],atom->tag[i4]); error->warning(str,0); + error->warning(str,0); fprintf(screen," 1st atom: %d %g %g %g\n", me,x[i1][0],x[i1][1],x[i1][2]); fprintf(screen," 2nd atom: %d %g %g %g\n", me,x[i2][0],x[i2][1],x[i2][2]); fprintf(screen," 3rd atom: %d %g %g %g\n", me,x[i3][0],x[i3][1],x[i3][2]); fprintf(screen," 4th atom: %d %g %g %g\n", me,x[i4][0],x[i4][1],x[i4][2]); } } } for (i = 0; i < 3; i++) { if (costheta[i] > 1.0) costheta[i] = 1.0; if (costheta[i] < -1.0) costheta[i] = -1.0; theta[i] = acos(costheta[i]); cossqtheta[i] = costheta[i]*costheta[i]; sintheta[i] = sin(theta[i]); invstheta[i] = 1.0/sintheta[i]; sinsqtheta[i] = sintheta[i]*sintheta[i]; } // cross & dot products cross(delr[0],delr[1],rABxrCB); cross(delr[2],delr[0],rDBxrAB); cross(delr[1],delr[2],rCBxrDB); dotCBDBAB = dot(rCBxrDB,delr[0]); dotDBABCB = dot(rDBxrAB,delr[1]); dotABCBDB = dot(rABxrCB,delr[2]); t = rmag[0] * rmag[1] * rmag[2]; inv3r = 1.0/t; invs3r[0] = invstheta[1] * inv3r; invs3r[1] = invstheta[2] * inv3r; invs3r[2] = invstheta[0] * inv3r; // chi ABCD, CBDA, DBAC // final chi is average of three schiABCD = dotCBDBAB * invs3r[0]; chiABCD = asin(schiABCD); schiCBDA = dotDBABCB * invs3r[1]; chiCBDA = asin(schiCBDA); schiDBAC = dotABCBDB * invs3r[2]; chiDBAC = asin(schiDBAC); chi = (chiABCD + chiCBDA + chiDBAC) / 3.0; deltachi = chi - chi0[type]; d2chi = deltachi * deltachi; // energy if (eflag) eimproper = k0[type]*d2chi; // forces // define d(delr) // i = bond AB/CB/DB, j = atom A/B/C/D for (i = 0; i < 3; i++) for (j = 0; j < 4; j++) ddelr[i][j] = 0.0; ddelr[0][0] = 1.0; ddelr[0][1] = -1.0; ddelr[1][1] = -1.0; ddelr[1][2] = 1.0; ddelr[2][1] = -1.0; ddelr[2][3] = 1.0; // compute d(|r|)/dr and d(1/|r|)/dr for each direction, bond and atom // define d(r) for each r // i = bond AB/CB/DB, j = atom A/B/C/D, k = X/Y/Z for (i = 0; i < 3; i++) for (j = 0; j < 4; j++) for (k = 0; k < 3; k++) { dr[i][j][k] = delr[i][k] * ddelr[i][j] / rmag[i]; dinvr[i][j][k] = -dr[i][j][k] / rmag2[i]; } // compute d(1 / (|r_AB| * |r_CB| * |r_DB|) / dr // i = atom A/B/C/D, j = X/Y/Z for (i = 0; i < 4; i++) for (j = 0; j < 3; j++) dinv3r[i][j] = rinvmag[1] * (rinvmag[2] * dinvr[0][i][j] + rinvmag[0] * dinvr[2][i][j]) + rinvmag[2] * rinvmag[0] * dinvr[1][i][j]; // compute d(theta)/d(r) for 3 angles // angleABC tt1 = costheta[0] / rmag2[0]; tt3 = costheta[0] / rmag2[1]; sc1 = 1.0 / sqrt(1.0 - cossqtheta[0]); dthetadr[0][0][0] = sc1 * ((tt1 * delr[0][0]) - (delr[1][0] * rinvmag[0] * rinvmag[1])); dthetadr[0][0][1] = sc1 * ((tt1 * delr[0][1]) - (delr[1][1] * rinvmag[0] * rinvmag[1])); dthetadr[0][0][2] = sc1 * ((tt1 * delr[0][2]) - (delr[1][2] * rinvmag[0] * rinvmag[1])); dthetadr[0][1][0] = -sc1 * ((tt1 * delr[0][0]) - (delr[1][0] * rinvmag[0] * rinvmag[1]) + (tt3 * delr[1][0]) - (delr[0][0] * rinvmag[0] * rinvmag[1])); dthetadr[0][1][1] = -sc1 * ((tt1 * delr[0][1]) - (delr[1][1] * rinvmag[0] * rinvmag[1]) + (tt3 * delr[1][1]) - (delr[0][1] * rinvmag[0] * rinvmag[1])); dthetadr[0][1][2] = -sc1 * ((tt1 * delr[0][2]) - (delr[1][2] * rinvmag[0] * rinvmag[1]) + (tt3 * delr[1][2]) - (delr[0][2] * rinvmag[0] * rinvmag[1])); dthetadr[0][2][0] = sc1 * ((tt3 * delr[1][0]) - (delr[0][0] * rinvmag[0] * rinvmag[1])); dthetadr[0][2][1] = sc1 * ((tt3 * delr[1][1]) - (delr[0][1] * rinvmag[0] * rinvmag[1])); dthetadr[0][2][2] = sc1 * ((tt3 * delr[1][2]) - (delr[0][2] * rinvmag[0] * rinvmag[1])); // angleCBD tt1 = costheta[1] / rmag2[1]; tt3 = costheta[1] / rmag2[2]; sc1 = 1.0 / sqrt(1.0 - cossqtheta[1]); dthetadr[1][2][0] = sc1 * ((tt1 * delr[1][0]) - (delr[2][0] * rinvmag[1] * rinvmag[2])); dthetadr[1][2][1] = sc1 * ((tt1 * delr[1][1]) - (delr[2][1] * rinvmag[1] * rinvmag[2])); dthetadr[1][2][2] = sc1 * ((tt1 * delr[1][2]) - (delr[2][2] * rinvmag[1] * rinvmag[2])); dthetadr[1][1][0] = -sc1 * ((tt1 * delr[1][0]) - (delr[2][0] * rinvmag[1] * rinvmag[2]) + (tt3 * delr[2][0]) - (delr[1][0] * rinvmag[2] * rinvmag[1])); dthetadr[1][1][1] = -sc1 * ((tt1 * delr[1][1]) - (delr[2][1] * rinvmag[1] * rinvmag[2]) + (tt3 * delr[2][1]) - (delr[1][1] * rinvmag[2] * rinvmag[1])); dthetadr[1][1][2] = -sc1 * ((tt1 * delr[1][2]) - (delr[2][2] * rinvmag[1] * rinvmag[2]) + (tt3 * delr[2][2]) - (delr[1][2] * rinvmag[2] * rinvmag[1])); dthetadr[1][3][0] = sc1 * ((tt3 * delr[2][0]) - (delr[1][0] * rinvmag[2] * rinvmag[1])); dthetadr[1][3][1] = sc1 * ((tt3 * delr[2][1]) - (delr[1][1] * rinvmag[2] * rinvmag[1])); dthetadr[1][3][2] = sc1 * ((tt3 * delr[2][2]) - (delr[1][2] * rinvmag[2] * rinvmag[1])); // angleABD tt1 = costheta[2] / rmag2[0]; tt3 = costheta[2] / rmag2[2]; sc1 = 1.0 / sqrt(1.0 - cossqtheta[2]); dthetadr[2][0][0] = sc1 * ((tt1 * delr[0][0]) - (delr[2][0] * rinvmag[0] * rinvmag[2])); dthetadr[2][0][1] = sc1 * ((tt1 * delr[0][1]) - (delr[2][1] * rinvmag[0] * rinvmag[2])); dthetadr[2][0][2] = sc1 * ((tt1 * delr[0][2]) - (delr[2][2] * rinvmag[0] * rinvmag[2])); dthetadr[2][1][0] = -sc1 * ((tt1 * delr[0][0]) - (delr[2][0] * rinvmag[0] * rinvmag[2]) + (tt3 * delr[2][0]) - (delr[0][0] * rinvmag[2] * rinvmag[0])); dthetadr[2][1][1] = -sc1 * ((tt1 * delr[0][1]) - (delr[2][1] * rinvmag[0] * rinvmag[2]) + (tt3 * delr[2][1]) - (delr[0][1] * rinvmag[2] * rinvmag[0])); dthetadr[2][1][2] = -sc1 * ((tt1 * delr[0][2]) - (delr[2][2] * rinvmag[0] * rinvmag[2]) + (tt3 * delr[2][2]) - (delr[0][2] * rinvmag[2] * rinvmag[0])); dthetadr[2][3][0] = sc1 * ((tt3 * delr[2][0]) - (delr[0][0] * rinvmag[2] * rinvmag[0])); dthetadr[2][3][1] = sc1 * ((tt3 * delr[2][1]) - (delr[0][1] * rinvmag[2] * rinvmag[0])); dthetadr[2][3][2] = sc1 * ((tt3 * delr[2][2]) - (delr[0][2] * rinvmag[2] * rinvmag[0])); // compute d( 1 / sin(theta))/dr // i = angle, j = atom, k = direction for (i = 0; i < 3; i++) { cossin2 = -costheta[i] / sinsqtheta[i]; for (j = 0; j < 4; j++) for (k = 0; k < 3; k++) dinvsth[i][j][k] = cossin2 * dthetadr[i][j][k]; } // compute d(1 / sin(theta) * |r_AB| * |r_CB| * |r_DB|)/dr // i = angle, j = atom for (i = 0; i < 4; i++) for (j = 0; j < 3; j++) { dinvs3r[0][i][j] = (invstheta[1] * dinv3r[i][j]) + (inv3r * dinvsth[1][i][j]); dinvs3r[1][i][j] = (invstheta[2] * dinv3r[i][j]) + (inv3r * dinvsth[2][i][j]); dinvs3r[2][i][j] = (invstheta[0] * dinv3r[i][j]) + (inv3r * dinvsth[0][i][j]); } // drCB(i,j,k), etc // i = vector X'/Y'/Z', j = atom A/B/C/D, k = direction X/Y/Z for (i = 0; i < 3; i++) { drCB[i][1][i] = -1.0; drAB[i][1][i] = -1.0; drDB[i][1][i] = -1.0; drDB[i][3][i] = 1.0; drCB[i][2][i] = 1.0; drAB[i][0][i] = 1.0; } // d((r_CB x r_DB) dot r_AB) // r_CB x d(r_DB) // d(r_CB) x r_DB // (r_CB x d(r_DB)) + (d(r_CB) x r_DB) // (r_CB x d(r_DB)) + (d(r_CB) x r_DB) dot r_AB // d(r_AB) dot (r_CB x r_DB) for (i = 0; i < 3; i++) for (j = 0; j < 4; j++) { cross(delr[1],drDB[i][j],rCBxdrDB); cross(drCB[i][j],delr[2],drCBxrDB); for (k = 0; k < 3; k++) dd[k] = rCBxdrDB[k] + drCBxrDB[k]; dot1 = dot(dd,delr[0]); dot2 = dot(rCBxrDB,drAB[i][j]); fdot[0][j][i] = dot1 + dot2; } // d((r_DB x r_AB) dot r_CB) // r_DB x d(r_AB) // d(r_DB) x r_AB // (r_DB x d(r_AB)) + (d(r_DB) x r_AB) // (r_DB x d(r_AB)) + (d(r_DB) x r_AB) dot r_CB // d(r_CB) dot (r_DB x r_AB) for (i = 0; i < 3; i++) for (j = 0; j < 4; j++) { cross(delr[2],drAB[i][j],rDBxdrAB); cross(drDB[i][j],delr[0],drDBxrAB); for (k = 0; k < 3; k++) dd[k] = rDBxdrAB[k] + drDBxrAB[k]; dot1 = dot(dd,delr[1]); dot2 = dot(rDBxrAB,drCB[i][j]); fdot[1][j][i] = dot1 + dot2; } // d((r_AB x r_CB) dot r_DB) // r_AB x d(r_CB) // d(r_AB) x r_CB // (r_AB x d(r_CB)) + (d(r_AB) x r_CB) // (r_AB x d(r_CB)) + (d(r_AB) x r_CB) dot r_DB // d(r_DB) dot (r_AB x r_CB) for (i = 0; i < 3; i++) for (j = 0; j < 4; j++) { cross(delr[0],drCB[i][j],rABxdrCB); cross(drAB[i][j],delr[1],drABxrCB); for (k = 0; k < 3; k++) dd[k] = rABxdrCB[k] + drABxrCB[k]; dot1 = dot(dd,delr[2]); dot2 = dot(rABxrCB,drDB[i][j]); fdot[2][j][i] = dot1 + dot2; } // force on each atom for (i = 0; i < 4; i++) for (j = 0; j < 3; j++) { ftmp = (fdot[0][i][j] * invs3r[0]) + (dinvs3r[0][i][j] * dotCBDBAB); dchi[0][i][j] = ftmp / cos(chiABCD); ftmp = (fdot[1][i][j] * invs3r[1]) + (dinvs3r[1][i][j] * dotDBABCB); dchi[1][i][j] = ftmp / cos(chiCBDA); ftmp = (fdot[2][i][j] * invs3r[2]) + (dinvs3r[2][i][j] * dotABCBDB); dchi[2][i][j] = ftmp / cos(chiDBAC); dtotalchi[i][j] = (dchi[0][i][j]+dchi[1][i][j]+dchi[2][i][j]) / 3.0; } for (i = 0; i < 4; i++) for (j = 0; j < 3; j++) fabcd[i][j] = -2.0*k0[type] * deltachi*dtotalchi[i][j]; // apply force to each of 4 atoms if (newton_bond || i1 < nlocal) { f[i1][0] += fabcd[0][0]; f[i1][1] += fabcd[0][1]; f[i1][2] += fabcd[0][2]; } if (newton_bond || i2 < nlocal) { f[i2][0] += fabcd[1][0]; f[i2][1] += fabcd[1][1]; f[i2][2] += fabcd[1][2]; } if (newton_bond || i3 < nlocal) { f[i3][0] += fabcd[2][0]; f[i3][1] += fabcd[2][1]; f[i3][2] += fabcd[2][2]; } if (newton_bond || i4 < nlocal) { f[i4][0] += fabcd[3][0]; f[i4][1] += fabcd[3][1]; f[i4][2] += fabcd[3][2]; } if (evflag) ev_tally(i1,i2,i3,i4,nlocal,newton_bond,eimproper, fabcd[0],fabcd[2],fabcd[3], delr[0][0],delr[0][1],delr[0][2], delr[1][0],delr[1][1],delr[1][2], delr[2][0]-delr[1][0],delr[2][1]-delr[1][1], delr[2][2]-delr[1][2]); } // compute angle-angle interactions angleangle(eflag,vflag); } /* ---------------------------------------------------------------------- */ void ImproperClass2::allocate() { allocated = 1; int n = atom->nimpropertypes; k0 = (double *) memory->smalloc((n+1)*sizeof(double),"improper:k0"); chi0 = (double *) memory->smalloc((n+1)*sizeof(double),"improper:chi0"); aa_k1 = (double *) memory->smalloc((n+1)*sizeof(double),"improper:aa_k1"); aa_k2 = (double *) memory->smalloc((n+1)*sizeof(double),"improper:aa_k2"); aa_k3 = (double *) memory->smalloc((n+1)*sizeof(double),"improper:aa_k3"); aa_theta0_1 = (double *) memory->smalloc((n+1)*sizeof(double),"improper:aa_theta0_1"); aa_theta0_2 = (double *) memory->smalloc((n+1)*sizeof(double),"improper:aa_theta0_2"); aa_theta0_3 = (double *) memory->smalloc((n+1)*sizeof(double),"improper:aa_theta0_3"); setflag = (int *) memory->smalloc((n+1)*sizeof(int),"improper:setflag"); setflag_i = (int *) memory->smalloc((n+1)*sizeof(int),"improper:setflag_i"); setflag_aa = (int *) memory->smalloc((n+1)*sizeof(int),"improper:setflag_aa"); for (int i = 1; i <= n; i++) setflag[i] = setflag_i[i] = setflag_aa[i] = 0; } /* ---------------------------------------------------------------------- set coeffs for one or more types arg1 = "aa" -> AngleAngle coeffs else arg1 -> improper coeffs ------------------------------------------------------------------------- */ void ImproperClass2::coeff(int narg, char **arg) { if (narg < 2) error->all("Incorrect args for improper coefficients"); if (!allocated) allocate(); int ilo,ihi; force->bounds(arg[0],atom->nimpropertypes,ilo,ihi); int count = 0; if (strcmp(arg[1],"aa") == 0) { if (narg != 8) error->all("Incorrect args for improper coefficients"); double k1_one = force->numeric(arg[2]); double k2_one = force->numeric(arg[3]); double k3_one = force->numeric(arg[4]); double theta0_1_one = force->numeric(arg[5]); double theta0_2_one = force->numeric(arg[6]); double theta0_3_one = force->numeric(arg[7]); // convert theta0's from degrees to radians for (int i = ilo; i <= ihi; i++) { aa_k1[i] = k1_one; aa_k2[i] = k2_one; aa_k3[i] = k3_one; aa_theta0_1[i] = theta0_1_one/180.0 * PI; aa_theta0_2[i] = theta0_2_one/180.0 * PI; aa_theta0_3[i] = theta0_3_one/180.0 * PI; setflag_aa[i] = 1; count++; } } else { if (narg != 3) error->all("Incorrect args for improper coefficients"); double k0_one = force->numeric(arg[1]); double chi0_one = force->numeric(arg[2]); // convert chi0 from degrees to radians for (int i = ilo; i <= ihi; i++) { k0[i] = k0_one; chi0[i] = chi0_one/180.0 * PI; setflag_i[i] = 1; count++; } } if (count == 0) error->all("Incorrect args for improper coefficients"); for (int i = ilo; i <= ihi; i++) if (setflag_i[i] == 1 && setflag_aa[i] == 1) setflag[i] = 1; } /* ---------------------------------------------------------------------- proc 0 writes out coeffs to restart file ------------------------------------------------------------------------- */ void ImproperClass2::write_restart(FILE *fp) { fwrite(&k0[1],sizeof(double),atom->nimpropertypes,fp); fwrite(&chi0[1],sizeof(double),atom->nimpropertypes,fp); fwrite(&aa_k1[1],sizeof(double),atom->nimpropertypes,fp); fwrite(&aa_k2[1],sizeof(double),atom->nimpropertypes,fp); fwrite(&aa_k3[1],sizeof(double),atom->nimpropertypes,fp); fwrite(&aa_theta0_1[1],sizeof(double),atom->nimpropertypes,fp); fwrite(&aa_theta0_2[1],sizeof(double),atom->nimpropertypes,fp); fwrite(&aa_theta0_3[1],sizeof(double),atom->nimpropertypes,fp); } /* ---------------------------------------------------------------------- proc 0 reads coeffs from restart file, bcasts them ------------------------------------------------------------------------- */ void ImproperClass2::read_restart(FILE *fp) { allocate(); if (comm->me == 0) { fread(&k0[1],sizeof(double),atom->nimpropertypes,fp); fread(&chi0[1],sizeof(double),atom->nimpropertypes,fp); fread(&aa_k1[1],sizeof(double),atom->nimpropertypes,fp); fread(&aa_k2[1],sizeof(double),atom->nimpropertypes,fp); fread(&aa_k3[1],sizeof(double),atom->nimpropertypes,fp); fread(&aa_theta0_1[1],sizeof(double),atom->nimpropertypes,fp); fread(&aa_theta0_2[1],sizeof(double),atom->nimpropertypes,fp); fread(&aa_theta0_3[1],sizeof(double),atom->nimpropertypes,fp); } MPI_Bcast(&k0[1],atom->nimpropertypes,MPI_DOUBLE,0,world); MPI_Bcast(&chi0[1],atom->nimpropertypes,MPI_DOUBLE,0,world); MPI_Bcast(&aa_k1[1],atom->nimpropertypes,MPI_DOUBLE,0,world); MPI_Bcast(&aa_k2[1],atom->nimpropertypes,MPI_DOUBLE,0,world); MPI_Bcast(&aa_k3[1],atom->nimpropertypes,MPI_DOUBLE,0,world); MPI_Bcast(&aa_theta0_1[1],atom->nimpropertypes,MPI_DOUBLE,0,world); MPI_Bcast(&aa_theta0_2[1],atom->nimpropertypes,MPI_DOUBLE,0,world); MPI_Bcast(&aa_theta0_3[1],atom->nimpropertypes,MPI_DOUBLE,0,world); for (int i = 1; i <= atom->nimpropertypes; i++) setflag[i] = 1; } /* ---------------------------------------------------------------------- angle-angle interactions within improper ------------------------------------------------------------------------- */ void ImproperClass2::angleangle(int eflag, int vflag) { int i1,i2,i3,i4,i,j,k,n,type; double eimproper; double delxAB,delyAB,delzAB,rABmag2,rAB; double delxBC,delyBC,delzBC,rBCmag2,rBC; double delxBD,delyBD,delzBD,rBDmag2,rBD; double costhABC,thetaABC,costhABD; double thetaABD,costhCBD,thetaCBD,dthABC,dthCBD,dthABD; double sc1,t1,t3,r12; double dthetadr[3][4][3],fabcd[4][3]; double **x = atom->x; double **f = atom->f; int **improperlist = neighbor->improperlist; int nimproperlist = neighbor->nimproperlist; int nlocal = atom->nlocal; int newton_bond = force->newton_bond; for (n = 0; n < nimproperlist; n++) { i1 = improperlist[n][0]; i2 = improperlist[n][1]; i3 = improperlist[n][2]; i4 = improperlist[n][3]; type = improperlist[n][4]; // difference vectors delxAB = x[i1][0] - x[i2][0]; delyAB = x[i1][1] - x[i2][1]; delzAB = x[i1][2] - x[i2][2]; domain->minimum_image(delxAB,delyAB,delzAB); delxBC = x[i3][0] - x[i2][0]; delyBC = x[i3][1] - x[i2][1]; delzBC = x[i3][2] - x[i2][2]; domain->minimum_image(delxBC,delyBC,delzBC); delxBD = x[i4][0] - x[i2][0]; delyBD = x[i4][1] - x[i2][1]; delzBD = x[i4][2] - x[i2][2]; domain->minimum_image(delxBD,delyBD,delzBD); // bond lengths rABmag2 = delxAB*delxAB + delyAB*delyAB + delzAB*delzAB; rAB = sqrt(rABmag2); rBCmag2 = delxBC*delxBC + delyBC*delyBC + delzBC*delzBC; rBC = sqrt(rBCmag2); rBDmag2 = delxBD*delxBD + delyBD*delyBD + delzBD*delzBD; rBD = sqrt(rBDmag2); // angle ABC, ABD, CBD costhABC = (delxAB*delxBC + delyAB*delyBC + delzAB*delzBC) / (rAB * rBC); if (costhABC > 1.0) costhABC = 1.0; if (costhABC < -1.0) costhABC = -1.0; thetaABC = acos(costhABC); costhABD = (delxAB*delxBD + delyAB*delyBD + delzAB*delzBD) / (rAB * rBD); if (costhABD > 1.0) costhABD = 1.0; if (costhABD < -1.0) costhABD = -1.0; thetaABD = acos(costhABD); costhCBD = (delxBC*delxBD + delyBC*delyBD + delzBC*delzBD) /(rBC * rBD); if (costhCBD > 1.0) costhCBD = 1.0; if (costhCBD < -1.0) costhCBD = -1.0; thetaCBD = acos(costhCBD); dthABC = thetaABC - aa_theta0_1[type]; dthCBD = thetaCBD - aa_theta0_2[type]; dthABD = thetaABD - aa_theta0_3[type]; // energy if (eflag) eimproper = aa_k2[type] * dthABC * dthABD + aa_k1[type] * dthABC * dthCBD + aa_k3[type] * dthABD * dthCBD; // d(theta)/d(r) array // angle i, atom j, coordinate k for (i = 0; i < 3; i++) for (j = 0; j < 4; j++) for (k = 0; k < 3; k++) dthetadr[i][j][k] = 0.0; // angle ABC sc1 = sqrt(1.0/(1.0 - costhABC*costhABC)); t1 = costhABC / rABmag2; t3 = costhABC / rBCmag2; r12 = 1.0 / (rAB * rBC); dthetadr[0][0][0] = sc1 * ((t1 * delxAB) - (delxBC * r12)); dthetadr[0][0][1] = sc1 * ((t1 * delyAB) - (delyBC * r12)); dthetadr[0][0][2] = sc1 * ((t1 * delzAB) - (delzBC * r12)); dthetadr[0][1][0] = sc1 * ((-t1 * delxAB) + (delxBC * r12) + (-t3 * delxBC) + (delxAB * r12)); dthetadr[0][1][1] = sc1 * ((-t1 * delyAB) + (delyBC * r12) + (-t3 * delyBC) + (delyAB * r12)); dthetadr[0][1][2] = sc1 * ((-t1 * delzAB) + (delzBC * r12) + (-t3 * delzBC) + (delzAB * r12)); dthetadr[0][2][0] = sc1 * ((t3 * delxBC) - (delxAB * r12)); dthetadr[0][2][1] = sc1 * ((t3 * delyBC) - (delyAB * r12)); dthetadr[0][2][2] = sc1 * ((t3 * delzBC) - (delzAB * r12)); // angle CBD sc1 = sqrt(1.0/(1.0 - costhCBD*costhCBD)); t1 = costhCBD / rBCmag2; t3 = costhCBD / rBDmag2; r12 = 1.0 / (rBC * rBD); dthetadr[1][2][0] = sc1 * ((t1 * delxBC) - (delxBD * r12)); dthetadr[1][2][1] = sc1 * ((t1 * delyBC) - (delyBD * r12)); dthetadr[1][2][2] = sc1 * ((t1 * delzBC) - (delzBD * r12)); dthetadr[1][1][0] = sc1 * ((-t1 * delxBC) + (delxBD * r12) + (-t3 * delxBD) + (delxBC * r12)); dthetadr[1][1][1] = sc1 * ((-t1 * delyBC) + (delyBD * r12) + (-t3 * delyBD) + (delyBC * r12)); dthetadr[1][1][2] = sc1 * ((-t1 * delzBC) + (delzBD * r12) + (-t3 * delzBD) + (delzBC * r12)); dthetadr[1][3][0] = sc1 * ((t3 * delxBD) - (delxBC * r12)); dthetadr[1][3][1] = sc1 * ((t3 * delyBD) - (delyBC * r12)); dthetadr[1][3][2] = sc1 * ((t3 * delzBD) - (delzBC * r12)); // angle ABD sc1 = sqrt(1.0/(1.0 - costhABD*costhABD)); t1 = costhABD / rABmag2; t3 = costhABD / rBDmag2; r12 = 1.0 / (rAB * rBD); dthetadr[2][0][0] = sc1 * ((t1 * delxAB) - (delxBD * r12)); dthetadr[2][0][1] = sc1 * ((t1 * delyAB) - (delyBD * r12)); dthetadr[2][0][2] = sc1 * ((t1 * delzAB) - (delzBD * r12)); dthetadr[2][1][0] = sc1 * ((-t1 * delxAB) + (delxBD * r12) + (-t3 * delxBD) + (delxAB * r12)); dthetadr[2][1][1] = sc1 * ((-t1 * delyAB) + (delyBD * r12) + (-t3 * delyBD) + (delyAB * r12)); dthetadr[2][1][2] = sc1 * ((-t1 * delzAB) + (delzBD * r12) + (-t3 * delzBD) + (delzAB * r12)); dthetadr[2][3][0] = sc1 * ((t3 * delxBD) - (delxAB * r12)); dthetadr[2][3][1] = sc1 * ((t3 * delyBD) - (delyAB * r12)); dthetadr[2][3][2] = sc1 * ((t3 * delzBD) - (delzAB * r12)); // angleangle forces for (i = 0; i < 4; i++) for (j = 0; j < 3; j++) fabcd[i][j] = - ((aa_k1[type] * (dthABC*dthetadr[1][i][j] + dthCBD*dthetadr[0][i][j])) + (aa_k2[type] * (dthABC*dthetadr[2][i][j] + dthABD*dthetadr[0][i][j])) + (aa_k3[type] * (dthABD*dthetadr[1][i][j] + dthCBD*dthetadr[2][i][j]))); // apply force to each of 4 atoms if (newton_bond || i1 < nlocal) { f[i1][0] += fabcd[0][0]; f[i1][1] += fabcd[0][1]; f[i1][2] += fabcd[0][2]; } if (newton_bond || i2 < nlocal) { f[i2][0] += fabcd[1][0]; f[i2][1] += fabcd[1][1]; f[i2][2] += fabcd[1][2]; } if (newton_bond || i3 < nlocal) { f[i3][0] += fabcd[2][0]; f[i3][1] += fabcd[2][1]; f[i3][2] += fabcd[2][2]; } if (newton_bond || i4 < nlocal) { f[i4][0] += fabcd[3][0]; f[i4][1] += fabcd[3][1]; f[i4][2] += fabcd[3][2]; } if (evflag) ev_tally(i1,i2,i3,i4,nlocal,newton_bond,eimproper, fabcd[0],fabcd[2],fabcd[3], delxAB,delyAB,delzAB,delxBC,delyBC,delzBC,delxBD,delyBD,delzBD); } } /* ---------------------------------------------------------------------- cross product: c = a x b ------------------------------------------------------------------------- */ void ImproperClass2::cross(double *a, double *b, double *c) { c[0] = a[1]*b[2] - a[2]*b[1]; c[1] = a[2]*b[0] - a[0]*b[2]; c[2] = a[0]*b[1] - a[1]*b[0]; } /* ---------------------------------------------------------------------- dot product of a dot b ------------------------------------------------------------------------- */ double ImproperClass2::dot(double *a, double *b) { return (a[0]*b[0] + a[1]*b[1] + a[2]*b[2]); } diff --git a/src/COLLOID/atom_vec_colloid.cpp b/src/COLLOID/atom_vec_colloid.cpp index 3c13ecde0..0ba21a735 100644 --- a/src/COLLOID/atom_vec_colloid.cpp +++ b/src/COLLOID/atom_vec_colloid.cpp @@ -1,703 +1,706 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ #include "stdlib.h" #include "atom_vec_colloid.h" +#include "lmptype.h" #include "atom.h" #include "force.h" #include "domain.h" #include "modify.h" #include "fix.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; #define DELTA 10000 /* ---------------------------------------------------------------------- */ AtomVecColloid::AtomVecColloid(LAMMPS *lmp, int narg, char **arg) : AtomVec(lmp, narg, arg) { molecular = 0; mass_type = 1; shape_type = 1; comm_x_only = 1; comm_f_only = 0; size_forward = 3; size_reverse = 6; size_border = 6; size_velocity = 6; size_data_atom = 5; size_data_vel = 7; xcol_data = 3; atom->omega_flag = atom->torque_flag = 1; } /* ---------------------------------------------------------------------- grow atom arrays n = 0 grows arrays by DELTA n > 0 allocates arrays to size n ------------------------------------------------------------------------- */ void AtomVecColloid::grow(int n) { if (n == 0) nmax += DELTA; else nmax = n; atom->nmax = nmax; + if (nmax < 0 || nmax > MAXSMALLINT) + error->one("Per-processor system is too big"); tag = atom->tag = (int *) memory->srealloc(atom->tag,nmax*sizeof(int),"atom:tag"); type = atom->type = (int *) memory->srealloc(atom->type,nmax*sizeof(int),"atom:type"); mask = atom->mask = (int *) memory->srealloc(atom->mask,nmax*sizeof(int),"atom:mask"); image = atom->image = (int *) memory->srealloc(atom->image,nmax*sizeof(int),"atom:image"); x = atom->x = memory->grow_2d_double_array(atom->x,nmax,3,"atom:x"); v = atom->v = memory->grow_2d_double_array(atom->v,nmax,3,"atom:v"); f = atom->f = memory->grow_2d_double_array(atom->f,nmax,3,"atom:f"); omega = atom->omega = memory->grow_2d_double_array(atom->omega,nmax,3,"atom:omega"); torque = atom->torque = memory->grow_2d_double_array(atom->torque,nmax,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 AtomVecColloid::grow_reset() { tag = atom->tag; type = atom->type; mask = atom->mask; image = atom->image; x = atom->x; v = atom->v; f = atom->f; omega = atom->omega; torque = atom->torque; } /* ---------------------------------------------------------------------- */ void AtomVecColloid::copy(int i, int j) { 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]; 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); } /* ---------------------------------------------------------------------- */ int AtomVecColloid::pack_comm(int n, int *list, double *buf, int pbc_flag, int *pbc) { int i,j,m; double dx,dy,dz; m = 0; if (pbc_flag == 0) { for (i = 0; i < n; i++) { j = list[i]; buf[m++] = x[j][0]; buf[m++] = x[j][1]; buf[m++] = x[j][2]; } } else { if (domain->triclinic == 0) { dx = pbc[0]*domain->xprd; dy = pbc[1]*domain->yprd; dz = pbc[2]*domain->zprd; } else { dx = pbc[0]*domain->xprd + pbc[5]*domain->xy + pbc[4]*domain->xz; dy = pbc[1]*domain->yprd + pbc[3]*domain->yz; dz = pbc[2]*domain->zprd; } for (i = 0; i < n; i++) { j = list[i]; buf[m++] = x[j][0] + dx; buf[m++] = x[j][1] + dy; buf[m++] = x[j][2] + dz; } } return m; } /* ---------------------------------------------------------------------- */ int AtomVecColloid::pack_comm_vel(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++] = 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; } 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]; } } return m; } /* ---------------------------------------------------------------------- */ void AtomVecColloid::unpack_comm(int n, int first, double *buf) { int i,m,last; m = 0; last = first + n; for (i = first; i < last; i++) { x[i][0] = buf[m++]; x[i][1] = buf[m++]; x[i][2] = buf[m++]; } } /* ---------------------------------------------------------------------- */ void AtomVecColloid::unpack_comm_vel(int n, int first, double *buf) { int i,m,last; m = 0; last = first + n; for (i = first; i < last; i++) { x[i][0] = buf[m++]; x[i][1] = buf[m++]; x[i][2] = buf[m++]; v[i][0] = buf[m++]; v[i][1] = buf[m++]; v[i][2] = buf[m++]; omega[i][0] = buf[m++]; omega[i][1] = buf[m++]; omega[i][2] = buf[m++]; } } /* ---------------------------------------------------------------------- */ int AtomVecColloid::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 AtomVecColloid::pack_reverse_one(int i, double *buf) { buf[0] = torque[i][0]; buf[1] = torque[i][1]; buf[2] = torque[i][2]; return 3; } /* ---------------------------------------------------------------------- */ void AtomVecColloid::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 AtomVecColloid::unpack_reverse_one(int i, double *buf) { torque[i][0] += buf[0]; torque[i][1] += buf[1]; torque[i][2] += buf[2]; return 3; } /* ---------------------------------------------------------------------- */ int AtomVecColloid::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]; } } 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]; } } return m; } /* ---------------------------------------------------------------------- */ int AtomVecColloid::pack_border_vel(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++] = 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]; } 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++] = 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; } /* ---------------------------------------------------------------------- */ void AtomVecColloid::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++]); } } /* ---------------------------------------------------------------------- */ void AtomVecColloid::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++]); 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++]; } } /* ---------------------------------------------------------------------- pack data for atom I for sending to another proc xyz must be 1st 3 values, so comm::exchange() can test on them ------------------------------------------------------------------------- */ int AtomVecColloid::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]; buf[m++] = image[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 AtomVecColloid::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] = static_cast<int> (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 AtomVecColloid::size_restart() { int i; int nlocal = atom->nlocal; int n = 14 * 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 AtomVecColloid::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]; buf[m++] = image[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]; 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 AtomVecColloid::unpack_restart(double *buf) { int nlocal = atom->nlocal; if (nlocal == nmax) { grow(0); if (atom->nextra_store) atom->extra = memory->grow_2d_double_array(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] = static_cast<int> (buf[m++]); v[nlocal][0] = buf[m++]; v[nlocal][1] = buf[m++]; v[nlocal][2] = 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 AtomVecColloid::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] = (512 << 20) | (512 << 10) | 512; 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 one line from Atoms section of data file initialize other atom quantities ------------------------------------------------------------------------- */ void AtomVecColloid::data_atom(double *coord, int imagetmp, char **values) { int nlocal = atom->nlocal; if (nlocal == nmax) grow(0); tag[nlocal] = atoi(values[0]); if (tag[nlocal] <= 0) error->one("Invalid atom ID in Atoms section of data file"); type[nlocal] = atoi(values[1]); if (type[nlocal] <= 0 || type[nlocal] > atom->ntypes) error->one("Invalid atom type in Atoms section of data file"); x[nlocal][0] = coord[0]; x[nlocal][1] = coord[1]; x[nlocal][2] = coord[2]; image[nlocal] = imagetmp; mask[nlocal] = 1; v[nlocal][0] = 0.0; v[nlocal][1] = 0.0; v[nlocal][2] = 0.0; omega[nlocal][0] = 0.0; omega[nlocal][1] = 0.0; omega[nlocal][2] = 0.0; atom->nlocal++; } /* ---------------------------------------------------------------------- unpack one line from Velocities section of data file ------------------------------------------------------------------------- */ void AtomVecColloid::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 AtomVecColloid::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; } /* ---------------------------------------------------------------------- return # of bytes of allocated memory ------------------------------------------------------------------------- */ double AtomVecColloid::memory_usage() { double bytes = 0.0; if (atom->memcheck("tag")) bytes += nmax * sizeof(int); if (atom->memcheck("type")) bytes += nmax * sizeof(int); if (atom->memcheck("mask")) bytes += nmax * sizeof(int); if (atom->memcheck("image")) bytes += nmax * sizeof(int); if (atom->memcheck("x")) bytes += nmax*3 * sizeof(double); if (atom->memcheck("v")) bytes += nmax*3 * sizeof(double); if (atom->memcheck("f")) bytes += nmax*3 * sizeof(double); if (atom->memcheck("omega")) bytes += nmax*3 * sizeof(double); if (atom->memcheck("torque")) bytes += nmax*3 * sizeof(double); return bytes; } diff --git a/src/DIPOLE/atom_vec_dipole.cpp b/src/DIPOLE/atom_vec_dipole.cpp index f3935ccce..cc81711b4 100644 --- a/src/DIPOLE/atom_vec_dipole.cpp +++ b/src/DIPOLE/atom_vec_dipole.cpp @@ -1,837 +1,840 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ #include "stdlib.h" #include "atom_vec_dipole.h" +#include "lmptype.h" #include "atom.h" #include "domain.h" #include "modify.h" #include "fix.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; #define DELTA 10000 /* ---------------------------------------------------------------------- */ AtomVecDipole::AtomVecDipole(LAMMPS *lmp, int narg, char **arg) : AtomVec(lmp, narg, arg) { molecular = 0; mass_type = 1; shape_type = 1; dipole_type = 1; comm_x_only = comm_f_only = 0; size_forward = 6; size_reverse = 6; size_border = 10; size_velocity = 6; size_data_atom = 9; size_data_vel = 7; xcol_data = 4; atom->q_flag = atom->mu_flag = atom->omega_flag = atom->torque_flag = 1; } /* ---------------------------------------------------------------------- grow atom arrays n = 0 grows arrays by DELTA n > 0 allocates arrays to size n ------------------------------------------------------------------------- */ void AtomVecDipole::grow(int n) { if (n == 0) nmax += DELTA; else nmax = n; atom->nmax = nmax; + if (nmax < 0 || nmax > MAXSMALLINT) + error->one("Per-processor system is too big"); tag = atom->tag = (int *) memory->srealloc(atom->tag,nmax*sizeof(int),"atom:tag"); type = atom->type = (int *) memory->srealloc(atom->type,nmax*sizeof(int),"atom:type"); mask = atom->mask = (int *) memory->srealloc(atom->mask,nmax*sizeof(int),"atom:mask"); image = atom->image = (int *) memory->srealloc(atom->image,nmax*sizeof(int),"atom:image"); x = atom->x = memory->grow_2d_double_array(atom->x,nmax,3,"atom:x"); v = atom->v = memory->grow_2d_double_array(atom->v,nmax,3,"atom:v"); f = atom->f = memory->grow_2d_double_array(atom->f,nmax,3,"atom:f"); q = atom->q = (double *) memory->srealloc(atom->q,nmax*sizeof(double),"atom:q"); mu = atom->mu = memory->grow_2d_double_array(atom->mu,nmax,3,"atom:mu"); omega = atom->omega = memory->grow_2d_double_array(atom->omega,nmax,3,"atom:omega"); torque = atom->torque = memory->grow_2d_double_array(atom->torque,nmax,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 AtomVecDipole::grow_reset() { tag = atom->tag; type = atom->type; mask = atom->mask; image = atom->image; x = atom->x; v = atom->v; f = atom->f; q = atom->q; mu = atom->mu; omega = atom->omega; torque = atom->torque; } /* ---------------------------------------------------------------------- */ void AtomVecDipole::copy(int i, int j) { tag[j] = tag[i]; type[j] = type[i]; mask[j] = mask[i]; image[j] = image[i]; x[j][0] = x[i][0]; x[j][1] = x[i][1]; x[j][2] = x[i][2]; v[j][0] = v[i][0]; v[j][1] = v[i][1]; v[j][2] = v[i][2]; q[j] = q[i]; mu[j][0] = mu[i][0]; mu[j][1] = mu[i][1]; mu[j][2] = mu[i][2]; 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); } /* ---------------------------------------------------------------------- */ int AtomVecDipole::pack_comm(int n, int *list, double *buf, int pbc_flag, int *pbc) { int i,j,m; double dx,dy,dz; m = 0; if (pbc_flag == 0) { for (i = 0; i < n; i++) { j = list[i]; buf[m++] = x[j][0]; buf[m++] = x[j][1]; buf[m++] = x[j][2]; buf[m++] = mu[j][0]; buf[m++] = mu[j][1]; buf[m++] = mu[j][2]; } } else { if (domain->triclinic == 0) { dx = pbc[0]*domain->xprd; dy = pbc[1]*domain->yprd; dz = pbc[2]*domain->zprd; } else { dx = pbc[0]*domain->xprd + pbc[5]*domain->xy + pbc[4]*domain->xz; dy = pbc[1]*domain->yprd + pbc[3]*domain->yz; dz = pbc[2]*domain->zprd; } for (i = 0; i < n; i++) { j = list[i]; buf[m++] = x[j][0] + dx; buf[m++] = x[j][1] + dy; buf[m++] = x[j][2] + dz; buf[m++] = mu[j][0]; buf[m++] = mu[j][1]; buf[m++] = mu[j][2]; } } return m; } /* ---------------------------------------------------------------------- */ int AtomVecDipole::pack_comm_vel(int n, int *list, double *buf, int pbc_flag, int *pbc) { int i,j,m; double dx,dy,dz; m = 0; if (pbc_flag == 0) { for (i = 0; i < n; i++) { j = list[i]; buf[m++] = x[j][0]; buf[m++] = x[j][1]; buf[m++] = x[j][2]; buf[m++] = mu[j][0]; buf[m++] = mu[j][1]; buf[m++] = mu[j][2]; buf[m++] = v[j][0]; buf[m++] = v[j][1]; buf[m++] = v[j][2]; 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; } for (i = 0; i < n; i++) { j = list[i]; buf[m++] = x[j][0] + dx; buf[m++] = x[j][1] + dy; buf[m++] = x[j][2] + dz; buf[m++] = mu[j][0]; buf[m++] = mu[j][1]; buf[m++] = mu[j][2]; buf[m++] = v[j][0]; buf[m++] = v[j][1]; buf[m++] = v[j][2]; buf[m++] = omega[j][0]; buf[m++] = omega[j][1]; buf[m++] = omega[j][2]; } } return m; } /* ---------------------------------------------------------------------- */ int AtomVecDipole::pack_comm_one(int i, double *buf) { buf[0] = mu[i][0]; buf[1] = mu[i][1]; buf[2] = mu[i][2]; return 3; } /* ---------------------------------------------------------------------- */ void AtomVecDipole::unpack_comm(int n, int first, double *buf) { int i,m,last; m = 0; last = first + n; for (i = first; i < last; i++) { x[i][0] = buf[m++]; x[i][1] = buf[m++]; x[i][2] = buf[m++]; mu[i][0] = buf[m++]; mu[i][1] = buf[m++]; mu[i][2] = buf[m++]; } } /* ---------------------------------------------------------------------- */ void AtomVecDipole::unpack_comm_vel(int n, int first, double *buf) { int i,m,last; m = 0; last = first + n; for (i = first; i < last; i++) { x[i][0] = buf[m++]; x[i][1] = buf[m++]; x[i][2] = buf[m++]; mu[i][0] = buf[m++]; mu[i][1] = buf[m++]; mu[i][2] = buf[m++]; v[i][0] = buf[m++]; v[i][1] = buf[m++]; v[i][2] = buf[m++]; omega[i][0] = buf[m++]; omega[i][1] = buf[m++]; omega[i][2] = buf[m++]; } } /* ---------------------------------------------------------------------- */ int AtomVecDipole::unpack_comm_one(int i, double *buf) { mu[i][0] = buf[0]; mu[i][1] = buf[1]; mu[i][2] = buf[2]; return 3; } /* ---------------------------------------------------------------------- */ int AtomVecDipole::pack_reverse(int n, int first, double *buf) { int i,m,last; m = 0; last = first + n; for (i = first; i < last; i++) { buf[m++] = f[i][0]; buf[m++] = f[i][1]; buf[m++] = f[i][2]; buf[m++] = torque[i][0]; buf[m++] = torque[i][1]; buf[m++] = torque[i][2]; } return m; } /* ---------------------------------------------------------------------- */ int AtomVecDipole::pack_reverse_one(int i, double *buf) { buf[0] = torque[i][0]; buf[1] = torque[i][1]; buf[2] = torque[i][2]; return 3; } /* ---------------------------------------------------------------------- */ void AtomVecDipole::unpack_reverse(int n, int *list, double *buf) { int i,j,m; m = 0; for (i = 0; i < n; i++) { j = list[i]; f[j][0] += buf[m++]; f[j][1] += buf[m++]; f[j][2] += buf[m++]; torque[j][0] += buf[m++]; torque[j][1] += buf[m++]; torque[j][2] += buf[m++]; } } /* ---------------------------------------------------------------------- */ int AtomVecDipole::unpack_reverse_one(int i, double *buf) { torque[i][0] += buf[0]; torque[i][1] += buf[1]; torque[i][2] += buf[2]; return 3; } /* ---------------------------------------------------------------------- */ int AtomVecDipole::pack_border(int n, int *list, double *buf, int pbc_flag, int *pbc) { int i,j,m; double dx,dy,dz; m = 0; if (pbc_flag == 0) { for (i = 0; i < n; i++) { j = list[i]; buf[m++] = x[j][0]; buf[m++] = x[j][1]; buf[m++] = x[j][2]; buf[m++] = tag[j]; buf[m++] = type[j]; buf[m++] = mask[j]; buf[m++] = q[j]; buf[m++] = mu[j][0]; buf[m++] = mu[j][1]; buf[m++] = mu[j][2]; } } else { if (domain->triclinic == 0) { dx = pbc[0]*domain->xprd; dy = pbc[1]*domain->yprd; dz = pbc[2]*domain->zprd; } else { dx = pbc[0]; 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++] = q[j]; buf[m++] = mu[j][0]; buf[m++] = mu[j][1]; buf[m++] = mu[j][2]; } } return m; } /* ---------------------------------------------------------------------- */ int AtomVecDipole::pack_border_vel(int n, int *list, double *buf, int pbc_flag, int *pbc) { int i,j,m; double dx,dy,dz; 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++] = q[j]; buf[m++] = mu[j][0]; buf[m++] = mu[j][1]; buf[m++] = mu[j][2]; buf[m++] = v[j][0]; buf[m++] = v[j][1]; buf[m++] = v[j][2]; 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]; } 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++] = q[j]; buf[m++] = mu[j][0]; buf[m++] = mu[j][1]; buf[m++] = mu[j][2]; buf[m++] = v[j][0]; buf[m++] = v[j][1]; buf[m++] = v[j][2]; buf[m++] = omega[j][0]; buf[m++] = omega[j][1]; buf[m++] = omega[j][2]; } } return m; } /* ---------------------------------------------------------------------- */ int AtomVecDipole::pack_border_one(int i, double *buf) { buf[0] = q[i]; buf[1] = mu[i][0]; buf[2] = mu[i][1]; buf[3] = mu[i][2]; return 4; } /* ---------------------------------------------------------------------- */ void AtomVecDipole::unpack_border(int n, int first, double *buf) { int i,m,last; m = 0; last = first + n; for (i = first; i < last; i++) { if (i == nmax) grow(0); x[i][0] = buf[m++]; x[i][1] = buf[m++]; x[i][2] = buf[m++]; tag[i] = static_cast<int> (buf[m++]); type[i] = static_cast<int> (buf[m++]); mask[i] = static_cast<int> (buf[m++]); q[i] = buf[m++]; mu[i][0] = buf[m++]; mu[i][1] = buf[m++]; mu[i][2] = buf[m++]; } } /* ---------------------------------------------------------------------- */ void AtomVecDipole::unpack_border_vel(int n, int first, double *buf) { int i,m,last; m = 0; last = first + n; for (i = first; i < last; i++) { if (i == nmax) grow(0); x[i][0] = buf[m++]; x[i][1] = buf[m++]; x[i][2] = buf[m++]; tag[i] = static_cast<int> (buf[m++]); type[i] = static_cast<int> (buf[m++]); mask[i] = static_cast<int> (buf[m++]); q[i] = buf[m++]; mu[i][0] = buf[m++]; mu[i][1] = buf[m++]; mu[i][2] = buf[m++]; v[i][0] = buf[m++]; v[i][1] = buf[m++]; v[i][2] = buf[m++]; omega[i][0] = buf[m++]; omega[i][1] = buf[m++]; omega[i][2] = buf[m++]; } } /* ---------------------------------------------------------------------- */ int AtomVecDipole::unpack_border_one(int i, double *buf) { q[i] = buf[0]; mu[i][0] = buf[1]; mu[i][1] = buf[2]; mu[i][2] = buf[3]; return 4; } /* ---------------------------------------------------------------------- pack all atom quantities for shipping to another proc xyz must be 1st 3 values, so that comm::exchange can test on them ------------------------------------------------------------------------- */ int AtomVecDipole::pack_exchange(int i, double *buf) { int m = 1; buf[m++] = x[i][0]; buf[m++] = x[i][1]; buf[m++] = x[i][2]; buf[m++] = v[i][0]; buf[m++] = v[i][1]; buf[m++] = v[i][2]; buf[m++] = tag[i]; buf[m++] = type[i]; buf[m++] = mask[i]; buf[m++] = image[i]; buf[m++] = q[i]; buf[m++] = mu[i][0]; buf[m++] = mu[i][1]; buf[m++] = mu[i][2]; 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 AtomVecDipole::unpack_exchange(double *buf) { int nlocal = atom->nlocal; if (nlocal == nmax) grow(0); int m = 1; x[nlocal][0] = buf[m++]; x[nlocal][1] = buf[m++]; x[nlocal][2] = buf[m++]; v[nlocal][0] = buf[m++]; v[nlocal][1] = buf[m++]; v[nlocal][2] = buf[m++]; tag[nlocal] = static_cast<int> (buf[m++]); type[nlocal] = static_cast<int> (buf[m++]); mask[nlocal] = static_cast<int> (buf[m++]); image[nlocal] = static_cast<int> (buf[m++]); q[nlocal] = buf[m++]; mu[nlocal][0] = buf[m++]; mu[nlocal][1] = buf[m++]; mu[nlocal][2] = 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 AtomVecDipole::size_restart() { int i; int nlocal = atom->nlocal; int n = 18 * nlocal; if (atom->nextra_restart) for (int iextra = 0; iextra < atom->nextra_restart; iextra++) for (i = 0; i < nlocal; i++) n += modify->fix[atom->extra_restart[iextra]]->size_restart(i); return n; } /* ---------------------------------------------------------------------- pack atom I's data for restart file including extra quantities xyz must be 1st 3 values, so that read_restart can test on them molecular types may be negative, but write as positive ------------------------------------------------------------------------- */ int AtomVecDipole::pack_restart(int i, double *buf) { int m = 1; buf[m++] = x[i][0]; buf[m++] = x[i][1]; buf[m++] = x[i][2]; buf[m++] = tag[i]; buf[m++] = type[i]; buf[m++] = mask[i]; buf[m++] = image[i]; buf[m++] = v[i][0]; buf[m++] = v[i][1]; buf[m++] = v[i][2]; buf[m++] = q[i]; buf[m++] = mu[i][0]; buf[m++] = mu[i][1]; buf[m++] = mu[i][2]; buf[m++] = 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 AtomVecDipole::unpack_restart(double *buf) { int nlocal = atom->nlocal; if (nlocal == nmax) { grow(0); if (atom->nextra_store) atom->extra = memory->grow_2d_double_array(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] = static_cast<int> (buf[m++]); v[nlocal][0] = buf[m++]; v[nlocal][1] = buf[m++]; v[nlocal][2] = buf[m++]; q[nlocal] = buf[m++]; mu[nlocal][0] = buf[m++]; mu[nlocal][1] = buf[m++]; mu[nlocal][2] = buf[m++]; 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 AtomVecDipole::create_atom(int itype, double *coord) { int nlocal = atom->nlocal; if (nlocal == nmax) grow(0); tag[nlocal] = 0; type[nlocal] = itype; x[nlocal][0] = coord[0]; x[nlocal][1] = coord[1]; x[nlocal][2] = coord[2]; mask[nlocal] = 1; image[nlocal] = (512 << 20) | (512 << 10) | 512; v[nlocal][0] = 0.0; v[nlocal][1] = 0.0; v[nlocal][2] = 0.0; q[nlocal] = 0.0; mu[nlocal][0] = 0.0; mu[nlocal][1] = 0.0; mu[nlocal][2] = 0.0; 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 AtomVecDipole::data_atom(double *coord, int imagetmp, char **values) { int nlocal = atom->nlocal; if (nlocal == nmax) grow(0); tag[nlocal] = atoi(values[0]); if (tag[nlocal] <= 0) error->one("Invalid atom ID in Atoms section of data file"); type[nlocal] = atoi(values[1]); if (type[nlocal] <= 0 || type[nlocal] > atom->ntypes) error->one("Invalid atom type in Atoms section of data file"); q[nlocal] = atof(values[2]); x[nlocal][0] = coord[0]; x[nlocal][1] = coord[1]; x[nlocal][2] = coord[2]; mu[nlocal][0] = atof(values[6]); mu[nlocal][1] = atof(values[7]); mu[nlocal][2] = atof(values[8]); 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 AtomVecDipole::data_atom_hybrid(int nlocal, char **values) { q[nlocal] = atof(values[0]); mu[nlocal][0] = atof(values[1]); mu[nlocal][1] = atof(values[2]); mu[nlocal][2] = atof(values[3]); return 4; } /* ---------------------------------------------------------------------- unpack one line from Velocities section of data file ------------------------------------------------------------------------- */ void AtomVecDipole::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 AtomVecDipole::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; } /* ---------------------------------------------------------------------- return # of bytes of allocated memory ------------------------------------------------------------------------- */ double AtomVecDipole::memory_usage() { double bytes = 0.0; if (atom->memcheck("tag")) bytes += nmax * sizeof(int); if (atom->memcheck("type")) bytes += nmax * sizeof(int); if (atom->memcheck("mask")) bytes += nmax * sizeof(int); if (atom->memcheck("image")) bytes += nmax * sizeof(int); if (atom->memcheck("x")) bytes += nmax*3 * sizeof(double); if (atom->memcheck("v")) bytes += nmax*3 * sizeof(double); if (atom->memcheck("f")) bytes += nmax*3 * sizeof(double); if (atom->memcheck("q")) bytes += nmax * sizeof(double); if (atom->memcheck("mu")) bytes += nmax*3 * sizeof(double); if (atom->memcheck("omega")) bytes += nmax*3 * sizeof(double); if (atom->memcheck("torque")) bytes += nmax*3 * sizeof(double); return bytes; } diff --git a/src/GPU/pair_cg_cmm_coul_long_gpu.cpp b/src/GPU/pair_cg_cmm_coul_long_gpu.cpp index 8c7825f31..6d7477577 100644 --- a/src/GPU/pair_cg_cmm_coul_long_gpu.cpp +++ b/src/GPU/pair_cg_cmm_coul_long_gpu.cpp @@ -1,499 +1,504 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- Contributing author: Mike Brown (SNL) ------------------------------------------------------------------------- */ #include "math.h" #include "stdio.h" #include "stdlib.h" #include "pair_cg_cmm_coul_long_gpu.h" +#include "lmptype.h" #include "atom.h" #include "atom_vec.h" #include "comm.h" #include "force.h" #include "neighbor.h" #include "neigh_list.h" #include "integrate.h" #include "memory.h" #include "error.h" #include "neigh_request.h" #include "universe.h" #include "update.h" #include "domain.h" #include "string.h" #include "kspace.h" #define MIN(a,b) ((a) < (b) ? (a) : (b)) #define MAX(a,b) ((a) > (b) ? (a) : (b)) #define EWALD_F 1.12837917 #define EWALD_P 0.3275911 #define A1 0.254829592 #define A2 -0.284496736 #define A3 1.421413741 #define A4 -1.453152027 #define A5 1.061405429 // External functions from cuda library for atom decomposition bool cmml_gpu_init(const int ntypes, double **cutsq, int **cg_type, double **host_lj1, double **host_lj2, double **host_lj3, double **host_lj4, double **offset, double *special_lj, const int nlocal, const int nall, const int max_nbors, const int maxspecial, const double cell_size, int &gpu_mode, FILE *screen, double **host_cut_ljsq, double host_cut_coulsq, double *host_special_coul, const double qqrd2e, const double g_ewald); void cmml_gpu_clear(); int * cmml_gpu_compute_n(const int timestep, const int ago, const int inum, const int nall, double **host_x, int *host_type, double *boxlo, double *boxhi, int *tag, int **nspecial, int **special, const bool eflag, const bool vflag, const bool eatom, const bool vatom, int &host_start, const double cpu_time, bool &success, double *host_q); void cmml_gpu_compute(const int timestep, const int ago, const int inum, const int nall, double **host_x, int *host_type, int *ilist, int *numj, int **firstneigh, const bool eflag, const bool vflag, const bool eatom, const bool vatom, int &host_start, const double cpu_time, bool &success, double *host_q); double cmml_gpu_bytes(); using namespace LAMMPS_NS; /* ---------------------------------------------------------------------- */ PairCGCMMCoulLongGPU::PairCGCMMCoulLongGPU(LAMMPS *lmp) : PairCGCMMCoulLong(lmp), gpu_mode(GPU_PAIR) { respa_enable = 0; cpu_time = 0.0; } /* ---------------------------------------------------------------------- free all arrays ------------------------------------------------------------------------- */ PairCGCMMCoulLongGPU::~PairCGCMMCoulLongGPU() { cmml_gpu_clear(); } /* ---------------------------------------------------------------------- */ void PairCGCMMCoulLongGPU::compute(int eflag, int vflag) { + if (update->ntimestep > MAXSMALLINT) + error->all("Timestep too big for GPU pair style"); + int ntimestep = update->ntimestep; + if (eflag || vflag) ev_setup(eflag,vflag); else evflag = vflag_fdotr = 0; int nall = atom->nlocal + atom->nghost; int inum, host_start; bool success = true; if (gpu_mode == GPU_NEIGH) { inum = atom->nlocal; - gpulist = cmml_gpu_compute_n(update->ntimestep, neighbor->ago, inum, nall, + gpulist = cmml_gpu_compute_n(ntimestep, neighbor->ago, inum, nall, atom->x, atom->type, domain->sublo, domain->subhi, atom->tag, atom->nspecial, atom->special, eflag, vflag, eflag_atom, vflag_atom, host_start, cpu_time, success, atom->q); } else { inum = list->inum; - cmml_gpu_compute(update->ntimestep, neighbor->ago, inum, nall, atom->x, + cmml_gpu_compute(ntimestep, neighbor->ago, inum, nall, atom->x, atom->type, list->ilist, list->numneigh, list->firstneigh, eflag, vflag, eflag_atom, vflag_atom, host_start, cpu_time, success, atom->q); } if (!success) error->one("Out of memory on GPGPU"); if (host_start<inum) { cpu_time = MPI_Wtime(); if (gpu_mode == GPU_NEIGH) cpu_compute(gpulist, host_start, eflag, vflag); else cpu_compute(host_start, eflag, vflag); cpu_time = MPI_Wtime() - cpu_time; } } /* ---------------------------------------------------------------------- init specific to this pair style ------------------------------------------------------------------------- */ void PairCGCMMCoulLongGPU::init_style() { cut_respa = NULL; if (!atom->q_flag) error->all("Pair style cg/cmm/coul/long requires atom attribute q"); if (force->pair_match("gpu",0) == NULL) error->all("Cannot use pair hybrid with multiple GPU pair styles"); // Repeat cutsq calculation because done after call to init_style double maxcut = -1.0; double cut; for (int i = 1; i <= atom->ntypes; i++) { for (int j = i; j <= atom->ntypes; j++) { if (setflag[i][j] != 0 || (setflag[i][i] != 0 && setflag[j][j] != 0)) { cut = init_one(i,j); cut *= cut; if (cut > maxcut) maxcut = cut; cutsq[i][j] = cutsq[j][i] = cut; } else cutsq[i][j] = cutsq[j][i] = 0.0; } } double cell_size = sqrt(maxcut) + neighbor->skin; // insure use of KSpace long-range solver, set g_ewald if (force->kspace == NULL) error->all("Pair style is incompatible with KSpace style"); g_ewald = force->kspace->g_ewald; // setup force tables if (ncoultablebits) init_tables(); int maxspecial=0; if (atom->molecular) maxspecial=atom->maxspecial; bool init_ok = cmml_gpu_init(atom->ntypes+1, cutsq, cg_type, lj1, lj2, lj3, lj4, offset, force->special_lj, atom->nlocal, atom->nlocal+atom->nghost, 300, maxspecial, cell_size, gpu_mode, screen, cut_ljsq, cut_coulsq_global, force->special_coul, force->qqrd2e, g_ewald); if (!init_ok) error->one("Insufficient memory on accelerator (or no fix gpu).\n"); if (force->newton_pair) error->all("Cannot use newton pair with GPU cg/cmm pair style"); if (gpu_mode != GPU_NEIGH) { int irequest = neighbor->request(this); neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->full = 1; } } /* ---------------------------------------------------------------------- */ double PairCGCMMCoulLongGPU::memory_usage() { double bytes = Pair::memory_usage(); return bytes + cmml_gpu_bytes(); } /* ---------------------------------------------------------------------- */ void PairCGCMMCoulLongGPU::cpu_compute(int start, int eflag, int vflag) { int i,j,ii,jj,inum,jnum,itype,jtype,itable; double qtmp,xtmp,ytmp,ztmp,delx,dely,delz; double fraction,table; double r,r2inv,r6inv,forcecoul,forcelj,factor_coul,factor_lj; double grij,expm2,prefactor,t,erfc; int *ilist,*jlist,*numneigh,**firstneigh; double rsq; double **x = atom->x; double **f = atom->f; double *q = atom->q; int *type = atom->type; int nlocal = atom->nlocal; int nall = nlocal + atom->nghost; double *special_coul = force->special_coul; double *special_lj = force->special_lj; double qqrd2e = force->qqrd2e; inum = list->inum; ilist = list->ilist; numneigh = list->numneigh; firstneigh = list->firstneigh; // loop over neighbors of my atoms for (ii = start; ii < inum; ii++) { i = ilist[ii]; qtmp = q[i]; xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; itype = type[i]; jlist = firstneigh[i]; jnum = numneigh[i]; for (jj = 0; jj < jnum; jj++) { j = jlist[jj]; if (j < nall) factor_coul = factor_lj = 1.0; else { factor_coul = special_coul[j/nall]; factor_lj = special_lj[j/nall]; j %= nall; } const double delx = xtmp - x[j][0]; const double dely = ytmp - x[j][1]; const double delz = ztmp - x[j][2]; const double rsq = delx*delx + dely*dely + delz*delz; const int jtype = type[j]; double evdwl = 0.0; double ecoul = 0.0; double fpair = 0.0; if (rsq < cutsq[itype][jtype]) { const double r2inv = 1.0/rsq; const int cgt=cg_type[itype][jtype]; double forcelj = 0.0; double forcecoul = 0.0; if (rsq < cut_ljsq[itype][jtype]) { forcelj=factor_lj; if (eflag) evdwl=factor_lj; if (cgt == CG_LJ12_4) { const double r4inv=r2inv*r2inv; forcelj *= r4inv*(lj1[itype][jtype]*r4inv*r4inv - lj2[itype][jtype]); if (eflag) { evdwl *= r4inv*(lj3[itype][jtype]*r4inv*r4inv - lj4[itype][jtype]) - offset[itype][jtype]; } } else if (cgt == CG_LJ9_6) { const double r3inv = r2inv*sqrt(r2inv); const double r6inv = r3inv*r3inv; forcelj *= r6inv*(lj1[itype][jtype]*r3inv - lj2[itype][jtype]); if (eflag) { evdwl *= r6inv*(lj3[itype][jtype]*r3inv - lj4[itype][jtype]) - offset[itype][jtype]; } } else { const double r6inv = r2inv*r2inv*r2inv; forcelj *= r6inv*(lj1[itype][jtype]*r6inv - lj2[itype][jtype]); if (eflag) { evdwl *= r6inv*(lj3[itype][jtype]*r6inv - lj4[itype][jtype]) - offset[itype][jtype]; } } } if (rsq < cut_coulsq_global) { if (!ncoultablebits || rsq <= tabinnersq) { const double r = sqrt(rsq); const double grij = g_ewald * r; const double expm2 = exp(-grij*grij); const double t = 1.0 / (1.0 + EWALD_P*grij); const double erfc = t * (A1+t*(A2+t*(A3+t*(A4+t*A5)))) * expm2; const double prefactor = qqrd2e * qtmp*q[j]/r; forcecoul = prefactor * (erfc + EWALD_F*grij*expm2); if (eflag) ecoul = prefactor*erfc; if (factor_coul < 1.0) { forcecoul -= (1.0-factor_coul)*prefactor; if (eflag) ecoul -= (1.0-factor_coul)*prefactor; } } else { union_int_float_t rsq_lookup; rsq_lookup.f = rsq; int itable = rsq_lookup.i & ncoulmask; itable >>= ncoulshiftbits; const double fraction = (rsq_lookup.f - rtable[itable]) * drtable[itable]; const double table = ftable[itable] + fraction*dftable[itable]; forcecoul = qtmp*q[j] * table; if (eflag) { const double table2 = etable[itable] + fraction*detable[itable]; ecoul = qtmp*q[j] * table2; } if (factor_coul < 1.0) { const double table2 = ctable[itable] + fraction*dctable[itable]; const double prefactor = qtmp*q[j] * table2; forcecoul -= (1.0-factor_coul)*prefactor; if (eflag) ecoul -= (1.0-factor_coul)*prefactor; } } } fpair = (forcecoul + forcelj) * r2inv; f[i][0] += delx*fpair; f[i][1] += dely*fpair; f[i][2] += delz*fpair; if (evflag) ev_tally_full(i,evdwl,ecoul,fpair,delx,dely,delz); } } } } /* ---------------------------------------------------------------------- */ void PairCGCMMCoulLongGPU::cpu_compute(int *nbors, int start, int eflag, int vflag) { int i,j,jnum,itype,jtype,itable; double qtmp,xtmp,ytmp,ztmp,delx,dely,delz; double fraction,table; double r,r2inv,r6inv,forcecoul,forcelj,factor_coul,factor_lj; double grij,expm2,prefactor,t,erfc; double rsq; double **x = atom->x; double **f = atom->f; double *q = atom->q; int *type = atom->type; int nlocal = atom->nlocal; int nall = nlocal + atom->nghost; int stride = nlocal-start; double *special_coul = force->special_coul; double *special_lj = force->special_lj; double qqrd2e = force->qqrd2e; // loop over neighbors of my atoms for (i = start; i < nlocal; i++) { qtmp = q[i]; xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; itype = type[i]; int *nbor = nbors + i - start; jnum = *nbor; nbor += stride; int *nbor_end = nbor + stride * jnum; for (; nbor<nbor_end; nbor+=stride) { j = *nbor; if (j < nall) factor_coul = factor_lj = 1.0; else { factor_coul = special_coul[j/nall]; factor_lj = special_lj[j/nall]; j %= nall; } delx = xtmp - x[j][0]; dely = ytmp - x[j][1]; delz = ztmp - x[j][2]; rsq = delx*delx + dely*dely + delz*delz; jtype = type[j]; double evdwl = 0.0; double ecoul = 0.0; double fpair = 0.0; if (rsq < cutsq[itype][jtype]) { const double r2inv = 1.0/rsq; const int cgt=cg_type[itype][jtype]; double forcelj = 0.0; double forcecoul = 0.0; if (rsq < cut_ljsq[itype][jtype]) { forcelj=factor_lj; if (eflag) evdwl=factor_lj; if (cgt == CG_LJ12_4) { const double r4inv=r2inv*r2inv; forcelj *= r4inv*(lj1[itype][jtype]*r4inv*r4inv - lj2[itype][jtype]); if (eflag) { evdwl *= r4inv*(lj3[itype][jtype]*r4inv*r4inv - lj4[itype][jtype]) - offset[itype][jtype]; } } else if (cgt == CG_LJ9_6) { const double r3inv = r2inv*sqrt(r2inv); const double r6inv = r3inv*r3inv; forcelj *= r6inv*(lj1[itype][jtype]*r3inv - lj2[itype][jtype]); if (eflag) { evdwl *= r6inv*(lj3[itype][jtype]*r3inv - lj4[itype][jtype]) - offset[itype][jtype]; } } else { const double r6inv = r2inv*r2inv*r2inv; forcelj *= r6inv*(lj1[itype][jtype]*r6inv - lj2[itype][jtype]); if (eflag) { evdwl *= r6inv*(lj3[itype][jtype]*r6inv - lj4[itype][jtype]) - offset[itype][jtype]; } } } if (rsq < cut_coulsq_global) { if (!ncoultablebits || rsq <= tabinnersq) { const double r = sqrt(rsq); const double grij = g_ewald * r; const double expm2 = exp(-grij*grij); const double t = 1.0 / (1.0 + EWALD_P*grij); const double erfc = t * (A1+t*(A2+t*(A3+t*(A4+t*A5)))) * expm2; const double prefactor = qqrd2e * qtmp*q[j]/r; forcecoul = prefactor * (erfc + EWALD_F*grij*expm2); if (eflag) ecoul = prefactor*erfc; if (factor_coul < 1.0) { forcecoul -= (1.0-factor_coul)*prefactor; if (eflag) ecoul -= (1.0-factor_coul)*prefactor; } } else { union_int_float_t rsq_lookup; rsq_lookup.f = rsq; int itable = rsq_lookup.i & ncoulmask; itable >>= ncoulshiftbits; const double fraction = (rsq_lookup.f - rtable[itable]) * drtable[itable]; const double table = ftable[itable] + fraction*dftable[itable]; forcecoul = qtmp*q[j] * table; if (eflag) { const double table2 = etable[itable] + fraction*detable[itable]; ecoul = qtmp*q[j] * table2; } if (factor_coul < 1.0) { const double table2 = ctable[itable] + fraction*dctable[itable]; const double prefactor = qtmp*q[j] * table2; forcecoul -= (1.0-factor_coul)*prefactor; if (eflag) ecoul -= (1.0-factor_coul)*prefactor; } } } fpair = (forcecoul + forcelj) * r2inv; f[i][0] += delx*fpair; f[i][1] += dely*fpair; f[i][2] += delz*fpair; if (j<start) { if (evflag) ev_tally_full(i,evdwl,ecoul,fpair,delx,dely,delz); } else { if (j<nlocal) { f[j][0] -= delx*fpair; f[j][1] -= dely*fpair; f[j][2] -= delz*fpair; } if (evflag) ev_tally(i,j,nlocal,0, evdwl,ecoul,fpair,delx,dely,delz); } } } } } diff --git a/src/GPU/pair_cg_cmm_gpu.cpp b/src/GPU/pair_cg_cmm_gpu.cpp index 345fbfbf3..19ba73aeb 100644 --- a/src/GPU/pair_cg_cmm_gpu.cpp +++ b/src/GPU/pair_cg_cmm_gpu.cpp @@ -1,362 +1,367 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- Contributing author: Mike Brown (SNL) ------------------------------------------------------------------------- */ #include "math.h" #include "stdio.h" #include "stdlib.h" #include "pair_cg_cmm_gpu.h" +#include "lmptype.h" #include "atom.h" #include "atom_vec.h" #include "comm.h" #include "force.h" #include "neighbor.h" #include "neigh_list.h" #include "integrate.h" #include "memory.h" #include "error.h" #include "neigh_request.h" #include "universe.h" #include "update.h" #include "domain.h" #include "string.h" #define MIN(a,b) ((a) < (b) ? (a) : (b)) #define MAX(a,b) ((a) > (b) ? (a) : (b)) // External functions from cuda library for atom decomposition bool cmm_gpu_init(const int ntypes, double **cutsq, int **cg_types, double **host_lj1, double **host_lj2, double **host_lj3, double **host_lj4, double **offset, double *special_lj, const int nlocal, const int nall, const int max_nbors, const int maxspecial, const double cell_size, int &gpu_mode, FILE *screen); void cmm_gpu_clear(); int * cmm_gpu_compute_n(const int timestep, const int ago, const int inum, const int nall, double **host_x, int *host_type, double *boxlo, double *boxhi, int *tag, int **nspecial, int **special, const bool eflag, const bool vflag, const bool eatom, const bool vatom, int &host_start, const double cpu_time, bool &success); void cmm_gpu_compute(const int timestep, const int ago, const int inum, const int nall, double **host_x, int *host_type, int *ilist, int *numj, int **firstneigh, const bool eflag, const bool vflag, const bool eatom, const bool vatom, int &host_start, const double cpu_time, bool &success); double cmm_gpu_bytes(); using namespace LAMMPS_NS; /* ---------------------------------------------------------------------- */ PairCGCMMGPU::PairCGCMMGPU(LAMMPS *lmp) : PairCGCMM(lmp), gpu_mode(GPU_PAIR) { respa_enable = 0; cpu_time = 0.0; } /* ---------------------------------------------------------------------- free all arrays ------------------------------------------------------------------------- */ PairCGCMMGPU::~PairCGCMMGPU() { cmm_gpu_clear(); } /* ---------------------------------------------------------------------- */ void PairCGCMMGPU::compute(int eflag, int vflag) { + if (update->ntimestep > MAXSMALLINT) + error->all("Timestep too big for GPU pair style"); + int ntimestep = update->ntimestep; + if (eflag || vflag) ev_setup(eflag,vflag); else evflag = vflag_fdotr = 0; int nall = atom->nlocal + atom->nghost; int inum, host_start; bool success = true; if (gpu_mode == GPU_NEIGH) { inum = atom->nlocal; - gpulist = cmm_gpu_compute_n(update->ntimestep, neighbor->ago, inum, nall, + gpulist = cmm_gpu_compute_n(ntimestep, neighbor->ago, inum, nall, atom->x, atom->type, domain->sublo, domain->subhi, atom->tag, atom->nspecial, atom->special, eflag, vflag, eflag_atom, vflag_atom, host_start, cpu_time, success); } else { inum = list->inum; - cmm_gpu_compute(update->ntimestep, neighbor->ago, inum, nall, atom->x, + cmm_gpu_compute(ntimestep, neighbor->ago, inum, nall, atom->x, atom->type, list->ilist, list->numneigh, list->firstneigh, eflag, vflag, eflag_atom, vflag_atom, host_start, cpu_time, success); } if (!success) error->one("Out of memory on GPGPU"); if (host_start<inum) { cpu_time = MPI_Wtime(); if (gpu_mode == GPU_NEIGH) cpu_compute(gpulist, host_start, eflag, vflag); else cpu_compute(host_start, eflag, vflag); cpu_time = MPI_Wtime() - cpu_time; } } /* ---------------------------------------------------------------------- init specific to this pair style ------------------------------------------------------------------------- */ void PairCGCMMGPU::init_style() { cut_respa = NULL; if (force->pair_match("gpu",0) == NULL) error->all("Cannot use pair hybrid with multiple GPU pair styles"); // Repeat cutsq calculation because done after call to init_style double maxcut = -1.0; double cut; for (int i = 1; i <= atom->ntypes; i++) { for (int j = i; j <= atom->ntypes; j++) { if (setflag[i][j] != 0 || (setflag[i][i] != 0 && setflag[j][j] != 0)) { cut = init_one(i,j); cut *= cut; if (cut > maxcut) maxcut = cut; cutsq[i][j] = cutsq[j][i] = cut; } else cutsq[i][j] = cutsq[j][i] = 0.0; } } double cell_size = sqrt(maxcut) + neighbor->skin; int maxspecial=0; if (atom->molecular) maxspecial=atom->maxspecial; bool init_ok = cmm_gpu_init(atom->ntypes+1,cutsq,cg_type,lj1,lj2,lj3,lj4, offset, force->special_lj, atom->nlocal, atom->nlocal+atom->nghost, 300, maxspecial, cell_size, gpu_mode, screen); if (!init_ok) error->one("Insufficient memory on accelerator (or no fix gpu).\n"); if (force->newton_pair) error->all("Cannot use newton pair with GPU CGCMM pair style"); if (gpu_mode != GPU_NEIGH) { int irequest = neighbor->request(this); neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->full = 1; } } /* ---------------------------------------------------------------------- */ double PairCGCMMGPU::memory_usage() { double bytes = Pair::memory_usage(); return bytes + cmm_gpu_bytes(); } /* ---------------------------------------------------------------------- */ void PairCGCMMGPU::cpu_compute(int start, int eflag, int vflag) { int i,j,ii,jj,inum,jnum,itype,jtype; double xtmp,ytmp,ztmp,delx,dely,delz,evdwl,fpair; double rsq,r2inv,r6inv,forcelj,factor_lj; int *ilist,*jlist,*numneigh,**firstneigh; double **x = atom->x; double **f = atom->f; int *type = atom->type; int nlocal = atom->nlocal; int nall = nlocal + atom->nghost; double *special_lj = force->special_lj; inum = list->inum; ilist = list->ilist; numneigh = list->numneigh; firstneigh = list->firstneigh; // loop over neighbors of my atoms for (ii = start; ii < inum; ii++) { i = ilist[ii]; xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; itype = type[i]; jlist = firstneigh[i]; jnum = numneigh[i]; for (jj = 0; jj < jnum; jj++) { j = jlist[jj]; if (j < nall) factor_lj = 1.0; else { factor_lj = special_lj[j/nall]; j %= nall; } delx = xtmp - x[j][0]; dely = ytmp - x[j][1]; delz = ztmp - x[j][2]; rsq = delx*delx + dely*dely + delz*delz; jtype = type[j]; if (rsq < cutsq[itype][jtype]) { const int cgt=cg_type[itype][jtype]; r2inv = 1.0/rsq; fpair = factor_lj; if (eflag) evdwl = factor_lj; if (cgt == CG_LJ12_4) { const double r4inv = r2inv*r2inv; fpair *= r4inv*(lj1[itype][jtype]*r4inv*r4inv - lj2[itype][jtype]); if (eflag) { evdwl *= r4inv*(lj3[itype][jtype]*r4inv*r4inv - lj4[itype][jtype]) - offset[itype][jtype]; } } else if (cgt == CG_LJ9_6) { const double r3inv = r2inv*sqrt(r2inv); const double r6inv = r3inv*r3inv; fpair *= r6inv*(lj1[itype][jtype]*r3inv - lj2[itype][jtype]); if (eflag) { evdwl *= r6inv*(lj3[itype][jtype]*r3inv - lj4[itype][jtype]) - offset[itype][jtype]; } } else { const double r6inv = r2inv*r2inv*r2inv; fpair *= r6inv*(lj1[itype][jtype]*r6inv - lj2[itype][jtype]); if (eflag) { evdwl *= r6inv*(lj3[itype][jtype]*r6inv - lj4[itype][jtype]) - offset[itype][jtype]; } } fpair *= r2inv; f[i][0] += delx*fpair; f[i][1] += dely*fpair; f[i][2] += delz*fpair; if (evflag) ev_tally_full(i,evdwl,0.0,fpair,delx,dely,delz); } } } } /* ---------------------------------------------------------------------- */ void PairCGCMMGPU::cpu_compute(int *nbors, int start, int eflag, int vflag) { int i,j,itype,jtype; int nlocal = atom->nlocal; int nall = nlocal + atom->nghost; int stride = nlocal-start; double xtmp,ytmp,ztmp,delx,dely,delz,evdwl,fpair; double rsq,r2inv,r6inv,forcelj,factor_lj; double *special_lj = force->special_lj; double **x = atom->x; double **f = atom->f; int *type = atom->type; // loop over neighbors of my atoms for (i = start; i < nlocal; i++) { xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; itype = type[i]; int *nbor = nbors + i - start; int jnum = *nbor; nbor += stride; int *nbor_end = nbor + stride * jnum; for (; nbor<nbor_end; nbor+=stride) { j = *nbor; if (j < nall) factor_lj = 1.0; else { factor_lj = special_lj[j/nall]; j %= nall; } delx = xtmp - x[j][0]; dely = ytmp - x[j][1]; delz = ztmp - x[j][2]; rsq = delx*delx + dely*dely + delz*delz; jtype = type[j]; if (rsq < cutsq[itype][jtype]) { const int cgt=cg_type[itype][jtype]; r2inv = 1.0/rsq; fpair = factor_lj; if (eflag) evdwl = factor_lj; if (cgt == CG_LJ12_4) { const double r4inv = r2inv*r2inv; fpair *= r4inv*(lj1[itype][jtype]*r4inv*r4inv - lj2[itype][jtype]); if (eflag) { evdwl *= r4inv*(lj3[itype][jtype]*r4inv*r4inv - lj4[itype][jtype]) - offset[itype][jtype]; } } else if (cgt == CG_LJ9_6) { const double r3inv = r2inv*sqrt(r2inv); const double r6inv = r3inv*r3inv; fpair *= r6inv*(lj1[itype][jtype]*r3inv - lj2[itype][jtype]); if (eflag) { evdwl *= r6inv*(lj3[itype][jtype]*r3inv - lj4[itype][jtype]) - offset[itype][jtype]; } } else { const double r6inv = r2inv*r2inv*r2inv; fpair *= r6inv*(lj1[itype][jtype]*r6inv - lj2[itype][jtype]); if (eflag) { evdwl *= r6inv*(lj3[itype][jtype]*r6inv - lj4[itype][jtype]) - offset[itype][jtype]; } } fpair *= r2inv; f[i][0] += delx*fpair; f[i][1] += dely*fpair; f[i][2] += delz*fpair; if (j<start) { if (evflag) ev_tally_full(i,evdwl,0.0,fpair,delx,dely,delz); } else { if (j<nlocal) { f[j][0] -= delx*fpair; f[j][1] -= dely*fpair; f[j][2] -= delz*fpair; } if (evflag) ev_tally(i,j,nlocal,0, evdwl,0.0,fpair,delx,dely,delz); } } } } } diff --git a/src/GPU/pair_gayberne_gpu.cpp b/src/GPU/pair_gayberne_gpu.cpp index 76079f73e..968350769 100644 --- a/src/GPU/pair_gayberne_gpu.cpp +++ b/src/GPU/pair_gayberne_gpu.cpp @@ -1,461 +1,466 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- Contributing author: Mike Brown (SNL) ------------------------------------------------------------------------- */ #include "math.h" #include "stdio.h" #include "stdlib.h" #include "pair_gayberne_gpu.h" +#include "lmptype.h" #include "math_extra.h" #include "atom.h" #include "atom_vec.h" #include "comm.h" #include "force.h" #include "neighbor.h" #include "neigh_list.h" #include "integrate.h" #include "memory.h" #include "error.h" #include "neigh_request.h" #include "universe.h" #include "domain.h" #include "update.h" #include "string.h" #define MIN(a,b) ((a) < (b) ? (a) : (b)) #define MAX(a,b) ((a) > (b) ? (a) : (b)) // External functions from cuda library for atom decomposition bool gb_gpu_init(const int ntypes, const double gamma, const double upsilon, const double mu, double **shape, double **well, double **cutsq, double **sigma, double **epsilon, double *host_lshape, int **form, double **host_lj1, double **host_lj2, double **host_lj3, double **host_lj4, double **offset, double *special_lj, const int nlocal, const int nall, const int max_nbors, const double cell_size, int &gpu_mode, FILE *screen); void gb_gpu_clear(); int * gb_gpu_compute_n(const int timestep, const int ago, const int inum, const int nall, double **host_x, int *host_type, double *boxlo, double *boxhi, const bool eflag, const bool vflag, const bool eatom, const bool vatom, int &host_start, const double cpu_time, bool &success, double **host_quat); int * gb_gpu_compute(const int timestep, const int ago, const int inum, const int nall, double **host_x, int *host_type, int *ilist, int *numj, int **firstneigh, const bool eflag, const bool vflag, const bool eatom, const bool vatom, int &host_start, const double cpu_time, bool &success, double **host_quat); double gb_gpu_bytes(); using namespace LAMMPS_NS; enum{SPHERE_SPHERE,SPHERE_ELLIPSE,ELLIPSE_SPHERE,ELLIPSE_ELLIPSE}; /* ---------------------------------------------------------------------- */ PairGayBerneGPU::PairGayBerneGPU(LAMMPS *lmp) : PairGayBerne(lmp), gpu_mode(GPU_PAIR) { } /* ---------------------------------------------------------------------- free all arrays ------------------------------------------------------------------------- */ PairGayBerneGPU::~PairGayBerneGPU() { gb_gpu_clear(); cpu_time = 0.0; } /* ---------------------------------------------------------------------- */ void PairGayBerneGPU::compute(int eflag, int vflag) { + if (update->ntimestep > MAXSMALLINT) + error->all("Timestep too big for GPU pair style"); + int ntimestep = update->ntimestep; + if (eflag || vflag) ev_setup(eflag,vflag); else evflag = vflag_fdotr = 0; int nall = atom->nlocal + atom->nghost; int inum, host_start; bool success = true; if (gpu_mode == GPU_NEIGH) { inum = atom->nlocal; - gpulist = gb_gpu_compute_n(update->ntimestep, neighbor->ago, inum, nall, + gpulist = gb_gpu_compute_n(ntimestep, neighbor->ago, inum, nall, atom->x, atom->type, domain->sublo, domain->subhi, eflag, vflag, eflag_atom, vflag_atom, host_start, cpu_time, success, atom->quat); } else { inum = list->inum; - olist = gb_gpu_compute(update->ntimestep, neighbor->ago, inum, nall, atom->x, + olist = gb_gpu_compute(ntimestep, neighbor->ago, inum, nall, atom->x, atom->type, list->ilist, list->numneigh, list->firstneigh, eflag, vflag, eflag_atom, vflag_atom, host_start, cpu_time, success, atom->quat); } if (!success) error->one("Out of memory on GPGPU"); if (host_start < inum) { cpu_time = MPI_Wtime(); if (gpu_mode == GPU_NEIGH) cpu_compute(gpulist,host_start,eflag,vflag); else cpu_compute(host_start,eflag,vflag); cpu_time = MPI_Wtime() - cpu_time; } } /* ---------------------------------------------------------------------- init specific to this pair style ------------------------------------------------------------------------- */ void PairGayBerneGPU::init_style() { if (force->pair_match("gpu",0) == NULL) error->all("Cannot use pair hybrid with multiple GPU pair styles"); if (!atom->quat_flag || !atom->torque_flag || !atom->avec->shape_type) error->all("Pair gayberne requires atom attributes quat, torque, shape"); if (atom->radius_flag) error->all("Pair gayberne cannot be used with atom attribute diameter"); // per-type shape precalculations for (int i = 1; i <= atom->ntypes; i++) { if (setwell[i]) { double *one = atom->shape[i]; shape[i][0] = one[0]*one[0]; shape[i][1] = one[1]*one[1]; shape[i][2] = one[2]*one[2]; lshape[i] = (one[0]*one[1]+one[2]*one[2])*sqrt(one[0]*one[1]); } } // Repeat cutsq calculation because done after call to init_style double maxcut = -1.0; double cut; for (int i = 1; i <= atom->ntypes; i++) { for (int j = i; j <= atom->ntypes; j++) { if (setflag[i][j] != 0 || (setflag[i][i] != 0 && setflag[j][j] != 0)) { cut = init_one(i,j); cut *= cut; if (cut > maxcut) maxcut = cut; cutsq[i][j] = cutsq[j][i] = cut; } else cutsq[i][j] = cutsq[j][i] = 0.0; } } double cell_size = sqrt(maxcut) + neighbor->skin; bool init_ok = gb_gpu_init(atom->ntypes+1, gamma, upsilon, mu, shape, well, cutsq, sigma, epsilon, lshape, form, lj1, lj2, lj3, lj4, offset, force->special_lj, atom->nlocal, atom->nlocal+atom->nghost, 300, cell_size, gpu_mode, screen); if (!init_ok) error->one("Insufficient memory on accelerator (or no fix gpu)."); if (force->newton_pair) error->all("Cannot use newton pair with GPU Gay-Berne pair style"); if (gpu_mode != GPU_NEIGH) { int irequest = neighbor->request(this); neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->full = 1; } } /* ---------------------------------------------------------------------- */ double PairGayBerneGPU::memory_usage() { double bytes = Pair::memory_usage(); return bytes + gb_gpu_bytes(); } /* ---------------------------------------------------------------------- */ void PairGayBerneGPU::cpu_compute(int start, int eflag, int vflag) { int i,j,ii,jj,inum,jnum,itype,jtype; double evdwl,one_eng,rsq,r2inv,r6inv,forcelj,factor_lj; double fforce[3],ttor[3],rtor[3],r12[3]; double a1[3][3],b1[3][3],g1[3][3],a2[3][3],b2[3][3],g2[3][3],temp[3][3]; int *ilist,*jlist,*numneigh,**firstneigh; double **x = atom->x; double **f = atom->f; double **quat = atom->quat; double **tor = atom->torque; int *type = atom->type; int nlocal = atom->nlocal; int nall = nlocal + atom->nghost; double *special_lj = force->special_lj; inum = list->inum; ilist = olist; numneigh = list->numneigh; firstneigh = list->firstneigh; // loop over neighbors of my atoms for (ii = start; ii < inum; ii++) { i = ilist[ii]; itype = type[i]; if (form[itype][itype] == ELLIPSE_ELLIPSE) { MathExtra::quat_to_mat_trans(quat[i],a1); MathExtra::diag_times3(well[itype],a1,temp); MathExtra::transpose_times3(a1,temp,b1); MathExtra::diag_times3(shape[itype],a1,temp); MathExtra::transpose_times3(a1,temp,g1); } jlist = firstneigh[i]; jnum = numneigh[i]; for (jj = 0; jj < jnum; jj++) { j = jlist[jj]; if (j < nall) factor_lj = 1.0; else { factor_lj = special_lj[j/nall]; j %= nall; } // r12 = center to center vector r12[0] = x[j][0]-x[i][0]; r12[1] = x[j][1]-x[i][1]; r12[2] = x[j][2]-x[i][2]; rsq = MathExtra::dot3(r12,r12); jtype = type[j]; // compute if less than cutoff if (rsq < cutsq[itype][jtype]) { switch (form[itype][jtype]) { case SPHERE_SPHERE: r2inv = 1.0/rsq; r6inv = r2inv*r2inv*r2inv; forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]); forcelj *= -r2inv; if (eflag) one_eng = r6inv*(r6inv*lj3[itype][jtype]-lj4[itype][jtype]) - offset[itype][jtype]; fforce[0] = r12[0]*forcelj; fforce[1] = r12[1]*forcelj; fforce[2] = r12[2]*forcelj; ttor[0] = ttor[1] = ttor[2] = 0.0; rtor[0] = rtor[1] = rtor[2] = 0.0; break; case SPHERE_ELLIPSE: MathExtra::quat_to_mat_trans(quat[j],a2); MathExtra::diag_times3(well[jtype],a2,temp); MathExtra::transpose_times3(a2,temp,b2); MathExtra::diag_times3(shape[jtype],a2,temp); MathExtra::transpose_times3(a2,temp,g2); one_eng = gayberne_lj(j,i,a2,b2,g2,r12,rsq,fforce,rtor); ttor[0] = ttor[1] = ttor[2] = 0.0; break; case ELLIPSE_SPHERE: one_eng = gayberne_lj(i,j,a1,b1,g1,r12,rsq,fforce,ttor); rtor[0] = rtor[1] = rtor[2] = 0.0; break; default: MathExtra::quat_to_mat_trans(quat[j],a2); MathExtra::diag_times3(well[jtype],a2,temp); MathExtra::transpose_times3(a2,temp,b2); MathExtra::diag_times3(shape[jtype],a2,temp); MathExtra::transpose_times3(a2,temp,g2); one_eng = gayberne_analytic(i,j,a1,a2,b1,b2,g1,g2,r12,rsq, fforce,ttor,rtor); break; } fforce[0] *= factor_lj; fforce[1] *= factor_lj; fforce[2] *= factor_lj; ttor[0] *= factor_lj; ttor[1] *= factor_lj; ttor[2] *= factor_lj; f[i][0] += fforce[0]; f[i][1] += fforce[1]; f[i][2] += fforce[2]; tor[i][0] += ttor[0]; tor[i][1] += ttor[1]; tor[i][2] += ttor[2]; if (eflag) evdwl = factor_lj*one_eng; if (evflag) ev_tally_xyz_full(i,evdwl,0.0,fforce[0],fforce[1],fforce[2], -r12[0],-r12[1],-r12[2]); } } } } /* ---------------------------------------------------------------------- */ void PairGayBerneGPU::cpu_compute(int *nbors, int start, int eflag, int vflag) { int i,j,itype,jtype; double evdwl,one_eng,rsq,r2inv,r6inv,forcelj,factor_lj; double fforce[3],ttor[3],rtor[3],r12[3]; double a1[3][3],b1[3][3],g1[3][3],a2[3][3],b2[3][3],g2[3][3],temp[3][3]; double **x = atom->x; double **f = atom->f; double **quat = atom->quat; double **tor = atom->torque; int *type = atom->type; int nlocal = atom->nlocal; int nall = nlocal + atom->nghost; int stride = nlocal-start; double *special_lj = force->special_lj; // loop over neighbors of my atoms for (i = start; i < nlocal; i++) { itype = type[i]; if (form[itype][itype] == ELLIPSE_ELLIPSE) { MathExtra::quat_to_mat_trans(quat[i],a1); MathExtra::diag_times3(well[itype],a1,temp); MathExtra::transpose_times3(a1,temp,b1); MathExtra::diag_times3(shape[itype],a1,temp); MathExtra::transpose_times3(a1,temp,g1); } int *nbor = nbors+i-start; int jnum =* nbor; nbor += stride; int *nbor_end = nbor + stride * jnum; for ( ; nbor < nbor_end; nbor += stride) { j = *nbor; if (j < nall) factor_lj = 1.0; else { factor_lj = special_lj[j/nall]; j %= nall; } // r12 = center to center vector r12[0] = x[j][0]-x[i][0]; r12[1] = x[j][1]-x[i][1]; r12[2] = x[j][2]-x[i][2]; rsq = MathExtra::dot3(r12,r12); jtype = type[j]; // compute if less than cutoff if (rsq < cutsq[itype][jtype]) { switch (form[itype][jtype]) { case SPHERE_SPHERE: r2inv = 1.0/rsq; r6inv = r2inv*r2inv*r2inv; forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]); forcelj *= -r2inv; if (eflag) one_eng = r6inv*(r6inv*lj3[itype][jtype]-lj4[itype][jtype]) - offset[itype][jtype]; fforce[0] = r12[0]*forcelj; fforce[1] = r12[1]*forcelj; fforce[2] = r12[2]*forcelj; ttor[0] = ttor[1] = ttor[2] = 0.0; rtor[0] = rtor[1] = rtor[2] = 0.0; break; case SPHERE_ELLIPSE: MathExtra::quat_to_mat_trans(quat[j],a2); MathExtra::diag_times3(well[jtype],a2,temp); MathExtra::transpose_times3(a2,temp,b2); MathExtra::diag_times3(shape[jtype],a2,temp); MathExtra::transpose_times3(a2,temp,g2); one_eng = gayberne_lj(j,i,a2,b2,g2,r12,rsq,fforce,rtor); ttor[0] = ttor[1] = ttor[2] = 0.0; break; case ELLIPSE_SPHERE: one_eng = gayberne_lj(i,j,a1,b1,g1,r12,rsq,fforce,ttor); rtor[0] = rtor[1] = rtor[2] = 0.0; break; default: MathExtra::quat_to_mat_trans(quat[j],a2); MathExtra::diag_times3(well[jtype],a2,temp); MathExtra::transpose_times3(a2,temp,b2); MathExtra::diag_times3(shape[jtype],a2,temp); MathExtra::transpose_times3(a2,temp,g2); one_eng = gayberne_analytic(i,j,a1,a2,b1,b2,g1,g2,r12,rsq, fforce,ttor,rtor); break; } fforce[0] *= factor_lj; fforce[1] *= factor_lj; fforce[2] *= factor_lj; ttor[0] *= factor_lj; ttor[1] *= factor_lj; ttor[2] *= factor_lj; f[i][0] += fforce[0]; f[i][1] += fforce[1]; f[i][2] += fforce[2]; tor[i][0] += ttor[0]; tor[i][1] += ttor[1]; tor[i][2] += ttor[2]; if (eflag) evdwl = factor_lj*one_eng; if (j<start) { if (evflag) ev_tally_xyz_full(i,evdwl,0.0,fforce[0],fforce[1], fforce[2],-r12[0],-r12[1],-r12[2]); } else { if (j < nlocal) { rtor[0] *= factor_lj; rtor[1] *= factor_lj; rtor[2] *= factor_lj; f[j][0] -= fforce[0]; f[j][1] -= fforce[1]; f[j][2] -= fforce[2]; tor[j][0] += rtor[0]; tor[j][1] += rtor[1]; tor[j][2] += rtor[2]; } if (evflag) ev_tally_xyz(i,j,nlocal,0, evdwl,0.0,fforce[0],fforce[1],fforce[2], -r12[0],-r12[1],-r12[2]); } } } } } diff --git a/src/GPU/pair_lj96_cut_gpu.cpp b/src/GPU/pair_lj96_cut_gpu.cpp index 583c2f27b..095e9d9c0 100644 --- a/src/GPU/pair_lj96_cut_gpu.cpp +++ b/src/GPU/pair_lj96_cut_gpu.cpp @@ -1,318 +1,323 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- Contributing author: Mike Brown (SNL) ------------------------------------------------------------------------- */ #include "math.h" #include "stdio.h" #include "stdlib.h" #include "pair_lj96_cut_gpu.h" +#include "lmptype.h" #include "atom.h" #include "atom_vec.h" #include "comm.h" #include "force.h" #include "neighbor.h" #include "neigh_list.h" #include "integrate.h" #include "memory.h" #include "error.h" #include "neigh_request.h" #include "universe.h" #include "update.h" #include "domain.h" #include "string.h" #define MIN(a,b) ((a) < (b) ? (a) : (b)) #define MAX(a,b) ((a) > (b) ? (a) : (b)) // External functions from cuda library for atom decomposition bool lj96_gpu_init(const int ntypes, double **cutsq, double **host_lj1, double **host_lj2, double **host_lj3, double **host_lj4, double **offset, double *special_lj, const int nlocal, const int nall, const int max_nbors, const int maxspecial, const double cell_size, int &gpu_mode, FILE *screen); void lj96_gpu_clear(); int * lj96_gpu_compute_n(const int timestep, const int ago, const int inum, const int nall, double **host_x, int *host_type, double *boxlo, double *boxhi, int *tag, int **nspecial, int **special, const bool eflag, const bool vflag, const bool eatom, const bool vatom, int &host_start, const double cpu_time, bool &success); void lj96_gpu_compute(const int timestep, const int ago, const int inum, const int nall, double **host_x, int *host_type, int *ilist, int *numj, int **firstneigh, const bool eflag, const bool vflag, const bool eatom, const bool vatom, int &host_start, const double cpu_time, bool &success); double lj96_gpu_bytes(); using namespace LAMMPS_NS; /* ---------------------------------------------------------------------- */ PairLJ96CutGPU::PairLJ96CutGPU(LAMMPS *lmp) : PairLJ96Cut(lmp), gpu_mode(GPU_PAIR) { respa_enable = 0; cpu_time = 0.0; } /* ---------------------------------------------------------------------- free all arrays ------------------------------------------------------------------------- */ PairLJ96CutGPU::~PairLJ96CutGPU() { lj96_gpu_clear(); } /* ---------------------------------------------------------------------- */ void PairLJ96CutGPU::compute(int eflag, int vflag) { + if (update->ntimestep > MAXSMALLINT) + error->all("Timestep too big for GPU pair style"); + int ntimestep = update->ntimestep; + if (eflag || vflag) ev_setup(eflag,vflag); else evflag = vflag_fdotr = 0; int nall = atom->nlocal + atom->nghost; int inum, host_start; bool success = true; if (gpu_mode == GPU_NEIGH) { inum = atom->nlocal; - gpulist = lj96_gpu_compute_n(update->ntimestep, neighbor->ago, inum, nall, + gpulist = lj96_gpu_compute_n(ntimestep, neighbor->ago, inum, nall, atom->x, atom->type, domain->sublo, domain->subhi, atom->tag, atom->nspecial, atom->special, eflag, vflag, eflag_atom, vflag_atom, host_start, cpu_time, success); } else { inum = list->inum; - lj96_gpu_compute(update->ntimestep, neighbor->ago, inum, nall, atom->x, + lj96_gpu_compute(ntimestep, neighbor->ago, inum, nall, atom->x, atom->type, list->ilist, list->numneigh, list->firstneigh, eflag, vflag, eflag_atom, vflag_atom, host_start, cpu_time, success); } if (!success) error->one("Out of memory on GPGPU"); if (host_start<inum) { cpu_time = MPI_Wtime(); if (gpu_mode == GPU_NEIGH) cpu_compute(gpulist, host_start, eflag, vflag); else cpu_compute(host_start, eflag, vflag); cpu_time = MPI_Wtime() - cpu_time; } } /* ---------------------------------------------------------------------- init specific to this pair style ------------------------------------------------------------------------- */ void PairLJ96CutGPU::init_style() { cut_respa = NULL; if (force->pair_match("gpu",0) == NULL) error->all("Cannot use pair hybrid with multiple GPU pair styles"); // Repeat cutsq calculation because done after call to init_style double maxcut = -1.0; double cut; for (int i = 1; i <= atom->ntypes; i++) { for (int j = i; j <= atom->ntypes; j++) { if (setflag[i][j] != 0 || (setflag[i][i] != 0 && setflag[j][j] != 0)) { cut = init_one(i,j); cut *= cut; if (cut > maxcut) maxcut = cut; cutsq[i][j] = cutsq[j][i] = cut; } else cutsq[i][j] = cutsq[j][i] = 0.0; } } double cell_size = sqrt(maxcut) + neighbor->skin; int maxspecial=0; if (atom->molecular) maxspecial=atom->maxspecial; bool init_ok = lj96_gpu_init(atom->ntypes+1, cutsq, lj1, lj2, lj3, lj4, offset, force->special_lj, atom->nlocal, atom->nlocal+atom->nghost, 300, maxspecial, cell_size, gpu_mode, screen); if (!init_ok) error->one("Insufficient memory on accelerator (or no fix gpu).\n"); if (force->newton_pair) error->all("Cannot use newton pair with GPU LJ96 pair style"); if (gpu_mode != GPU_NEIGH) { int irequest = neighbor->request(this); neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->full = 1; } } /* ---------------------------------------------------------------------- */ double PairLJ96CutGPU::memory_usage() { double bytes = Pair::memory_usage(); return bytes + lj96_gpu_bytes(); } /* ---------------------------------------------------------------------- */ void PairLJ96CutGPU::cpu_compute(int start, int eflag, int vflag) { int i,j,ii,jj,inum,jnum,itype,jtype; double xtmp,ytmp,ztmp,delx,dely,delz,evdwl,fpair; double rsq,r2inv,r3inv,r6inv,forcelj,factor_lj; int *ilist,*jlist,*numneigh,**firstneigh; double **x = atom->x; double **f = atom->f; int *type = atom->type; int nlocal = atom->nlocal; int nall = nlocal + atom->nghost; double *special_lj = force->special_lj; inum = list->inum; ilist = list->ilist; numneigh = list->numneigh; firstneigh = list->firstneigh; // loop over neighbors of my atoms for (ii = start; ii < inum; ii++) { i = ilist[ii]; xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; itype = type[i]; jlist = firstneigh[i]; jnum = numneigh[i]; for (jj = 0; jj < jnum; jj++) { j = jlist[jj]; if (j < nall) factor_lj = 1.0; else { factor_lj = special_lj[j/nall]; j %= nall; } delx = xtmp - x[j][0]; dely = ytmp - x[j][1]; delz = ztmp - x[j][2]; rsq = delx*delx + dely*dely + delz*delz; jtype = type[j]; if (rsq < cutsq[itype][jtype]) { r2inv = 1.0/rsq; r6inv = r2inv*r2inv*r2inv; r3inv = sqrt(r6inv); forcelj = r6inv * (lj1[itype][jtype]*r3inv - lj2[itype][jtype]); fpair = factor_lj*forcelj*r2inv; f[i][0] += delx*fpair; f[i][1] += dely*fpair; f[i][2] += delz*fpair; if (eflag) { evdwl = r6inv*(lj3[itype][jtype]*r3inv-lj4[itype][jtype]) - offset[itype][jtype]; evdwl *= factor_lj; } if (evflag) ev_tally_full(i,evdwl,0.0,fpair,delx,dely,delz); } } } } /* ---------------------------------------------------------------------- */ void PairLJ96CutGPU::cpu_compute(int *nbors, int start, int eflag, int vflag) { int i,j,itype,jtype; int nlocal = atom->nlocal; int nall = nlocal + atom->nghost; int stride = nlocal-start; double xtmp,ytmp,ztmp,delx,dely,delz,evdwl,fpair; double rsq,r2inv,r3inv,r6inv,forcelj,factor_lj; double *special_lj = force->special_lj; double **x = atom->x; double **f = atom->f; int *type = atom->type; // loop over neighbors of my atoms for (i = start; i < nlocal; i++) { xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; itype = type[i]; int *nbor = nbors + i - start; int jnum = *nbor; nbor += stride; int *nbor_end = nbor + stride * jnum; for (; nbor<nbor_end; nbor+=stride) { j = *nbor; if (j < nall) factor_lj = 1.0; else { factor_lj = special_lj[j/nall]; j %= nall; } delx = xtmp - x[j][0]; dely = ytmp - x[j][1]; delz = ztmp - x[j][2]; rsq = delx*delx + dely*dely + delz*delz; jtype = type[j]; if (rsq < cutsq[itype][jtype]) { r2inv = 1.0/rsq; r6inv = r2inv*r2inv*r2inv; r3inv = sqrt(r6inv); forcelj = r6inv * (lj1[itype][jtype]*r3inv - lj2[itype][jtype]); fpair = factor_lj*forcelj*r2inv; f[i][0] += delx*fpair; f[i][1] += dely*fpair; f[i][2] += delz*fpair; if (eflag) { evdwl = r6inv*(lj3[itype][jtype]*r3inv-lj4[itype][jtype]) - offset[itype][jtype]; evdwl *= factor_lj; } if (j<start) { if (evflag) ev_tally_full(i,evdwl,0.0,fpair,delx,dely,delz); } else { if (j<nlocal) { f[j][0] -= delx*fpair; f[j][1] -= dely*fpair; f[j][2] -= delz*fpair; } if (evflag) ev_tally(i,j,nlocal,0, evdwl,0.0,fpair,delx,dely,delz); } } } } } diff --git a/src/GPU/pair_lj_cut_coul_cut_gpu.cpp b/src/GPU/pair_lj_cut_coul_cut_gpu.cpp index 54430cbc3..1c8632c3a 100644 --- a/src/GPU/pair_lj_cut_coul_cut_gpu.cpp +++ b/src/GPU/pair_lj_cut_coul_cut_gpu.cpp @@ -1,364 +1,369 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- Contributing author: Mike Brown (SNL) ------------------------------------------------------------------------- */ #include "math.h" #include "stdio.h" #include "stdlib.h" #include "pair_lj_cut_coul_cut_gpu.h" +#include "lmptype.h" #include "atom.h" #include "atom_vec.h" #include "comm.h" #include "force.h" #include "neighbor.h" #include "neigh_list.h" #include "integrate.h" #include "memory.h" #include "error.h" #include "neigh_request.h" #include "universe.h" #include "update.h" #include "domain.h" #include "string.h" #define MIN(a,b) ((a) < (b) ? (a) : (b)) #define MAX(a,b) ((a) > (b) ? (a) : (b)) // External functions from cuda library for atom decomposition bool ljc_gpu_init(const int ntypes, double **cutsq, double **host_lj1, double **host_lj2, double **host_lj3, double **host_lj4, double **offset, double *special_lj, const int nlocal, const int nall, const int max_nbors, const int maxspecial, const double cell_size, int &gpu_mode, FILE *screen, double **host_cut_ljsq, double **host_cut_coulsq, double *host_special_coul, const double qqrd2e); void ljc_gpu_clear(); int * ljc_gpu_compute_n(const int timestep, const int ago, const int inum, const int nall, double **host_x, int *host_type, double *boxlo, double *boxhi, int *tag, int **nspecial, int **special, const bool eflag, const bool vflag, const bool eatom, const bool vatom, int &host_start, const double cpu_time, bool &success, double *host_q); void ljc_gpu_compute(const int timestep, const int ago, const int inum, const int nall, double **host_x, int *host_type, int *ilist, int *numj, int **firstneigh, const bool eflag, const bool vflag, const bool eatom, const bool vatom, int &host_start, const double cpu_time, bool &success, double *host_q); double ljc_gpu_bytes(); using namespace LAMMPS_NS; /* ---------------------------------------------------------------------- */ PairLJCutCoulCutGPU::PairLJCutCoulCutGPU(LAMMPS *lmp) : PairLJCutCoulCut(lmp), gpu_mode(GPU_PAIR) { respa_enable = 0; cpu_time = 0.0; } /* ---------------------------------------------------------------------- free all arrays ------------------------------------------------------------------------- */ PairLJCutCoulCutGPU::~PairLJCutCoulCutGPU() { ljc_gpu_clear(); } /* ---------------------------------------------------------------------- */ void PairLJCutCoulCutGPU::compute(int eflag, int vflag) { + if (update->ntimestep > MAXSMALLINT) + error->all("Timestep too big for GPU pair style"); + int ntimestep = update->ntimestep; + if (eflag || vflag) ev_setup(eflag,vflag); else evflag = vflag_fdotr = 0; int nall = atom->nlocal + atom->nghost; int inum, host_start; bool success = true; if (gpu_mode == GPU_NEIGH) { inum = atom->nlocal; - gpulist = ljc_gpu_compute_n(update->ntimestep, neighbor->ago, inum, nall, + gpulist = ljc_gpu_compute_n(ntimestep, neighbor->ago, inum, nall, atom->x, atom->type, domain->sublo, domain->subhi, atom->tag, atom->nspecial, atom->special, eflag, vflag, eflag_atom, vflag_atom, host_start, cpu_time, success, atom->q); } else { inum = list->inum; - ljc_gpu_compute(update->ntimestep, neighbor->ago, inum, nall, atom->x, + ljc_gpu_compute(ntimestep, neighbor->ago, inum, nall, atom->x, atom->type, list->ilist, list->numneigh, list->firstneigh, eflag, vflag, eflag_atom, vflag_atom, host_start, cpu_time, success, atom->q); } if (!success) error->one("Out of memory on GPGPU"); if (host_start<inum) { cpu_time = MPI_Wtime(); if (gpu_mode == GPU_NEIGH) cpu_compute(gpulist, host_start, eflag, vflag); else cpu_compute(host_start, eflag, vflag); cpu_time = MPI_Wtime() - cpu_time; } } /* ---------------------------------------------------------------------- init specific to this pair style ------------------------------------------------------------------------- */ void PairLJCutCoulCutGPU::init_style() { if (!atom->q_flag) error->all("Pair style lj/cut/coul/cut requires atom attribute q"); if (force->pair_match("gpu",0) == NULL) error->all("Cannot use pair hybrid with multiple GPU pair styles"); // Repeat cutsq calculation because done after call to init_style double maxcut = -1.0; double cut; for (int i = 1; i <= atom->ntypes; i++) { for (int j = i; j <= atom->ntypes; j++) { if (setflag[i][j] != 0 || (setflag[i][i] != 0 && setflag[j][j] != 0)) { cut = init_one(i,j); cut *= cut; if (cut > maxcut) maxcut = cut; cutsq[i][j] = cutsq[j][i] = cut; } else cutsq[i][j] = cutsq[j][i] = 0.0; } } double cell_size = sqrt(maxcut) + neighbor->skin; int maxspecial=0; if (atom->molecular) maxspecial=atom->maxspecial; bool init_ok = ljc_gpu_init(atom->ntypes+1, cutsq, lj1, lj2, lj3, lj4, offset, force->special_lj, atom->nlocal, atom->nlocal+atom->nghost, 300, maxspecial, cell_size, gpu_mode, screen, cut_ljsq, cut_coulsq, force->special_coul, force->qqrd2e); if (!init_ok) error->one("Insufficient memory on accelerator (or no fix gpu).\n"); if (force->newton_pair) error->all("Cannot use newton pair with GPU LJ pair style"); if (gpu_mode != GPU_NEIGH) { int irequest = neighbor->request(this); neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->full = 1; } } /* ---------------------------------------------------------------------- */ double PairLJCutCoulCutGPU::memory_usage() { double bytes = Pair::memory_usage(); return bytes + ljc_gpu_bytes(); } /* ---------------------------------------------------------------------- */ void PairLJCutCoulCutGPU::cpu_compute(int start, int eflag, int vflag) { int i,j,ii,jj,inum,jnum,itype,jtype; double qtmp,xtmp,ytmp,ztmp,delx,dely,delz,evdwl,ecoul,fpair; double rsq,r2inv,r6inv,forcecoul,forcelj,factor_coul,factor_lj; int *ilist,*jlist,*numneigh,**firstneigh; evdwl = ecoul = 0.0; double **x = atom->x; double **f = atom->f; double *q = atom->q; int *type = atom->type; int nlocal = atom->nlocal; int nall = nlocal + atom->nghost; double *special_coul = force->special_coul; double *special_lj = force->special_lj; int newton_pair = force->newton_pair; double qqrd2e = force->qqrd2e; inum = list->inum; ilist = list->ilist; numneigh = list->numneigh; firstneigh = list->firstneigh; // loop over neighbors of my atoms for (ii = start; ii < inum; ii++) { i = ilist[ii]; qtmp = q[i]; xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; itype = type[i]; jlist = firstneigh[i]; jnum = numneigh[i]; for (jj = 0; jj < jnum; jj++) { j = jlist[jj]; if (j < nall) factor_coul = factor_lj = 1.0; else { factor_coul = special_coul[j/nall]; factor_lj = special_lj[j/nall]; j %= nall; } delx = xtmp - x[j][0]; dely = ytmp - x[j][1]; delz = ztmp - x[j][2]; rsq = delx*delx + dely*dely + delz*delz; jtype = type[j]; if (rsq < cutsq[itype][jtype]) { r2inv = 1.0/rsq; if (rsq < cut_coulsq[itype][jtype]) forcecoul = qqrd2e * qtmp*q[j]*sqrt(r2inv); else forcecoul = 0.0; if (rsq < cut_ljsq[itype][jtype]) { r6inv = r2inv*r2inv*r2inv; forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]); } else forcelj = 0.0; fpair = (factor_coul*forcecoul + factor_lj*forcelj) * r2inv; f[i][0] += delx*fpair; f[i][1] += dely*fpair; f[i][2] += delz*fpair; if (eflag) { if (rsq < cut_coulsq[itype][jtype]) ecoul = factor_coul * qqrd2e * qtmp*q[j]*sqrt(r2inv); else ecoul = 0.0; if (rsq < cut_ljsq[itype][jtype]) { evdwl = r6inv*(lj3[itype][jtype]*r6inv-lj4[itype][jtype]) - offset[itype][jtype]; evdwl *= factor_lj; } else evdwl = 0.0; } if (evflag) ev_tally_full(i,evdwl,ecoul,fpair,delx,dely,delz); } } } } /* ---------------------------------------------------------------------- */ void PairLJCutCoulCutGPU::cpu_compute(int *nbors, int start, int eflag, int vflag) { int i,j,jnum,itype,jtype; double qtmp,xtmp,ytmp,ztmp,delx,dely,delz,evdwl,ecoul,fpair; double rsq,r2inv,r6inv,forcecoul,forcelj,factor_coul,factor_lj; evdwl = ecoul = 0.0; double **x = atom->x; double **f = atom->f; double *q = atom->q; int *type = atom->type; int nlocal = atom->nlocal; int nall = nlocal + atom->nghost; int stride = nlocal-start; double *special_coul = force->special_coul; double *special_lj = force->special_lj; double qqrd2e = force->qqrd2e; // loop over neighbors of my atoms for (i = start; i < nlocal; i++) { qtmp = q[i]; xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; itype = type[i]; int *nbor = nbors + i - start; jnum = *nbor; nbor += stride; int *nbor_end = nbor + stride * jnum; for (; nbor<nbor_end; nbor+=stride) { j = *nbor; if (j < nall) factor_coul = factor_lj = 1.0; else { factor_coul = special_coul[j/nall]; factor_lj = special_lj[j/nall]; j %= nall; } delx = xtmp - x[j][0]; dely = ytmp - x[j][1]; delz = ztmp - x[j][2]; rsq = delx*delx + dely*dely + delz*delz; jtype = type[j]; if (rsq < cutsq[itype][jtype]) { r2inv = 1.0/rsq; if (rsq < cut_coulsq[itype][jtype]) forcecoul = qqrd2e * qtmp*q[j]*sqrt(r2inv); else forcecoul = 0.0; if (rsq < cut_ljsq[itype][jtype]) { r6inv = r2inv*r2inv*r2inv; forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]); } else forcelj = 0.0; fpair = (factor_coul*forcecoul + factor_lj*forcelj) * r2inv; f[i][0] += delx*fpair; f[i][1] += dely*fpair; f[i][2] += delz*fpair; if (eflag) { if (rsq < cut_coulsq[itype][jtype]) ecoul = factor_coul * qqrd2e * qtmp*q[j]*sqrt(r2inv); else ecoul = 0.0; if (rsq < cut_ljsq[itype][jtype]) { evdwl = r6inv*(lj3[itype][jtype]*r6inv-lj4[itype][jtype]) - offset[itype][jtype]; evdwl *= factor_lj; } else evdwl = 0.0; } if (j<start) { if (evflag) ev_tally_full(i,evdwl,ecoul,fpair,delx,dely,delz); } else { if (j<nlocal) { f[j][0] -= delx*fpair; f[j][1] -= dely*fpair; f[j][2] -= delz*fpair; } if (evflag) ev_tally(i,j,nlocal,0, evdwl,ecoul,fpair,delx,dely,delz); } } } } } diff --git a/src/GPU/pair_lj_cut_coul_long_gpu.cpp b/src/GPU/pair_lj_cut_coul_long_gpu.cpp index 2ae806439..632f151dc 100644 --- a/src/GPU/pair_lj_cut_coul_long_gpu.cpp +++ b/src/GPU/pair_lj_cut_coul_long_gpu.cpp @@ -1,452 +1,457 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- Contributing author: Mike Brown (SNL) ------------------------------------------------------------------------- */ #include "math.h" #include "stdio.h" #include "stdlib.h" #include "pair_lj_cut_coul_long_gpu.h" +#include "lmptype.h" #include "atom.h" #include "atom_vec.h" #include "comm.h" #include "force.h" #include "neighbor.h" #include "neigh_list.h" #include "integrate.h" #include "memory.h" #include "error.h" #include "neigh_request.h" #include "universe.h" #include "update.h" #include "domain.h" #include "string.h" #include "kspace.h" #define MIN(a,b) ((a) < (b) ? (a) : (b)) #define MAX(a,b) ((a) > (b) ? (a) : (b)) #define EWALD_F 1.12837917 #define EWALD_P 0.3275911 #define A1 0.254829592 #define A2 -0.284496736 #define A3 1.421413741 #define A4 -1.453152027 #define A5 1.061405429 // External functions from cuda library for atom decomposition bool ljcl_gpu_init(const int ntypes, double **cutsq, double **host_lj1, double **host_lj2, double **host_lj3, double **host_lj4, double **offset, double *special_lj, const int nlocal, const int nall, const int max_nbors, const int maxspecial, const double cell_size, int &gpu_mode, FILE *screen, double **host_cut_ljsq, double host_cut_coulsq, double *host_special_coul, const double qqrd2e, const double g_ewald); void ljcl_gpu_clear(); int * ljcl_gpu_compute_n(const int timestep, const int ago, const int inum, const int nall, double **host_x, int *host_type, double *boxlo, double *boxhi, int *tag, int **nspecial, int **special, const bool eflag, const bool vflag, const bool eatom, const bool vatom, int &host_start, const double cpu_time, bool &success, double *host_q); void ljcl_gpu_compute(const int timestep, const int ago, const int inum, const int nall, double **host_x, int *host_type, int *ilist, int *numj, int **firstneigh, const bool eflag, const bool vflag, const bool eatom, const bool vatom, int &host_start, const double cpu_time, bool &success, double *host_q); double ljcl_gpu_bytes(); using namespace LAMMPS_NS; /* ---------------------------------------------------------------------- */ PairLJCutCoulLongGPU::PairLJCutCoulLongGPU(LAMMPS *lmp) : PairLJCutCoulLong(lmp), gpu_mode(GPU_PAIR) { respa_enable = 0; cpu_time = 0.0; } /* ---------------------------------------------------------------------- free all arrays ------------------------------------------------------------------------- */ PairLJCutCoulLongGPU::~PairLJCutCoulLongGPU() { ljcl_gpu_clear(); } /* ---------------------------------------------------------------------- */ void PairLJCutCoulLongGPU::compute(int eflag, int vflag) { + if (update->ntimestep > MAXSMALLINT) + error->all("Timestep too big for GPU pair style"); + int ntimestep = update->ntimestep; + if (eflag || vflag) ev_setup(eflag,vflag); else evflag = vflag_fdotr = 0; int nall = atom->nlocal + atom->nghost; int inum, host_start; bool success = true; if (gpu_mode == GPU_NEIGH) { inum = atom->nlocal; - gpulist = ljcl_gpu_compute_n(update->ntimestep, neighbor->ago, inum, nall, + gpulist = ljcl_gpu_compute_n(ntimestep, neighbor->ago, inum, nall, atom->x, atom->type, domain->sublo, domain->subhi, atom->tag, atom->nspecial, atom->special, eflag, vflag, eflag_atom, vflag_atom, host_start, cpu_time, success, atom->q); } else { inum = list->inum; - ljcl_gpu_compute(update->ntimestep, neighbor->ago, inum, nall, atom->x, + ljcl_gpu_compute(ntimestep, neighbor->ago, inum, nall, atom->x, atom->type, list->ilist, list->numneigh, list->firstneigh, eflag, vflag, eflag_atom, vflag_atom, host_start, cpu_time, success, atom->q); } if (!success) error->one("Out of memory on GPGPU"); if (host_start<inum) { cpu_time = MPI_Wtime(); if (gpu_mode == GPU_NEIGH) cpu_compute(gpulist, host_start, eflag, vflag); else cpu_compute(host_start, eflag, vflag); cpu_time = MPI_Wtime() - cpu_time; } } /* ---------------------------------------------------------------------- init specific to this pair style ------------------------------------------------------------------------- */ void PairLJCutCoulLongGPU::init_style() { cut_respa = NULL; if (!atom->q_flag) error->all("Pair style lj/cut/coul/cut requires atom attribute q"); if (force->pair_match("gpu",0) == NULL) error->all("Cannot use pair hybrid with multiple GPU pair styles"); // Repeat cutsq calculation because done after call to init_style double maxcut = -1.0; double cut; for (int i = 1; i <= atom->ntypes; i++) { for (int j = i; j <= atom->ntypes; j++) { if (setflag[i][j] != 0 || (setflag[i][i] != 0 && setflag[j][j] != 0)) { cut = init_one(i,j); cut *= cut; if (cut > maxcut) maxcut = cut; cutsq[i][j] = cutsq[j][i] = cut; } else cutsq[i][j] = cutsq[j][i] = 0.0; } } double cell_size = sqrt(maxcut) + neighbor->skin; cut_coulsq = cut_coul * cut_coul; // insure use of KSpace long-range solver, set g_ewald if (force->kspace == NULL) error->all("Pair style is incompatible with KSpace style"); g_ewald = force->kspace->g_ewald; // setup force tables if (ncoultablebits) init_tables(); int maxspecial=0; if (atom->molecular) maxspecial=atom->maxspecial; bool init_ok = ljcl_gpu_init(atom->ntypes+1, cutsq, lj1, lj2, lj3, lj4, offset, force->special_lj, atom->nlocal, atom->nlocal+atom->nghost, 300, maxspecial, cell_size, gpu_mode, screen, cut_ljsq, cut_coulsq, force->special_coul, force->qqrd2e, g_ewald); if (!init_ok) error->one("Insufficient memory on accelerator (or no fix gpu).\n"); if (force->newton_pair) error->all("Cannot use newton pair with GPU LJ pair style"); if (gpu_mode != GPU_NEIGH) { int irequest = neighbor->request(this); neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->full = 1; } } /* ---------------------------------------------------------------------- */ double PairLJCutCoulLongGPU::memory_usage() { double bytes = Pair::memory_usage(); return bytes + ljcl_gpu_bytes(); } /* ---------------------------------------------------------------------- */ void PairLJCutCoulLongGPU::cpu_compute(int start, int eflag, int vflag) { int i,j,ii,jj,inum,jnum,itype,jtype,itable; double qtmp,xtmp,ytmp,ztmp,delx,dely,delz,evdwl,ecoul,fpair; double fraction,table; double r,r2inv,r6inv,forcecoul,forcelj,factor_coul,factor_lj; double grij,expm2,prefactor,t,erfc; int *ilist,*jlist,*numneigh,**firstneigh; double rsq; evdwl = ecoul = 0.0; double **x = atom->x; double **f = atom->f; double *q = atom->q; int *type = atom->type; int nlocal = atom->nlocal; int nall = nlocal + atom->nghost; double *special_coul = force->special_coul; double *special_lj = force->special_lj; double qqrd2e = force->qqrd2e; inum = list->inum; ilist = list->ilist; numneigh = list->numneigh; firstneigh = list->firstneigh; // loop over neighbors of my atoms for (ii = start; ii < inum; ii++) { i = ilist[ii]; qtmp = q[i]; xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; itype = type[i]; jlist = firstneigh[i]; jnum = numneigh[i]; for (jj = 0; jj < jnum; jj++) { j = jlist[jj]; if (j < nall) factor_coul = factor_lj = 1.0; else { factor_coul = special_coul[j/nall]; factor_lj = special_lj[j/nall]; j %= nall; } delx = xtmp - x[j][0]; dely = ytmp - x[j][1]; delz = ztmp - x[j][2]; rsq = delx*delx + dely*dely + delz*delz; jtype = type[j]; if (rsq < cutsq[itype][jtype]) { r2inv = 1.0/rsq; if (rsq < cut_coulsq) { if (!ncoultablebits || rsq <= tabinnersq) { r = sqrt(rsq); grij = g_ewald * r; expm2 = exp(-grij*grij); t = 1.0 / (1.0 + EWALD_P*grij); erfc = t * (A1+t*(A2+t*(A3+t*(A4+t*A5)))) * expm2; prefactor = qqrd2e * qtmp*q[j]/r; forcecoul = prefactor * (erfc + EWALD_F*grij*expm2); if (factor_coul < 1.0) forcecoul -= (1.0-factor_coul)*prefactor; } else { union_int_float_t rsq_lookup; rsq_lookup.f = rsq; itable = rsq_lookup.i & ncoulmask; itable >>= ncoulshiftbits; fraction = (rsq_lookup.f - rtable[itable]) * drtable[itable]; table = ftable[itable] + fraction*dftable[itable]; forcecoul = qtmp*q[j] * table; if (factor_coul < 1.0) { table = ctable[itable] + fraction*dctable[itable]; prefactor = qtmp*q[j] * table; forcecoul -= (1.0-factor_coul)*prefactor; } } } else forcecoul = 0.0; if (rsq < cut_ljsq[itype][jtype]) { r6inv = r2inv*r2inv*r2inv; forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]); } else forcelj = 0.0; fpair = (forcecoul + factor_lj*forcelj) * r2inv; f[i][0] += delx*fpair; f[i][1] += dely*fpair; f[i][2] += delz*fpair; if (eflag) { if (rsq < cut_coulsq) { if (!ncoultablebits || rsq <= tabinnersq) ecoul = prefactor*erfc; else { table = etable[itable] + fraction*detable[itable]; ecoul = qtmp*q[j] * table; } if (factor_coul < 1.0) ecoul -= (1.0-factor_coul)*prefactor; } else ecoul = 0.0; if (rsq < cut_ljsq[itype][jtype]) { evdwl = r6inv*(lj3[itype][jtype]*r6inv-lj4[itype][jtype]) - offset[itype][jtype]; evdwl *= factor_lj; } else evdwl = 0.0; } if (evflag) ev_tally_full(i,evdwl,ecoul,fpair,delx,dely,delz); } } } } /* ---------------------------------------------------------------------- */ void PairLJCutCoulLongGPU::cpu_compute(int *nbors, int start, int eflag, int vflag) { int i,j,jnum,itype,jtype,itable; double qtmp,xtmp,ytmp,ztmp,delx,dely,delz,evdwl,ecoul,fpair; double fraction,table; double r,r2inv,r6inv,forcecoul,forcelj,factor_coul,factor_lj; double grij,expm2,prefactor,t,erfc; double rsq; evdwl = ecoul = 0.0; double **x = atom->x; double **f = atom->f; double *q = atom->q; int *type = atom->type; int nlocal = atom->nlocal; int nall = nlocal + atom->nghost; int stride = nlocal-start; double *special_coul = force->special_coul; double *special_lj = force->special_lj; double qqrd2e = force->qqrd2e; // loop over neighbors of my atoms for (i = start; i < nlocal; i++) { qtmp = q[i]; xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; itype = type[i]; int *nbor = nbors + i - start; jnum = *nbor; nbor += stride; int *nbor_end = nbor + stride * jnum; for (; nbor<nbor_end; nbor+=stride) { j = *nbor; if (j < nall) factor_coul = factor_lj = 1.0; else { factor_coul = special_coul[j/nall]; factor_lj = special_lj[j/nall]; j %= nall; } delx = xtmp - x[j][0]; dely = ytmp - x[j][1]; delz = ztmp - x[j][2]; rsq = delx*delx + dely*dely + delz*delz; jtype = type[j]; if (rsq < cutsq[itype][jtype]) { r2inv = 1.0/rsq; if (rsq < cut_coulsq) { if (!ncoultablebits || rsq <= tabinnersq) { r = sqrt(rsq); grij = g_ewald * r; expm2 = exp(-grij*grij); t = 1.0 / (1.0 + EWALD_P*grij); erfc = t * (A1+t*(A2+t*(A3+t*(A4+t*A5)))) * expm2; prefactor = qqrd2e * qtmp*q[j]/r; forcecoul = prefactor * (erfc + EWALD_F*grij*expm2); if (factor_coul < 1.0) forcecoul -= (1.0-factor_coul)*prefactor; } else { union_int_float_t rsq_lookup; rsq_lookup.f = rsq; itable = rsq_lookup.i & ncoulmask; itable >>= ncoulshiftbits; fraction = (rsq_lookup.f - rtable[itable]) * drtable[itable]; table = ftable[itable] + fraction*dftable[itable]; forcecoul = qtmp*q[j] * table; if (factor_coul < 1.0) { table = ctable[itable] + fraction*dctable[itable]; prefactor = qtmp*q[j] * table; forcecoul -= (1.0-factor_coul)*prefactor; } } } else forcecoul = 0.0; if (rsq < cut_ljsq[itype][jtype]) { r6inv = r2inv*r2inv*r2inv; forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]); } else forcelj = 0.0; fpair = (forcecoul + factor_lj*forcelj) * r2inv; f[i][0] += delx*fpair; f[i][1] += dely*fpair; f[i][2] += delz*fpair; if (eflag) { if (rsq < cut_coulsq) { if (!ncoultablebits || rsq <= tabinnersq) ecoul = prefactor*erfc; else { table = etable[itable] + fraction*detable[itable]; ecoul = qtmp*q[j] * table; } if (factor_coul < 1.0) ecoul -= (1.0-factor_coul)*prefactor; } else ecoul = 0.0; if (rsq < cut_ljsq[itype][jtype]) { evdwl = r6inv*(lj3[itype][jtype]*r6inv-lj4[itype][jtype]) - offset[itype][jtype]; evdwl *= factor_lj; } else evdwl = 0.0; } if (j<start) { if (evflag) ev_tally_full(i,evdwl,ecoul,fpair,delx,dely,delz); } else { if (j<nlocal) { f[j][0] -= delx*fpair; f[j][1] -= dely*fpair; f[j][2] -= delz*fpair; } if (evflag) ev_tally(i,j,nlocal,0, evdwl,ecoul,fpair,delx,dely,delz); } } } } } diff --git a/src/GPU/pair_lj_cut_gpu.cpp b/src/GPU/pair_lj_cut_gpu.cpp index 1e7d952e1..ba2269d24 100644 --- a/src/GPU/pair_lj_cut_gpu.cpp +++ b/src/GPU/pair_lj_cut_gpu.cpp @@ -1,317 +1,322 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- Contributing author: Mike Brown (SNL) ------------------------------------------------------------------------- */ #include "math.h" #include "stdio.h" #include "stdlib.h" #include "pair_lj_cut_gpu.h" +#include "lmptype.h" #include "atom.h" #include "atom_vec.h" #include "comm.h" #include "force.h" #include "neighbor.h" #include "neigh_list.h" #include "integrate.h" #include "memory.h" #include "error.h" #include "neigh_request.h" #include "universe.h" #include "update.h" #include "domain.h" #include "string.h" #define MIN(a,b) ((a) < (b) ? (a) : (b)) #define MAX(a,b) ((a) > (b) ? (a) : (b)) // External functions from cuda library for atom decomposition bool ljl_gpu_init(const int ntypes, double **cutsq, double **host_lj1, double **host_lj2, double **host_lj3, double **host_lj4, double **offset, double *special_lj, const int nlocal, const int nall, const int max_nbors, const int maxspecial, const double cell_size, int &gpu_mode, FILE *screen); void ljl_gpu_clear(); int * ljl_gpu_compute_n(const int timestep, const int ago, const int inum, const int nall, double **host_x, int *host_type, double *boxlo, double *boxhi, int *tag, int **nspecial, int **special, const bool eflag, const bool vflag, const bool eatom, const bool vatom, int &host_start, const double cpu_time, bool &success); void ljl_gpu_compute(const int timestep, const int ago, const int inum, const int nall, double **host_x, int *host_type, int *ilist, int *numj, int **firstneigh, const bool eflag, const bool vflag, const bool eatom, const bool vatom, int &host_start, const double cpu_time, bool &success); double ljl_gpu_bytes(); using namespace LAMMPS_NS; /* ---------------------------------------------------------------------- */ PairLJCutGPU::PairLJCutGPU(LAMMPS *lmp) : PairLJCut(lmp), gpu_mode(GPU_PAIR) { respa_enable = 0; cpu_time = 0.0; } /* ---------------------------------------------------------------------- free all arrays ------------------------------------------------------------------------- */ PairLJCutGPU::~PairLJCutGPU() { ljl_gpu_clear(); } /* ---------------------------------------------------------------------- */ void PairLJCutGPU::compute(int eflag, int vflag) { + if (update->ntimestep > MAXSMALLINT) + error->all("Timestep too big for GPU pair style"); + int ntimestep = update->ntimestep; + if (eflag || vflag) ev_setup(eflag,vflag); else evflag = vflag_fdotr = 0; int nall = atom->nlocal + atom->nghost; int inum, host_start; bool success = true; if (gpu_mode == GPU_NEIGH) { inum = atom->nlocal; - gpulist = ljl_gpu_compute_n(update->ntimestep, neighbor->ago, inum, nall, + gpulist = ljl_gpu_compute_n(ntimestep, neighbor->ago, inum, nall, atom->x, atom->type, domain->sublo, domain->subhi, atom->tag, atom->nspecial, atom->special, eflag, vflag, eflag_atom, vflag_atom, host_start, cpu_time, success); } else { inum = list->inum; - ljl_gpu_compute(update->ntimestep, neighbor->ago, inum, nall, atom->x, + ljl_gpu_compute(ntimestep, neighbor->ago, inum, nall, atom->x, atom->type, list->ilist, list->numneigh, list->firstneigh, eflag, vflag, eflag_atom, vflag_atom, host_start, cpu_time, success); } if (!success) error->one("Out of memory on GPGPU"); if (host_start<inum) { cpu_time = MPI_Wtime(); if (gpu_mode == GPU_NEIGH) cpu_compute(gpulist, host_start, eflag, vflag); else cpu_compute(host_start, eflag, vflag); cpu_time = MPI_Wtime() - cpu_time; } } /* ---------------------------------------------------------------------- init specific to this pair style ------------------------------------------------------------------------- */ void PairLJCutGPU::init_style() { cut_respa = NULL; if (force->pair_match("gpu",0) == NULL) error->all("Cannot use pair hybrid with multiple GPU pair styles"); // Repeat cutsq calculation because done after call to init_style double maxcut = -1.0; double cut; for (int i = 1; i <= atom->ntypes; i++) { for (int j = i; j <= atom->ntypes; j++) { if (setflag[i][j] != 0 || (setflag[i][i] != 0 && setflag[j][j] != 0)) { cut = init_one(i,j); cut *= cut; if (cut > maxcut) maxcut = cut; cutsq[i][j] = cutsq[j][i] = cut; } else cutsq[i][j] = cutsq[j][i] = 0.0; } } double cell_size = sqrt(maxcut) + neighbor->skin; int maxspecial=0; if (atom->molecular) maxspecial=atom->maxspecial; bool init_ok = ljl_gpu_init(atom->ntypes+1, cutsq, lj1, lj2, lj3, lj4, offset, force->special_lj, atom->nlocal, atom->nlocal+atom->nghost, 300, maxspecial, cell_size, gpu_mode, screen); if (!init_ok) error->one("Insufficient memory on accelerator (or no fix gpu).\n"); if (force->newton_pair) error->all("Cannot use newton pair with GPU LJ pair style"); if (gpu_mode != GPU_NEIGH) { int irequest = neighbor->request(this); neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->full = 1; } } /* ---------------------------------------------------------------------- */ double PairLJCutGPU::memory_usage() { double bytes = Pair::memory_usage(); return bytes + ljl_gpu_bytes(); } /* ---------------------------------------------------------------------- */ void PairLJCutGPU::cpu_compute(int start, int eflag, int vflag) { int i,j,ii,jj,inum,jnum,itype,jtype; double xtmp,ytmp,ztmp,delx,dely,delz,evdwl,fpair; double rsq,r2inv,r6inv,forcelj,factor_lj; int *ilist,*jlist,*numneigh,**firstneigh; double **x = atom->x; double **f = atom->f; int *type = atom->type; int nlocal = atom->nlocal; int nall = nlocal + atom->nghost; double *special_lj = force->special_lj; inum = list->inum; ilist = list->ilist; numneigh = list->numneigh; firstneigh = list->firstneigh; // loop over neighbors of my atoms for (ii = start; ii < inum; ii++) { i = ilist[ii]; xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; itype = type[i]; jlist = firstneigh[i]; jnum = numneigh[i]; for (jj = 0; jj < jnum; jj++) { j = jlist[jj]; if (j < nall) factor_lj = 1.0; else { factor_lj = special_lj[j/nall]; j %= nall; } delx = xtmp - x[j][0]; dely = ytmp - x[j][1]; delz = ztmp - x[j][2]; rsq = delx*delx + dely*dely + delz*delz; jtype = type[j]; if (rsq < cutsq[itype][jtype]) { r2inv = 1.0/rsq; r6inv = r2inv*r2inv*r2inv; forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]); fpair = factor_lj*forcelj*r2inv; f[i][0] += delx*fpair; f[i][1] += dely*fpair; f[i][2] += delz*fpair; if (eflag) { evdwl = r6inv*(lj3[itype][jtype]*r6inv-lj4[itype][jtype]) - offset[itype][jtype]; evdwl *= factor_lj; } if (evflag) ev_tally_full(i,evdwl,0.0,fpair,delx,dely,delz); } } } } /* ---------------------------------------------------------------------- */ void PairLJCutGPU::cpu_compute(int *nbors, int start, int eflag, int vflag) { int i,j,itype,jtype; int nlocal = atom->nlocal; int nall = nlocal + atom->nghost; int stride = nlocal-start; double xtmp,ytmp,ztmp,delx,dely,delz,evdwl,fpair; double rsq,r2inv,r6inv,forcelj,factor_lj; double *special_lj = force->special_lj; double **x = atom->x; double **f = atom->f; int *type = atom->type; // loop over neighbors of my atoms for (i = start; i < nlocal; i++) { xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; itype = type[i]; int *nbor = nbors + i - start; int jnum = *nbor; nbor += stride; int *nbor_end = nbor + stride * jnum; for (; nbor<nbor_end; nbor+=stride) { j = *nbor; if (j < nall) factor_lj = 1.0; else { factor_lj = special_lj[j/nall]; j %= nall; } delx = xtmp - x[j][0]; dely = ytmp - x[j][1]; delz = ztmp - x[j][2]; rsq = delx*delx + dely*dely + delz*delz; jtype = type[j]; if (rsq < cutsq[itype][jtype]) { r2inv = 1.0/rsq; r6inv = r2inv*r2inv*r2inv; forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]); fpair = factor_lj*forcelj*r2inv; f[i][0] += delx*fpair; f[i][1] += dely*fpair; f[i][2] += delz*fpair; if (eflag) { evdwl = r6inv*(lj3[itype][jtype]*r6inv-lj4[itype][jtype]) - offset[itype][jtype]; evdwl *= factor_lj; } if (j<start) { if (evflag) ev_tally_full(i,evdwl,0.0,fpair,delx,dely,delz); } else { if (j<nlocal) { f[j][0] -= delx*fpair; f[j][1] -= dely*fpair; f[j][2] -= delz*fpair; } if (evflag) ev_tally(i,j,nlocal,0, evdwl,0.0,fpair,delx,dely,delz); } } } } } diff --git a/src/GRANULAR/atom_vec_granular.cpp b/src/GRANULAR/atom_vec_granular.cpp index 0a37ae8e9..0ebb38d8f 100644 --- a/src/GRANULAR/atom_vec_granular.cpp +++ b/src/GRANULAR/atom_vec_granular.cpp @@ -1,957 +1,960 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain 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_granular.h" +#include "lmptype.h" #include "atom.h" #include "domain.h" #include "modify.h" #include "force.h" #include "fix.h" #include "fix_adapt.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; #define DELTA 10000 /* ---------------------------------------------------------------------- */ AtomVecGranular::AtomVecGranular(LAMMPS *lmp, int narg, char **arg) : AtomVec(lmp, narg, arg) { 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->radius_flag = atom->density_flag = atom->rmass_flag = 1; atom->omega_flag = atom->torque_flag = 1; radvary = 0; PI = 4.0*atan(1.0); } /* ---------------------------------------------------------------------- */ void AtomVecGranular::init() { // set radvary if particle diameters are time-varying due to fix adapt 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; size_forward = 5; } } } /* ---------------------------------------------------------------------- grow atom arrays n = 0 grows arrays by DELTA n > 0 allocates arrays to size n ------------------------------------------------------------------------- */ void AtomVecGranular::grow(int n) { if (n == 0) nmax += DELTA; else nmax = n; atom->nmax = nmax; + if (nmax < 0 || nmax > MAXSMALLINT) + error->one("Per-processor system is too big"); tag = atom->tag = (int *) memory->srealloc(atom->tag,nmax*sizeof(int),"atom:tag"); type = atom->type = (int *) memory->srealloc(atom->type,nmax*sizeof(int),"atom:type"); mask = atom->mask = (int *) memory->srealloc(atom->mask,nmax*sizeof(int),"atom:mask"); image = atom->image = (int *) memory->srealloc(atom->image,nmax*sizeof(int),"atom:image"); x = atom->x = memory->grow_2d_double_array(atom->x,nmax,3,"atom:x"); v = atom->v = memory->grow_2d_double_array(atom->v,nmax,3,"atom:v"); f = atom->f = memory->grow_2d_double_array(atom->f,nmax,3,"atom:f"); radius = atom->radius = (double *) memory->srealloc(atom->radius,nmax*sizeof(double),"atom:radius"); density = atom->density = (double *) memory->srealloc(atom->density,nmax*sizeof(double),"atom:density"); rmass = atom->rmass = (double *) memory->srealloc(atom->rmass,nmax*sizeof(double),"atom:rmass"); omega = atom->omega = memory->grow_2d_double_array(atom->omega,nmax,3,"atom:omega"); torque = atom->torque = memory->grow_2d_double_array(atom->torque,nmax,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 AtomVecGranular::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; density = atom->density; rmass = atom->rmass; omega = atom->omega; torque = atom->torque; } /* ---------------------------------------------------------------------- */ void AtomVecGranular::copy(int i, int j) { 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]; density[j] = density[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); } /* ---------------------------------------------------------------------- */ int AtomVecGranular::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 AtomVecGranular::pack_comm_vel(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]; 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; } 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 { 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; } 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]; } } } return m; } /* ---------------------------------------------------------------------- */ int AtomVecGranular::pack_comm_one(int i, double *buf) { if (radvary == 0) return 0; buf[0] = radius[i]; buf[1] = rmass[i]; return 2; } /* ---------------------------------------------------------------------- */ void AtomVecGranular::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 AtomVecGranular::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 AtomVecGranular::unpack_comm_one(int i, double *buf) { if (radvary == 0) return 0; radius[i] = buf[0]; rmass[i] = buf[1]; return 2; } /* ---------------------------------------------------------------------- */ int AtomVecGranular::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 AtomVecGranular::pack_reverse_one(int i, double *buf) { buf[0] = torque[i][0]; buf[1] = torque[i][1]; buf[2] = torque[i][2]; return 3; } /* ---------------------------------------------------------------------- */ void AtomVecGranular::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 AtomVecGranular::unpack_reverse_one(int i, double *buf) { torque[i][0] += buf[0]; torque[i][1] += buf[1]; torque[i][2] += buf[2]; return 3; } /* ---------------------------------------------------------------------- */ int AtomVecGranular::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 AtomVecGranular::pack_border_vel(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]; 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]; } 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]; } } return m; } /* ---------------------------------------------------------------------- */ int AtomVecGranular::pack_border_one(int i, double *buf) { buf[0] = radius[i]; buf[1] = rmass[i]; return 2; } /* ---------------------------------------------------------------------- */ void AtomVecGranular::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 AtomVecGranular::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 AtomVecGranular::unpack_border_one(int i, double *buf) { radius[i] = buf[0]; rmass[i] = buf[1]; return 2; } /* ---------------------------------------------------------------------- pack data for atom I for sending to another proc xyz must be 1st 3 values, so comm::exchange() can test on them ------------------------------------------------------------------------- */ int AtomVecGranular::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]; buf[m++] = image[i]; buf[m++] = radius[i]; buf[m++] = density[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 AtomVecGranular::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] = static_cast<int> (buf[m++]); radius[nlocal] = buf[m++]; density[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 AtomVecGranular::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 AtomVecGranular::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]; 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++] = density[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 AtomVecGranular::unpack_restart(double *buf) { int nlocal = atom->nlocal; if (nlocal == nmax) { grow(0); if (atom->nextra_store) atom->extra = memory->grow_2d_double_array(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] = static_cast<int> (buf[m++]); v[nlocal][0] = buf[m++]; v[nlocal][1] = buf[m++]; v[nlocal][2] = buf[m++]; radius[nlocal] = buf[m++]; density[nlocal] = buf[m++]; if (radius[nlocal] == 0.0) rmass[nlocal] = density[nlocal]; else rmass[nlocal] = 4.0*PI/3.0 * radius[nlocal]*radius[nlocal]*radius[nlocal] * density[nlocal]; 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 AtomVecGranular::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] = (512 << 20) | (512 << 10) | 512; v[nlocal][0] = 0.0; v[nlocal][1] = 0.0; v[nlocal][2] = 0.0; radius[nlocal] = 0.5; density[nlocal] = 1.0; rmass[nlocal] = 4.0*PI/3.0 * radius[nlocal]*radius[nlocal]*radius[nlocal] * density[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 AtomVecGranular::data_atom(double *coord, int imagetmp, char **values) { int nlocal = atom->nlocal; if (nlocal == nmax) grow(0); tag[nlocal] = atoi(values[0]); if (tag[nlocal] <= 0) error->one("Invalid atom ID in Atoms section of data file"); type[nlocal] = atoi(values[1]); if (type[nlocal] <= 0 || type[nlocal] > atom->ntypes) error->one("Invalid atom type in Atoms section of data file"); radius[nlocal] = 0.5 * atof(values[2]); if (radius[nlocal] < 0.0) error->one("Invalid radius in Atoms section of data file"); density[nlocal] = atof(values[3]); if (density[nlocal] <= 0.0) error->one("Invalid density in Atoms section of data file"); if (radius[nlocal] == 0.0) rmass[nlocal] = density[nlocal]; else rmass[nlocal] = 4.0*PI/3.0 * radius[nlocal]*radius[nlocal]*radius[nlocal] * density[nlocal]; 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 AtomVecGranular::data_atom_hybrid(int nlocal, char **values) { radius[nlocal] = 0.5 * atof(values[0]); if (radius[nlocal] < 0.0) error->one("Invalid radius in Atoms section of data file"); density[nlocal] = atof(values[1]); if (density[nlocal] <= 0.0) error->one("Invalid density in Atoms section of data file"); if (radius[nlocal] == 0.0) rmass[nlocal] = density[nlocal]; else rmass[nlocal] = 4.0*PI/3.0 * radius[nlocal]*radius[nlocal]*radius[nlocal] * density[nlocal]; return 2; } /* ---------------------------------------------------------------------- unpack one line from Velocities section of data file ------------------------------------------------------------------------- */ void AtomVecGranular::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 AtomVecGranular::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; } /* ---------------------------------------------------------------------- return # of bytes of allocated memory ------------------------------------------------------------------------- */ double AtomVecGranular::memory_usage() { double bytes = 0.0; if (atom->memcheck("tag")) bytes += nmax * sizeof(int); if (atom->memcheck("type")) bytes += nmax * sizeof(int); if (atom->memcheck("mask")) bytes += nmax * sizeof(int); if (atom->memcheck("image")) bytes += nmax * sizeof(int); if (atom->memcheck("x")) bytes += nmax*3 * sizeof(double); if (atom->memcheck("v")) bytes += nmax*3 * sizeof(double); if (atom->memcheck("f")) bytes += nmax*3 * sizeof(double); if (atom->memcheck("radius")) bytes += nmax * sizeof(double); if (atom->memcheck("density")) bytes += nmax * sizeof(double); if (atom->memcheck("rmass")) bytes += nmax * sizeof(double); if (atom->memcheck("omega")) bytes += nmax*3 * sizeof(double); if (atom->memcheck("torque")) bytes += nmax*3 * sizeof(double); return bytes; } diff --git a/src/GRANULAR/fix_pour.cpp b/src/GRANULAR/fix_pour.cpp index 8b00fde01..0f54bbf79 100644 --- a/src/GRANULAR/fix_pour.cpp +++ b/src/GRANULAR/fix_pour.cpp @@ -1,577 +1,579 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ #include "math.h" #include "stdlib.h" #include "string.h" #include "fix_pour.h" #include "atom.h" #include "atom_vec.h" #include "force.h" #include "update.h" #include "comm.h" #include "modify.h" #include "fix_gravity.h" #include "domain.h" #include "region.h" #include "region_block.h" #include "region_cylinder.h" #include "random_park.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; #define EPSILON 0.001 /* ---------------------------------------------------------------------- */ FixPour::FixPour(LAMMPS *lmp, int narg, char **arg) : Fix(lmp, narg, arg) { if (narg < 6) error->all("Illegal fix pour command"); time_depend = 1; if (!atom->radius_flag || !atom->rmass_flag) error->all("Fix pour requires atom attributes radius, rmass"); // required args ninsert = atoi(arg[3]); ntype = atoi(arg[4]); seed = atoi(arg[5]); if (seed <= 0) error->all("Illegal fix pour command"); PI = 4.0*atan(1.0); // option defaults int iregion = -1; radius_lo = radius_hi = 0.5; density_lo = density_hi = 1.0; volfrac = 0.25; maxattempt = 50; rate = 0.0; vxlo = vxhi = vylo = vyhi = vy = vz = 0.0; // optional args int iarg = 6; while (iarg < narg) { if (strcmp(arg[iarg],"region") == 0) { if (iarg+2 > narg) error->all("Illegal fix pour command"); iregion = domain->find_region(arg[iarg+1]); if (iregion == -1) error->all("Fix pour region ID does not exist"); iarg += 2; } else if (strcmp(arg[iarg],"diam") == 0) { if (iarg+3 > narg) error->all("Illegal fix pour command"); radius_lo = 0.5 * atof(arg[iarg+1]); radius_hi = 0.5 * atof(arg[iarg+2]); iarg += 3; } else if (strcmp(arg[iarg],"dens") == 0) { if (iarg+3 > narg) error->all("Illegal fix pour command"); density_lo = atof(arg[iarg+1]); density_hi = atof(arg[iarg+2]); iarg += 3; } else if (strcmp(arg[iarg],"vol") == 0) { if (iarg+3 > narg) error->all("Illegal fix pour command"); volfrac = atof(arg[iarg+1]); maxattempt = atoi(arg[iarg+2]); iarg += 3; } else if (strcmp(arg[iarg],"rate") == 0) { if (iarg+2 > narg) error->all("Illegal fix pour command"); rate = atof(arg[iarg+1]); iarg += 2; } else if (strcmp(arg[iarg],"vel") == 0) { if (domain->dimension == 3) { if (iarg+6 > narg) error->all("Illegal fix pour command"); vxlo = atof(arg[iarg+1]); vxhi = atof(arg[iarg+2]); vylo = atof(arg[iarg+3]); vyhi = atof(arg[iarg+4]); vz = atof(arg[iarg+5]); iarg += 6; } else { if (iarg+4 > narg) error->all("Illegal fix pour command"); vxlo = atof(arg[iarg+1]); vxhi = atof(arg[iarg+2]); vy = atof(arg[iarg+3]); vz = 0.0; iarg += 4; } } else error->all("Illegal fix pour command"); } // error checks on region and its extent being inside simulation box if (iregion == -1) error->all("Must specify a region in fix pour"); if (domain->regions[iregion]->bboxflag == 0) error->all("Fix pour region does not support a bounding box"); if (domain->regions[iregion]->dynamic_check()) error->all("Fix pour region cannot be dynamic"); if (strcmp(domain->regions[iregion]->style,"block") == 0) { region_style = 1; xlo = ((RegBlock *) domain->regions[iregion])->xlo; xhi = ((RegBlock *) domain->regions[iregion])->xhi; ylo = ((RegBlock *) domain->regions[iregion])->ylo; yhi = ((RegBlock *) domain->regions[iregion])->yhi; zlo = ((RegBlock *) domain->regions[iregion])->zlo; zhi = ((RegBlock *) domain->regions[iregion])->zhi; if (xlo < domain->boxlo[0] || xhi > domain->boxhi[0] || ylo < domain->boxlo[1] || yhi > domain->boxhi[1] || zlo < domain->boxlo[2] || zhi > domain->boxhi[2]) error->all("Insertion region extends outside simulation box"); } else if (strcmp(domain->regions[iregion]->style,"cylinder") == 0) { region_style = 2; char axis = ((RegCylinder *) domain->regions[iregion])->axis; xc = ((RegCylinder *) domain->regions[iregion])->c1; yc = ((RegCylinder *) domain->regions[iregion])->c2; rc = ((RegCylinder *) domain->regions[iregion])->radius; zlo = ((RegCylinder *) domain->regions[iregion])->lo; zhi = ((RegCylinder *) domain->regions[iregion])->hi; if (axis != 'z') error->all("Must use a z-axis cylinder with fix pour"); if (xc-rc < domain->boxlo[0] || xc+rc > domain->boxhi[0] || yc-rc < domain->boxlo[1] || yc+rc > domain->boxhi[1] || zlo < domain->boxlo[2] || zhi > domain->boxhi[2]) error->all("Insertion region extends outside simulation box"); } else error->all("Must use a block or cylinder region with fix pour"); if (region_style == 2 && domain->dimension == 2) error->all("Must use a block region with fix pour for 2d simulations"); // random number generator, same for all procs random = new RanPark(lmp,seed); // allgather arrays MPI_Comm_rank(world,&me); MPI_Comm_size(world,&nprocs); recvcounts = new int[nprocs]; displs = new int[nprocs]; // grav = gravity in distance/time^2 units // assume grav = -magnitude at this point, enforce in init() int ifix; for (ifix = 0; ifix < modify->nfix; ifix++) if (strcmp(modify->fix[ifix]->style,"gravity") == 0) break; if (ifix == modify->nfix) error->all("No fix gravity defined for fix pour"); grav = - ((FixGravity *) modify->fix[ifix])->magnitude * force->ftm2v; // nfreq = timesteps between insertions // should be time for a particle to fall from top of insertion region // to bottom, taking into account that the region may be moving // set these 2 eqs equal to each other, solve for smallest positive t // x = zhi + vz*t + 1/2 grav t^2 // x = zlo + rate*t // gives t = [-(vz-rate) - sqrt((vz-rate)^2 - 2*grav*(zhi-zlo))] / grav // where zhi-zlo > 0, grav < 0, and vz & rate can be either > 0 or < 0 double v_relative,delta; if (domain->dimension == 3) { v_relative = vz - rate; delta = zhi - zlo; } else { v_relative = vy - rate; delta = yhi - ylo; } double t = (-v_relative - sqrt(v_relative*v_relative - 2.0*grav*delta)) / grav; nfreq = static_cast<int> (t/update->dt + 0.5); // 1st insertion on next timestep force_reneighbor = 1; next_reneighbor = update->ntimestep + 1; nfirst = next_reneighbor; ninserted = 0; // nper = # to insert each time // depends on specified volume fraction // volume = volume of insertion region // volume_one = volume of inserted particle (with max possible radius) // in 3d, insure dy >= 1, for quasi-2d simulations double volume,volume_one; if (domain->dimension == 3) { if (region_style == 1) { double dy = yhi - ylo; if (dy < 1.0) dy = 1.0; volume = (xhi-xlo) * dy * (zhi-zlo); } else volume = PI*rc*rc * (zhi-zlo); volume_one = 4.0/3.0 * PI * radius_hi*radius_hi*radius_hi; } else { volume = (xhi-xlo) * (yhi-ylo); volume_one = PI * radius_hi*radius_hi; } nper = static_cast<int> (volfrac*volume/volume_one); int nfinal = update->ntimestep + 1 + (ninsert-1)/nper * nfreq; // print stats if (me == 0) { if (screen) fprintf(screen, "Particle insertion: %d every %d steps, %d by step %d\n", nper,nfreq,ninsert,nfinal); if (logfile) fprintf(logfile, "Particle insertion: %d every %d steps, %d by step %d\n", nper,nfreq,ninsert,nfinal); } } /* ---------------------------------------------------------------------- */ FixPour::~FixPour() { delete random; delete [] recvcounts; delete [] displs; } /* ---------------------------------------------------------------------- */ int FixPour::setmask() { int mask = 0; mask |= PRE_EXCHANGE; return mask; } /* ---------------------------------------------------------------------- */ void FixPour::init() { if (domain->triclinic) error->all("Cannot use fix pour with triclinic box"); // insure gravity fix exists // for 3d must point in -z, for 2d must point in -y // else insertion cannot work int ifix; for (ifix = 0; ifix < modify->nfix; ifix++) if (strcmp(modify->fix[ifix]->style,"gravity") == 0) break; if (ifix == modify->nfix) error->all("No fix gravity defined for fix pour"); double xgrav = ((FixGravity *) modify->fix[ifix])->xgrav; double ygrav = ((FixGravity *) modify->fix[ifix])->ygrav; double zgrav = ((FixGravity *) modify->fix[ifix])->zgrav; if (domain->dimension == 3) { if (fabs(xgrav) > EPSILON || fabs(ygrav) > EPSILON || fabs(zgrav+1.0) > EPSILON) error->all("Gravity must point in -z to use with fix pour in 3d"); } else { if (fabs(xgrav) > EPSILON || fabs(ygrav+1.0) > EPSILON || fabs(zgrav) > EPSILON) error->all("Gravity must point in -y to use with fix pour in 2d"); } double gnew = - ((FixGravity *) modify->fix[ifix])->magnitude * force->ftm2v; if (gnew != grav) error->all("Gravity changed since fix pour was created"); } /* ---------------------------------------------------------------------- perform particle insertion ------------------------------------------------------------------------- */ void FixPour::pre_exchange() { int i; // just return if should not be called on this timestep if (next_reneighbor != update->ntimestep) return; // nnew = # to insert this timestep int nnew = nper; if (ninserted + nnew > ninsert) nnew = ninsert - ninserted; // lo/hi current = z (or y) bounds of insertion region this timestep if (domain->dimension == 3) { lo_current = zlo + (update->ntimestep - nfirst) * update->dt * rate; hi_current = zhi + (update->ntimestep - nfirst) * update->dt * rate; } else { lo_current = ylo + (update->ntimestep - nfirst) * update->dt * rate; hi_current = yhi + (update->ntimestep - nfirst) * update->dt * rate; } // ncount = # of my atoms that overlap the insertion region // nprevious = total of ncount across all procs int ncount = 0; for (i = 0; i < atom->nlocal; i++) if (overlap(i)) ncount++; int nprevious; MPI_Allreduce(&ncount,&nprevious,1,MPI_INT,MPI_SUM,world); // xmine is for my atoms // xnear is for atoms from all procs + atoms to be inserted double **xmine = memory->create_2d_double_array(ncount,4,"fix_pour:xmine"); double **xnear = memory->create_2d_double_array(nprevious+nnew,4,"fix_pour:xnear"); int nnear = nprevious; // setup for allgatherv int n = 4*ncount; MPI_Allgather(&n,1,MPI_INT,recvcounts,1,MPI_INT,world); displs[0] = 0; for (int iproc = 1; iproc < nprocs; iproc++) displs[iproc] = displs[iproc-1] + recvcounts[iproc-1]; // load up xmine array double **x = atom->x; double *radius = atom->radius; ncount = 0; for (i = 0; i < atom->nlocal; i++) if (overlap(i)) { xmine[ncount][0] = x[i][0]; xmine[ncount][1] = x[i][1]; xmine[ncount][2] = x[i][2]; xmine[ncount][3] = radius[i]; ncount++; } // perform allgatherv to acquire list of nearby particles on all procs double *ptr = NULL; if (ncount) ptr = xmine[0]; MPI_Allgatherv(ptr,4*ncount,MPI_DOUBLE, xnear[0],recvcounts,displs,MPI_DOUBLE,world); // insert new atoms into xnear list, one by one // check against all nearby atoms and previously inserted ones // if there is an overlap then try again at same z (3d) or y (2d) coord // else insert by adding to xnear list // max = maximum # of insertion attempts for all particles // h = height, biased to give uniform distribution in time of insertion int success; double coord[3],radtmp,delx,dely,delz,rsq,radsum,rn,h; int attempt = 0; int max = nnew * maxattempt; int ntotal = nprevious+nnew; while (nnear < ntotal) { rn = random->uniform(); h = hi_current - rn*rn * (hi_current-lo_current); radtmp = radius_lo + random->uniform() * (radius_hi-radius_lo); success = 0; while (attempt < max) { attempt++; xyz_random(h,coord); for (i = 0; i < nnear; i++) { delx = coord[0] - xnear[i][0]; dely = coord[1] - xnear[i][1]; delz = coord[2] - xnear[i][2]; rsq = delx*delx + dely*dely + delz*delz; radsum = radtmp + xnear[i][3]; if (rsq <= radsum*radsum) break; } if (i == nnear) { success = 1; break; } } if (success) { xnear[nnear][0] = coord[0]; xnear[nnear][1] = coord[1]; xnear[nnear][2] = coord[2]; xnear[nnear][3] = radtmp; nnear++; } else break; } // warn if not all insertions were performed ninserted += nnear-nprevious; if (nnear - nprevious < nnew && me == 0) error->warning("Less insertions than requested",0); // check if new atom is in my sub-box or above it if I'm highest proc // if so, add to my list via create_atom() // initialize info about the atom // type, diameter, density set from fix parameters // group mask set to "all" plus fix group // z velocity set to what velocity would be if particle // had fallen from top of insertion region // this gives continuous stream of atoms // solution for v from these 2 eqs, after eliminate t: // v = vz + grav*t // coord[2] = hi_current + vz*t + 1/2 grav t^2 // set npartner for new atom to 0 (assume not touching any others) AtomVec *avec = atom->avec; int j,m,flag; double denstmp,vxtmp,vytmp,vztmp; double *sublo = domain->sublo; double *subhi = domain->subhi; int nfix = modify->nfix; Fix **fix = modify->fix; for (i = nprevious; i < nnear; i++) { coord[0] = xnear[i][0]; coord[1] = xnear[i][1]; coord[2] = xnear[i][2]; radtmp = xnear[i][3]; denstmp = density_lo + random->uniform() * (density_hi-density_lo); if (domain->dimension == 3) { vxtmp = vxlo + random->uniform() * (vxhi-vxlo); vytmp = vylo + random->uniform() * (vyhi-vylo); vztmp = -sqrt(vz*vz + 2.0*grav*(coord[2]-hi_current)); } else { vxtmp = vxlo + random->uniform() * (vxhi-vxlo); vytmp = -sqrt(vy*vy + 2.0*grav*(coord[1]-hi_current)); vztmp = 0.0; } flag = 0; if (coord[0] >= sublo[0] && coord[0] < subhi[0] && coord[1] >= sublo[1] && coord[1] < subhi[1] && coord[2] >= sublo[2] && coord[2] < subhi[2]) flag = 1; else if (domain->dimension == 3 && coord[2] >= domain->boxhi[2] && comm->myloc[2] == comm->procgrid[2]-1 && coord[0] >= sublo[0] && coord[0] < subhi[0] && coord[1] >= sublo[1] && coord[1] < subhi[1]) flag = 1; else if (domain->dimension == 2 && coord[1] >= domain->boxhi[1] && comm->myloc[1] == comm->procgrid[1]-1 && coord[0] >= sublo[0] && coord[0] < subhi[0]) flag = 1; if (flag) { avec->create_atom(ntype,coord); m = atom->nlocal - 1; atom->type[m] = ntype; atom->radius[m] = radtmp; atom->density[m] = denstmp; atom->rmass[m] = 4.0*PI/3.0 * radtmp*radtmp*radtmp * denstmp; atom->mask[m] = 1 | groupbit; atom->v[m][0] = vxtmp; atom->v[m][1] = vytmp; atom->v[m][2] = vztmp; for (j = 0; j < nfix; j++) if (fix[j]->create_attribute) fix[j]->set_arrays(m); } } - // set tag # of new particles beyond all previous atoms // reset global natoms + // set tag # of new particles beyond all previous atoms // if global map exists, reset it now instead of waiting for comm // since deleting atoms messes up ghosts - if (atom->tag_enable) { - atom->tag_extend(); + if (nnear - nprevious > 0) { atom->natoms += nnear - nprevious; - if (atom->map_style) { - atom->nghost = 0; - atom->map_init(); - atom->map_set(); + if (atom->tag_enable) { + atom->tag_extend(); + if (atom->map_style) { + atom->nghost = 0; + atom->map_init(); + atom->map_set(); + } } } // free local memory memory->destroy_2d_double_array(xmine); memory->destroy_2d_double_array(xnear); // next timestep to insert if (ninserted < ninsert) next_reneighbor += nfreq; else next_reneighbor = 0; } /* ---------------------------------------------------------------------- check if particle i could overlap with a particle inserted into region return 1 if yes, 0 if no use maximum diameter for inserted particle ------------------------------------------------------------------------- */ int FixPour::overlap(int i) { double delta = radius_hi + atom->radius[i]; double **x = atom->x; if (domain->dimension == 3) { if (region_style == 1) { if (x[i][0] < xlo-delta || x[i][0] > xhi+delta || x[i][1] < ylo-delta || x[i][1] > yhi+delta || x[i][2] < lo_current-delta || x[i][2] > hi_current+delta) return 0; } else { if (x[i][2] < lo_current-delta || x[i][2] > hi_current+delta) return 0; double delx = x[i][0] - xc; double dely = x[i][1] - yc; double rsq = delx*delx + dely*dely; double r = rc + delta; if (rsq > r*r) return 0; } } else { if (x[i][0] < xlo-delta || x[i][0] > xhi+delta || x[i][1] < lo_current-delta || x[i][1] > hi_current+delta) return 0; } return 1; } /* ---------------------------------------------------------------------- */ void FixPour::xyz_random(double h, double *coord) { if (domain->dimension == 3) { if (region_style == 1) { coord[0] = xlo + random->uniform() * (xhi-xlo); coord[1] = ylo + random->uniform() * (yhi-ylo); coord[2] = h; } else { double r1,r2; while (1) { r1 = random->uniform() - 0.5; r2 = random->uniform() - 0.5; if (r1*r1 + r2*r2 < 0.25) break; } coord[0] = xc + 2.0*r1*rc; coord[1] = yc + 2.0*r2*rc; coord[2] = h; } } else { coord[0] = xlo + random->uniform() * (xhi-xlo); coord[1] = h; coord[2] = 0.0; } } /* ---------------------------------------------------------------------- */ void FixPour::reset_dt() { error->all("Cannot change timestep with fix pour"); } diff --git a/src/MANYBODY/fix_qeq_comb.cpp b/src/MANYBODY/fix_qeq_comb.cpp index b8f13964f..7c91cd51c 100644 --- a/src/MANYBODY/fix_qeq_comb.cpp +++ b/src/MANYBODY/fix_qeq_comb.cpp @@ -1,253 +1,257 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- Contributing author: Tzu-Ray Shan (U Florida, rayshan@ufl.edu) ------------------------------------------------------------------------- */ #include "mpi.h" #include "math.h" #include "stdlib.h" #include "string.h" #include "fix_qeq_comb.h" +#include "lmptype.h" #include "atom.h" #include "force.h" #include "group.h" #include "respa.h" #include "pair_comb.h" #include "update.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; #define MIN(A,B) ((A) < (B)) ? (A) : (B) #define MAX(A,B) ((A) > (B)) ? (A) : (B) /* ---------------------------------------------------------------------- */ FixQEQComb::FixQEQComb(LAMMPS *lmp, int narg, char **arg) : Fix(lmp, narg, arg) { if (narg < 5) error->all("Illegal fix qeq/comb command"); peratom_flag = 1; size_peratom_cols = 0; peratom_freq = 1; nevery = force->inumeric(arg[3]); precision = force->numeric(arg[4]); if (nevery <= 0 || precision <= 0.0) error->all("Illegal fix qeq/comb command"); MPI_Comm_rank(world,&me); // optional args fp = NULL; int iarg = 5; while (iarg < narg) { if (strcmp(arg[iarg],"file") == 0) { if (iarg+2 > narg) error->all("Illegal fix qeq/comb command"); if (me == 0) { fp = fopen(arg[iarg+1],"w"); if (fp == NULL) { char str[128]; sprintf(str,"Cannot open fix qeq/comb file %s",arg[iarg+1]); error->one(str); } } iarg += 2; } else error->all("Illegal fix qeq/comb command"); } nmax = atom->nmax; qf = (double *) memory->smalloc(nmax*sizeof(double),"qeq:qf"); q1 = (double *) memory->smalloc(nmax*sizeof(double),"qeq:q1"); q2 = (double *) memory->smalloc(nmax*sizeof(double),"qeq:q2"); vector_atom = qf; // zero the vector since dump may access it on timestep 0 // zero the vector since a variable may access it before first run int nlocal = atom->nlocal; for (int i = 0; i < nlocal; i++) qf[i] = 0.0; } /* ---------------------------------------------------------------------- */ FixQEQComb::~FixQEQComb() { if (me == 0 && fp) fclose(fp); memory->sfree(qf); memory->sfree(q1); memory->sfree(q2); } /* ---------------------------------------------------------------------- */ int FixQEQComb::setmask() { int mask = 0; mask |= POST_FORCE; mask |= POST_FORCE_RESPA; return mask; } /* ---------------------------------------------------------------------- */ void FixQEQComb::init() { if (!atom->q_flag) error->all("Fix qeq/comb requires atom attribute q"); comb = (PairComb *) force->pair_match("comb",1); if (comb == NULL) error->all("Must use pair_style comb with fix qeq/comb"); if (strcmp(update->integrate_style,"respa") == 0) nlevels_respa = ((Respa *) update->integrate)->nlevels; ngroup = group->count(igroup); if (ngroup == 0) error->all("Fix qeq/comb group has no atoms"); } /* ---------------------------------------------------------------------- */ void FixQEQComb::setup(int vflag) { firstflag = 1; if (strcmp(update->integrate_style,"verlet") == 0) post_force(vflag); else { ((Respa *) update->integrate)->copy_flevel_f(nlevels_respa-1); post_force_respa(vflag,nlevels_respa-1,0); ((Respa *) update->integrate)->copy_f_flevel(nlevels_respa-1); } firstflag = 0; } /* ---------------------------------------------------------------------- */ void FixQEQComb::post_force(int vflag) { int i,iloop,loopmax; double heatpq,qmass,dtq,dtq2; double enegchkall,enegmaxall; if (update->ntimestep % nevery) return; // reallocate work arrays if necessary // qf = charge force // q1 = charge displacement // q2 = tmp storage of charge force for next iteration if (atom->nmax > nmax) { memory->sfree(qf); memory->sfree(q1); memory->sfree(q2); nmax = atom->nmax; qf = (double *) memory->smalloc(nmax*sizeof(double),"qeq:qf"); q1 = (double *) memory->smalloc(nmax*sizeof(double),"qeq:q1"); q2 = (double *) memory->smalloc(nmax*sizeof(double),"qeq:q2"); vector_atom = qf; } // more loops for first-time charge equilibrium iloop = 0; if (firstflag) loopmax = 1000; else loopmax = 500; // charge-equilibration loop - if (me == 0 && fp) - fprintf(fp,"Charge equilibration on step %d\n",update->ntimestep); + if (me == 0 && fp) { + char fstr[64]; + sprintf(fstr,"Charge equilibration on step %s\n",BIGINT_FORMAT); + fprintf(fp,fstr,update->ntimestep); + } heatpq = 0.01; qmass = 0.06; dtq = 0.040; dtq2 = 0.5*dtq*dtq/qmass; double enegchk = 0.0; double enegtot = 0.0; double enegmax = 0.0; double *q = atom->q; int *mask = atom->mask; int nlocal = atom->nlocal; for (i = 0; i < nlocal; i++) q1[i] = q2[i] = qf[i] = 0.0; for (iloop = 0; iloop < loopmax; iloop ++ ) { for (i = 0; i < nlocal; i++) if (mask[i] & groupbit) { q1[i] = qf[i]*dtq2 - heatpq*q1[i]; q[i] += q1[i]; } enegtot = comb->yasu_char(qf,igroup); enegtot /= ngroup; enegchk = enegmax = 0.0; for (i = 0; i < nlocal ; i++) if (mask[i] & groupbit) { q2[i] = enegtot-qf[i]; enegmax = MAX(enegmax,fabs(q2[i])); enegchk += fabs(q2[i]); qf[i] = q2[i]; } MPI_Allreduce(&enegchk,&enegchkall,1,MPI_DOUBLE,MPI_SUM,world); enegchk = enegchkall/ngroup; MPI_Allreduce(&enegmax,&enegmaxall,1,MPI_DOUBLE,MPI_MAX,world); enegmax = enegmaxall; if (enegchk <= precision && enegmax <= 10.0*precision) break; if (me == 0 && fp) fprintf(fp," iteration: %d, enegtot %.6g, " "enegmax %.6g, fq deviation: %.6g\n", iloop,enegtot,enegmax,enegchk); for (i = 0; i < nlocal; i++) if (mask[i] & groupbit) q1[i] += qf[i]*dtq2 - heatpq*q1[i]; } if (me == 0 && fp) { if (iloop == loopmax) fprintf(fp,"Charges did not converge in %d iterations\n",iloop); else fprintf(fp,"Charges converged in %d iterations to %.10f tolerance\n", iloop,enegchk); } } /* ---------------------------------------------------------------------- */ void FixQEQComb::post_force_respa(int vflag, int ilevel, int iloop) { if (ilevel == nlevels_respa-1) post_force(vflag); } /* ---------------------------------------------------------------------- memory usage of local atom-based arrays ------------------------------------------------------------------------- */ double FixQEQComb::memory_usage() { double bytes = atom->nmax*3 * sizeof(double); return bytes; } diff --git a/src/MOLECULE/atom_vec_angle.cpp b/src/MOLECULE/atom_vec_angle.cpp index 6789db500..33390ee34 100644 --- a/src/MOLECULE/atom_vec_angle.cpp +++ b/src/MOLECULE/atom_vec_angle.cpp @@ -1,811 +1,814 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ #include "stdlib.h" #include "atom_vec_angle.h" +#include "lmptype.h" #include "atom.h" #include "domain.h" #include "modify.h" #include "fix.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; #define MIN(A,B) ((A) < (B)) ? (A) : (B) #define MAX(A,B) ((A) > (B)) ? (A) : (B) #define DELTA 10000 /* ---------------------------------------------------------------------- */ AtomVecAngle::AtomVecAngle(LAMMPS *lmp, int narg, char **arg) : AtomVec(lmp, narg, arg) { molecular = 1; bonds_allow = angles_allow = 1; mass_type = 1; comm_x_only = comm_f_only = 1; size_forward = 3; size_reverse = 3; size_border = 7; size_velocity = 3; size_data_atom = 6; size_data_vel = 4; xcol_data = 4; atom->molecule_flag = 1; } /* ---------------------------------------------------------------------- grow atom arrays n = 0 grows arrays by DELTA n > 0 allocates arrays to size n ------------------------------------------------------------------------- */ void AtomVecAngle::grow(int n) { if (n == 0) nmax += DELTA; else nmax = n; atom->nmax = nmax; + if (nmax < 0 || nmax > MAXSMALLINT) + error->one("Per-processor system is too big"); tag = atom->tag = (int *) memory->srealloc(atom->tag,nmax*sizeof(int),"atom:tag"); type = atom->type = (int *) memory->srealloc(atom->type,nmax*sizeof(int),"atom:type"); mask = atom->mask = (int *) memory->srealloc(atom->mask,nmax*sizeof(int),"atom:mask"); image = atom->image = (int *) memory->srealloc(atom->image,nmax*sizeof(int),"atom:image"); x = atom->x = memory->grow_2d_double_array(atom->x,nmax,3,"atom:x"); v = atom->v = memory->grow_2d_double_array(atom->v,nmax,3,"atom:v"); f = atom->f = memory->grow_2d_double_array(atom->f,nmax,3,"atom:f"); molecule = atom->molecule = (int *) memory->srealloc(atom->molecule,nmax*sizeof(int),"atom:molecule"); nspecial = atom->nspecial = memory->grow_2d_int_array(atom->nspecial,nmax,3,"atom:nspecial"); special = atom->special = memory->grow_2d_int_array(atom->special,nmax,atom->maxspecial, "atom:special"); num_bond = atom->num_bond = (int *) memory->srealloc(atom->num_bond,nmax*sizeof(int),"atom:num_bond"); bond_type = atom->bond_type = memory->grow_2d_int_array(atom->bond_type,nmax,atom->bond_per_atom, "atom:bond_type"); bond_atom = atom->bond_atom = memory->grow_2d_int_array(atom->bond_atom,nmax,atom->bond_per_atom, "atom:bond_atom"); num_angle = atom->num_angle = (int *) memory->srealloc(atom->num_angle,nmax*sizeof(int),"atom:num_angle"); angle_type = atom->angle_type = memory->grow_2d_int_array(atom->angle_type,nmax,atom->angle_per_atom, "atom:angle_type"); angle_atom1 = atom->angle_atom1 = memory->grow_2d_int_array(atom->angle_atom1,nmax,atom->angle_per_atom, "atom:angle_atom1"); angle_atom2 = atom->angle_atom2 = memory->grow_2d_int_array(atom->angle_atom2,nmax,atom->angle_per_atom, "atom:angle_atom2"); angle_atom3 = atom->angle_atom3 = memory->grow_2d_int_array(atom->angle_atom3,nmax,atom->angle_per_atom, "atom:angle_atom3"); if (atom->nextra_grow) for (int iextra = 0; iextra < atom->nextra_grow; iextra++) modify->fix[atom->extra_grow[iextra]]->grow_arrays(nmax); } /* ---------------------------------------------------------------------- reset local array ptrs ------------------------------------------------------------------------- */ void AtomVecAngle::grow_reset() { tag = atom->tag; type = atom->type; mask = atom->mask; image = atom->image; x = atom->x; v = atom->v; f = atom->f; molecule = atom->molecule; nspecial = atom->nspecial; special = atom->special; num_bond = atom->num_bond; bond_type = atom->bond_type; bond_atom = atom->bond_atom; num_angle = atom->num_angle; angle_type = atom->angle_type; angle_atom1 = atom->angle_atom1; angle_atom2 = atom->angle_atom2; angle_atom3 = atom->angle_atom3; } /* ---------------------------------------------------------------------- */ void AtomVecAngle::copy(int i, int j) { int k; tag[j] = tag[i]; type[j] = type[i]; mask[j] = mask[i]; image[j] = image[i]; x[j][0] = x[i][0]; x[j][1] = x[i][1]; x[j][2] = x[i][2]; v[j][0] = v[i][0]; v[j][1] = v[i][1]; v[j][2] = v[i][2]; molecule[j] = molecule[i]; num_bond[j] = num_bond[i]; for (k = 0; k < num_bond[j]; k++) { bond_type[j][k] = bond_type[i][k]; bond_atom[j][k] = bond_atom[i][k]; } num_angle[j] = num_angle[i]; for (k = 0; k < num_angle[j]; k++) { angle_type[j][k] = angle_type[i][k]; angle_atom1[j][k] = angle_atom1[i][k]; angle_atom2[j][k] = angle_atom2[i][k]; angle_atom3[j][k] = angle_atom3[i][k]; } nspecial[j][0] = nspecial[i][0]; nspecial[j][1] = nspecial[i][1]; nspecial[j][2] = nspecial[i][2]; for (k = 0; k < nspecial[j][2]; k++) special[j][k] = special[i][k]; if (atom->nextra_grow) for (int iextra = 0; iextra < atom->nextra_grow; iextra++) modify->fix[atom->extra_grow[iextra]]->copy_arrays(i,j); } /* ---------------------------------------------------------------------- */ int AtomVecAngle::pack_comm(int n, int *list, double *buf, int pbc_flag, int *pbc) { int i,j,m; double dx,dy,dz; m = 0; if (pbc_flag == 0) { for (i = 0; i < n; i++) { j = list[i]; buf[m++] = x[j][0]; buf[m++] = x[j][1]; buf[m++] = x[j][2]; } } else { if (domain->triclinic == 0) { dx = pbc[0]*domain->xprd; dy = pbc[1]*domain->yprd; dz = pbc[2]*domain->zprd; } else { dx = pbc[0]*domain->xprd + pbc[5]*domain->xy + pbc[4]*domain->xz; dy = pbc[1]*domain->yprd + pbc[3]*domain->yz; dz = pbc[2]*domain->zprd; } for (i = 0; i < n; i++) { j = list[i]; buf[m++] = x[j][0] + dx; buf[m++] = x[j][1] + dy; buf[m++] = x[j][2] + dz; } } return m; } /* ---------------------------------------------------------------------- */ int AtomVecAngle::pack_comm_vel(int n, int *list, double *buf, int pbc_flag, int *pbc) { int i,j,m; double dx,dy,dz; m = 0; if (pbc_flag == 0) { for (i = 0; i < n; i++) { j = list[i]; buf[m++] = x[j][0]; buf[m++] = x[j][1]; buf[m++] = x[j][2]; buf[m++] = v[j][0]; buf[m++] = v[j][1]; buf[m++] = v[j][2]; } } else { if (domain->triclinic == 0) { dx = pbc[0]*domain->xprd; dy = pbc[1]*domain->yprd; dz = pbc[2]*domain->zprd; } else { dx = pbc[0]*domain->xprd + pbc[5]*domain->xy + pbc[4]*domain->xz; dy = pbc[1]*domain->yprd + pbc[3]*domain->yz; dz = pbc[2]*domain->zprd; } 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]; } } return m; } /* ---------------------------------------------------------------------- */ void AtomVecAngle::unpack_comm(int n, int first, double *buf) { int i,m,last; m = 0; last = first + n; for (i = first; i < last; i++) { x[i][0] = buf[m++]; x[i][1] = buf[m++]; x[i][2] = buf[m++]; } } /* ---------------------------------------------------------------------- */ void AtomVecAngle::unpack_comm_vel(int n, int first, double *buf) { int i,m,last; m = 0; last = first + n; for (i = first; i < last; i++) { x[i][0] = buf[m++]; x[i][1] = buf[m++]; x[i][2] = buf[m++]; v[i][0] = buf[m++]; v[i][1] = buf[m++]; v[i][2] = buf[m++]; } } /* ---------------------------------------------------------------------- */ int AtomVecAngle::pack_reverse(int n, int first, double *buf) { int i,m,last; m = 0; last = first + n; for (i = first; i < last; i++) { buf[m++] = f[i][0]; buf[m++] = f[i][1]; buf[m++] = f[i][2]; } return m; } /* ---------------------------------------------------------------------- */ void AtomVecAngle::unpack_reverse(int n, int *list, double *buf) { int i,j,m; m = 0; for (i = 0; i < n; i++) { j = list[i]; f[j][0] += buf[m++]; f[j][1] += buf[m++]; f[j][2] += buf[m++]; } } /* ---------------------------------------------------------------------- */ int AtomVecAngle::pack_border(int n, int *list, double *buf, int pbc_flag, int *pbc) { int i,j,m; double dx,dy,dz; m = 0; if (pbc_flag == 0) { for (i = 0; i < n; i++) { j = list[i]; buf[m++] = x[j][0]; buf[m++] = x[j][1]; buf[m++] = x[j][2]; buf[m++] = tag[j]; buf[m++] = type[j]; buf[m++] = mask[j]; buf[m++] = molecule[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++] = molecule[j]; } } return m; } /* ---------------------------------------------------------------------- */ int AtomVecAngle::pack_border_vel(int n, int *list, double *buf, int pbc_flag, int *pbc) { int i,j,m; double dx,dy,dz; 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++] = molecule[j]; buf[m++] = v[j][0]; buf[m++] = v[j][1]; buf[m++] = v[j][2]; } } else { if (domain->triclinic == 0) { dx = pbc[0]*domain->xprd; dy = pbc[1]*domain->yprd; dz = pbc[2]*domain->zprd; } else { dx = pbc[0]; dy = pbc[1]; dz = pbc[2]; } 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++] = molecule[j]; buf[m++] = v[j][0]; buf[m++] = v[j][1]; buf[m++] = v[j][2]; } } return m; } /* ---------------------------------------------------------------------- */ int AtomVecAngle::pack_border_one(int i, double *buf) { buf[0] = molecule[i]; return 1; } /* ---------------------------------------------------------------------- */ void AtomVecAngle::unpack_border(int n, int first, double *buf) { int i,m,last; m = 0; last = first + n; for (i = first; i < last; i++) { if (i == nmax) grow(0); x[i][0] = buf[m++]; x[i][1] = buf[m++]; x[i][2] = buf[m++]; tag[i] = static_cast<int> (buf[m++]); type[i] = static_cast<int> (buf[m++]); mask[i] = static_cast<int> (buf[m++]); molecule[i] = static_cast<int> (buf[m++]); } } /* ---------------------------------------------------------------------- */ void AtomVecAngle::unpack_border_vel(int n, int first, double *buf) { int i,m,last; m = 0; last = first + n; for (i = first; i < last; i++) { if (i == nmax) grow(0); x[i][0] = buf[m++]; x[i][1] = buf[m++]; x[i][2] = buf[m++]; tag[i] = static_cast<int> (buf[m++]); type[i] = static_cast<int> (buf[m++]); mask[i] = static_cast<int> (buf[m++]); molecule[i] = static_cast<int> (buf[m++]); v[i][0] = buf[m++]; v[i][1] = buf[m++]; v[i][2] = buf[m++]; } } /* ---------------------------------------------------------------------- */ int AtomVecAngle::unpack_border_one(int i, double *buf) { molecule[i] = static_cast<int> (buf[0]); return 1; } /* ---------------------------------------------------------------------- pack data for atom I for sending to another proc xyz must be 1st 3 values, so comm::exchange() can test on them ------------------------------------------------------------------------- */ int AtomVecAngle::pack_exchange(int i, double *buf) { int k; int m = 1; buf[m++] = x[i][0]; buf[m++] = x[i][1]; buf[m++] = x[i][2]; buf[m++] = v[i][0]; buf[m++] = v[i][1]; buf[m++] = v[i][2]; buf[m++] = tag[i]; buf[m++] = type[i]; buf[m++] = mask[i]; buf[m++] = image[i]; buf[m++] = molecule[i]; buf[m++] = num_bond[i]; for (k = 0; k < num_bond[i]; k++) { buf[m++] = bond_type[i][k]; buf[m++] = bond_atom[i][k]; } buf[m++] = num_angle[i]; for (k = 0; k < num_angle[i]; k++) { buf[m++] = angle_type[i][k]; buf[m++] = angle_atom1[i][k]; buf[m++] = angle_atom2[i][k]; buf[m++] = angle_atom3[i][k]; } buf[m++] = nspecial[i][0]; buf[m++] = nspecial[i][1]; buf[m++] = nspecial[i][2]; for (k = 0; k < nspecial[i][2]; k++) buf[m++] = special[i][k]; if (atom->nextra_grow) for (int iextra = 0; iextra < atom->nextra_grow; iextra++) m += modify->fix[atom->extra_grow[iextra]]->pack_exchange(i,&buf[m]); buf[0] = m; return m; } /* ---------------------------------------------------------------------- */ int AtomVecAngle::unpack_exchange(double *buf) { int k; int nlocal = atom->nlocal; if (nlocal == nmax) grow(0); int m = 1; x[nlocal][0] = buf[m++]; x[nlocal][1] = buf[m++]; x[nlocal][2] = buf[m++]; v[nlocal][0] = buf[m++]; v[nlocal][1] = buf[m++]; v[nlocal][2] = buf[m++]; tag[nlocal] = static_cast<int> (buf[m++]); type[nlocal] = static_cast<int> (buf[m++]); mask[nlocal] = static_cast<int> (buf[m++]); image[nlocal] = static_cast<int> (buf[m++]); molecule[nlocal] = static_cast<int> (buf[m++]); num_bond[nlocal] = static_cast<int> (buf[m++]); for (k = 0; k < num_bond[nlocal]; k++) { bond_type[nlocal][k] = static_cast<int> (buf[m++]); bond_atom[nlocal][k] = static_cast<int> (buf[m++]); } num_angle[nlocal] = static_cast<int> (buf[m++]); for (k = 0; k < num_angle[nlocal]; k++) { angle_type[nlocal][k] = static_cast<int> (buf[m++]); angle_atom1[nlocal][k] = static_cast<int> (buf[m++]); angle_atom2[nlocal][k] = static_cast<int> (buf[m++]); angle_atom3[nlocal][k] = static_cast<int> (buf[m++]); } nspecial[nlocal][0] = static_cast<int> (buf[m++]); nspecial[nlocal][1] = static_cast<int> (buf[m++]); nspecial[nlocal][2] = static_cast<int> (buf[m++]); for (k = 0; k < nspecial[nlocal][2]; k++) special[nlocal][k] = static_cast<int> (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 AtomVecAngle::size_restart() { int i; int nlocal = atom->nlocal; int n = 0; for (i = 0; i < nlocal; i++) n += 14 + 2*num_bond[i] + 4*num_angle[i]; if (atom->nextra_restart) for (int iextra = 0; iextra < atom->nextra_restart; iextra++) for (i = 0; i < nlocal; i++) n += modify->fix[atom->extra_restart[iextra]]->size_restart(i); return n; } /* ---------------------------------------------------------------------- pack atom I's data for restart file including extra quantities xyz must be 1st 3 values, so that read_restart can test on them molecular types may be negative, but write as positive ------------------------------------------------------------------------- */ int AtomVecAngle::pack_restart(int i, double *buf) { int k; int m = 1; buf[m++] = x[i][0]; buf[m++] = x[i][1]; buf[m++] = x[i][2]; buf[m++] = tag[i]; buf[m++] = type[i]; buf[m++] = mask[i]; buf[m++] = image[i]; buf[m++] = v[i][0]; buf[m++] = v[i][1]; buf[m++] = v[i][2]; buf[m++] = molecule[i]; buf[m++] = num_bond[i]; for (k = 0; k < num_bond[i]; k++) { buf[m++] = MAX(bond_type[i][k],-bond_type[i][k]); buf[m++] = bond_atom[i][k]; } buf[m++] = num_angle[i]; for (k = 0; k < num_angle[i]; k++) { buf[m++] = MAX(angle_type[i][k],-angle_type[i][k]); buf[m++] = angle_atom1[i][k]; buf[m++] = angle_atom2[i][k]; buf[m++] = angle_atom3[i][k]; } if (atom->nextra_restart) for (int iextra = 0; iextra < atom->nextra_restart; iextra++) m += modify->fix[atom->extra_restart[iextra]]->pack_restart(i,&buf[m]); buf[0] = m; return m; } /* ---------------------------------------------------------------------- unpack data for one atom from restart file including extra quantities ------------------------------------------------------------------------- */ int AtomVecAngle::unpack_restart(double *buf) { int k; int nlocal = atom->nlocal; if (nlocal == nmax) { grow(0); if (atom->nextra_store) atom->extra = memory->grow_2d_double_array(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] = static_cast<int> (buf[m++]); v[nlocal][0] = buf[m++]; v[nlocal][1] = buf[m++]; v[nlocal][2] = buf[m++]; molecule[nlocal] = static_cast<int> (buf[m++]); num_bond[nlocal] = static_cast<int> (buf[m++]); for (k = 0; k < num_bond[nlocal]; k++) { bond_type[nlocal][k] = static_cast<int> (buf[m++]); bond_atom[nlocal][k] = static_cast<int> (buf[m++]); } num_angle[nlocal] = static_cast<int> (buf[m++]); for (k = 0; k < num_angle[nlocal]; k++) { angle_type[nlocal][k] = static_cast<int> (buf[m++]); angle_atom1[nlocal][k] = static_cast<int> (buf[m++]); angle_atom2[nlocal][k] = static_cast<int> (buf[m++]); angle_atom3[nlocal][k] = static_cast<int> (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 AtomVecAngle::create_atom(int itype, double *coord) { int nlocal = atom->nlocal; if (nlocal == nmax) grow(0); tag[nlocal] = 0; type[nlocal] = itype; x[nlocal][0] = coord[0]; x[nlocal][1] = coord[1]; x[nlocal][2] = coord[2]; mask[nlocal] = 1; image[nlocal] = (512 << 20) | (512 << 10) | 512; v[nlocal][0] = 0.0; v[nlocal][1] = 0.0; v[nlocal][2] = 0.0; molecule[nlocal] = 0; num_bond[nlocal] = 0; num_angle[nlocal] = 0; nspecial[nlocal][0] = nspecial[nlocal][1] = nspecial[nlocal][2] = 0; atom->nlocal++; } /* ---------------------------------------------------------------------- unpack one line from Atoms section of data file initialize other atom quantities ------------------------------------------------------------------------- */ void AtomVecAngle::data_atom(double *coord, int imagetmp, char **values) { int nlocal = atom->nlocal; if (nlocal == nmax) grow(0); tag[nlocal] = atoi(values[0]); if (tag[nlocal] <= 0) error->one("Invalid atom ID in Atoms section of data file"); molecule[nlocal] = atoi(values[1]); type[nlocal] = atoi(values[2]); if (type[nlocal] <= 0 || type[nlocal] > atom->ntypes) error->one("Invalid atom type in Atoms section of data file"); x[nlocal][0] = coord[0]; x[nlocal][1] = coord[1]; x[nlocal][2] = coord[2]; image[nlocal] = imagetmp; mask[nlocal] = 1; v[nlocal][0] = 0.0; v[nlocal][1] = 0.0; v[nlocal][2] = 0.0; num_bond[nlocal] = 0; num_angle[nlocal] = 0; atom->nlocal++; } /* ---------------------------------------------------------------------- unpack hybrid quantities from one line in Atoms section of data file initialize other atom quantities for this sub-style ------------------------------------------------------------------------- */ int AtomVecAngle::data_atom_hybrid(int nlocal, char **values) { molecule[nlocal] = atoi(values[0]); num_bond[nlocal] = 0; num_angle[nlocal] = 0; return 1; } /* ---------------------------------------------------------------------- return # of bytes of allocated memory ------------------------------------------------------------------------- */ double AtomVecAngle::memory_usage() { double bytes = 0.0; if (atom->memcheck("tag")) bytes += nmax * sizeof(int); if (atom->memcheck("type")) bytes += nmax * sizeof(int); if (atom->memcheck("mask")) bytes += nmax * sizeof(int); if (atom->memcheck("image")) bytes += nmax * sizeof(int); if (atom->memcheck("x")) bytes += nmax*3 * sizeof(double); if (atom->memcheck("v")) bytes += nmax*3 * sizeof(double); if (atom->memcheck("f")) bytes += nmax*3 * sizeof(double); if (atom->memcheck("molecule")) bytes += nmax * sizeof(int); if (atom->memcheck("nspecial")) bytes += nmax*3 * sizeof(int); if (atom->memcheck("special")) bytes += nmax*atom->maxspecial * sizeof(int); if (atom->memcheck("num_bond")) bytes += nmax * sizeof(int); if (atom->memcheck("bond_type")) bytes += nmax*atom->bond_per_atom * sizeof(int); if (atom->memcheck("bond_atom")) bytes += nmax*atom->bond_per_atom * sizeof(int); if (atom->memcheck("num_angle")) bytes += nmax * sizeof(int); if (atom->memcheck("angle_type")) bytes += nmax*atom->angle_per_atom * sizeof(int); if (atom->memcheck("angle_atom1")) bytes += nmax*atom->angle_per_atom * sizeof(int); if (atom->memcheck("angle_atom2")) bytes += nmax*atom->angle_per_atom * sizeof(int); if (atom->memcheck("angle_atom3")) bytes += nmax*atom->angle_per_atom * sizeof(int); return bytes; } diff --git a/src/MOLECULE/atom_vec_bond.cpp b/src/MOLECULE/atom_vec_bond.cpp index 1e8f91323..13ea1e5e2 100644 --- a/src/MOLECULE/atom_vec_bond.cpp +++ b/src/MOLECULE/atom_vec_bond.cpp @@ -1,740 +1,743 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ #include "stdlib.h" #include "atom_vec_bond.h" +#include "lmptype.h" #include "atom.h" #include "domain.h" #include "modify.h" #include "fix.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; #define MIN(A,B) ((A) < (B)) ? (A) : (B) #define MAX(A,B) ((A) > (B)) ? (A) : (B) #define DELTA 10000 /* ---------------------------------------------------------------------- */ AtomVecBond::AtomVecBond(LAMMPS *lmp, int narg, char **arg) : AtomVec(lmp, narg, arg) { molecular = 1; bonds_allow = 1; mass_type = 1; comm_x_only = comm_f_only = 1; size_forward = 3; size_reverse = 3; size_border = 7; size_velocity = 3; size_data_atom = 6; size_data_vel = 4; xcol_data = 4; atom->molecule_flag = 1; } /* ---------------------------------------------------------------------- grow atom arrays n = 0 grows arrays by DELTA n > 0 allocates arrays to size n ------------------------------------------------------------------------- */ void AtomVecBond::grow(int n) { if (n == 0) nmax += DELTA; else nmax = n; atom->nmax = nmax; + if (nmax < 0 || nmax > MAXSMALLINT) + error->one("Per-processor system is too big"); tag = atom->tag = (int *) memory->srealloc(atom->tag,nmax*sizeof(int),"atom:tag"); type = atom->type = (int *) memory->srealloc(atom->type,nmax*sizeof(int),"atom:type"); mask = atom->mask = (int *) memory->srealloc(atom->mask,nmax*sizeof(int),"atom:mask"); image = atom->image = (int *) memory->srealloc(atom->image,nmax*sizeof(int),"atom:image"); x = atom->x = memory->grow_2d_double_array(atom->x,nmax,3,"atom:x"); v = atom->v = memory->grow_2d_double_array(atom->v,nmax,3,"atom:v"); f = atom->f = memory->grow_2d_double_array(atom->f,nmax,3,"atom:f"); molecule = atom->molecule = (int *) memory->srealloc(atom->molecule,nmax*sizeof(int),"atom:molecule"); nspecial = atom->nspecial = memory->grow_2d_int_array(atom->nspecial,nmax,3,"atom:nspecial"); special = atom->special = memory->grow_2d_int_array(atom->special,nmax,atom->maxspecial, "atom:special"); num_bond = atom->num_bond = (int *) memory->srealloc(atom->num_bond,nmax*sizeof(int),"atom:num_bond"); bond_type = atom->bond_type = memory->grow_2d_int_array(atom->bond_type,nmax,atom->bond_per_atom, "atom:bond_type"); bond_atom = atom->bond_atom = memory->grow_2d_int_array(atom->bond_atom,nmax,atom->bond_per_atom, "atom:bond_atom"); if (atom->nextra_grow) for (int iextra = 0; iextra < atom->nextra_grow; iextra++) modify->fix[atom->extra_grow[iextra]]->grow_arrays(nmax); } /* ---------------------------------------------------------------------- reset local array ptrs ------------------------------------------------------------------------- */ void AtomVecBond::grow_reset() { tag = atom->tag; type = atom->type; mask = atom->mask; image = atom->image; x = atom->x; v = atom->v; f = atom->f; molecule = atom->molecule; nspecial = atom->nspecial; special = atom->special; num_bond = atom->num_bond; bond_type = atom->bond_type; bond_atom = atom->bond_atom; } /* ---------------------------------------------------------------------- */ void AtomVecBond::copy(int i, int j) { int k; tag[j] = tag[i]; type[j] = type[i]; mask[j] = mask[i]; image[j] = image[i]; x[j][0] = x[i][0]; x[j][1] = x[i][1]; x[j][2] = x[i][2]; v[j][0] = v[i][0]; v[j][1] = v[i][1]; v[j][2] = v[i][2]; molecule[j] = molecule[i]; num_bond[j] = num_bond[i]; for (k = 0; k < num_bond[j]; k++) { bond_type[j][k] = bond_type[i][k]; bond_atom[j][k] = bond_atom[i][k]; } nspecial[j][0] = nspecial[i][0]; nspecial[j][1] = nspecial[i][1]; nspecial[j][2] = nspecial[i][2]; for (k = 0; k < nspecial[j][2]; k++) special[j][k] = special[i][k]; if (atom->nextra_grow) for (int iextra = 0; iextra < atom->nextra_grow; iextra++) modify->fix[atom->extra_grow[iextra]]->copy_arrays(i,j); } /* ---------------------------------------------------------------------- */ int AtomVecBond::pack_comm(int n, int *list, double *buf, int pbc_flag, int *pbc) { int i,j,m; double dx,dy,dz; m = 0; if (pbc_flag == 0) { for (i = 0; i < n; i++) { j = list[i]; buf[m++] = x[j][0]; buf[m++] = x[j][1]; buf[m++] = x[j][2]; } } else { if (domain->triclinic == 0) { dx = pbc[0]*domain->xprd; dy = pbc[1]*domain->yprd; dz = pbc[2]*domain->zprd; } else { dx = pbc[0]*domain->xprd + pbc[5]*domain->xy + pbc[4]*domain->xz; dy = pbc[1]*domain->yprd + pbc[3]*domain->yz; dz = pbc[2]*domain->zprd; } for (i = 0; i < n; i++) { j = list[i]; buf[m++] = x[j][0] + dx; buf[m++] = x[j][1] + dy; buf[m++] = x[j][2] + dz; } } return m; } /* ---------------------------------------------------------------------- */ int AtomVecBond::pack_comm_vel(int n, int *list, double *buf, int pbc_flag, int *pbc) { int i,j,m; double dx,dy,dz; m = 0; if (pbc_flag == 0) { for (i = 0; i < n; i++) { j = list[i]; buf[m++] = x[j][0]; buf[m++] = x[j][1]; buf[m++] = x[j][2]; buf[m++] = v[j][0]; buf[m++] = v[j][1]; buf[m++] = v[j][2]; } } else { if (domain->triclinic == 0) { dx = pbc[0]*domain->xprd; dy = pbc[1]*domain->yprd; dz = pbc[2]*domain->zprd; } else { dx = pbc[0]*domain->xprd + pbc[5]*domain->xy + pbc[4]*domain->xz; dy = pbc[1]*domain->yprd + pbc[3]*domain->yz; dz = pbc[2]*domain->zprd; } 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]; } } return m; } /* ---------------------------------------------------------------------- */ void AtomVecBond::unpack_comm(int n, int first, double *buf) { int i,m,last; m = 0; last = first + n; for (i = first; i < last; i++) { x[i][0] = buf[m++]; x[i][1] = buf[m++]; x[i][2] = buf[m++]; } } /* ---------------------------------------------------------------------- */ void AtomVecBond::unpack_comm_vel(int n, int first, double *buf) { int i,m,last; m = 0; last = first + n; for (i = first; i < last; i++) { x[i][0] = buf[m++]; x[i][1] = buf[m++]; x[i][2] = buf[m++]; v[i][0] = buf[m++]; v[i][1] = buf[m++]; v[i][2] = buf[m++]; } } /* ---------------------------------------------------------------------- */ int AtomVecBond::pack_reverse(int n, int first, double *buf) { int i,m,last; m = 0; last = first + n; for (i = first; i < last; i++) { buf[m++] = f[i][0]; buf[m++] = f[i][1]; buf[m++] = f[i][2]; } return m; } /* ---------------------------------------------------------------------- */ void AtomVecBond::unpack_reverse(int n, int *list, double *buf) { int i,j,m; m = 0; for (i = 0; i < n; i++) { j = list[i]; f[j][0] += buf[m++]; f[j][1] += buf[m++]; f[j][2] += buf[m++]; } } /* ---------------------------------------------------------------------- */ int AtomVecBond::pack_border(int n, int *list, double *buf, int pbc_flag, int *pbc) { int i,j,m; double dx,dy,dz; m = 0; if (pbc_flag == 0) { for (i = 0; i < n; i++) { j = list[i]; buf[m++] = x[j][0]; buf[m++] = x[j][1]; buf[m++] = x[j][2]; buf[m++] = tag[j]; buf[m++] = type[j]; buf[m++] = mask[j]; buf[m++] = molecule[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++] = molecule[j]; } } return m; } /* ---------------------------------------------------------------------- */ int AtomVecBond::pack_border_vel(int n, int *list, double *buf, int pbc_flag, int *pbc) { int i,j,m; double dx,dy,dz; 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++] = molecule[j]; buf[m++] = v[j][0]; buf[m++] = v[j][1]; buf[m++] = v[j][2]; } } else { if (domain->triclinic == 0) { dx = pbc[0]*domain->xprd; dy = pbc[1]*domain->yprd; dz = pbc[2]*domain->zprd; } else { dx = pbc[0]; dy = pbc[1]; dz = pbc[2]; } 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++] = molecule[j]; buf[m++] = v[j][0]; buf[m++] = v[j][1]; buf[m++] = v[j][2]; } } return m; } /* ---------------------------------------------------------------------- */ int AtomVecBond::pack_border_one(int i, double *buf) { buf[0] = molecule[i]; return 1; } /* ---------------------------------------------------------------------- */ void AtomVecBond::unpack_border(int n, int first, double *buf) { int i,m,last; m = 0; last = first + n; for (i = first; i < last; i++) { if (i == nmax) grow(0); x[i][0] = buf[m++]; x[i][1] = buf[m++]; x[i][2] = buf[m++]; tag[i] = static_cast<int> (buf[m++]); type[i] = static_cast<int> (buf[m++]); mask[i] = static_cast<int> (buf[m++]); molecule[i] = static_cast<int> (buf[m++]); } } /* ---------------------------------------------------------------------- */ void AtomVecBond::unpack_border_vel(int n, int first, double *buf) { int i,m,last; m = 0; last = first + n; for (i = first; i < last; i++) { if (i == nmax) grow(0); x[i][0] = buf[m++]; x[i][1] = buf[m++]; x[i][2] = buf[m++]; tag[i] = static_cast<int> (buf[m++]); type[i] = static_cast<int> (buf[m++]); mask[i] = static_cast<int> (buf[m++]); molecule[i] = static_cast<int> (buf[m++]); v[i][0] = buf[m++]; v[i][1] = buf[m++]; v[i][2] = buf[m++]; } } /* ---------------------------------------------------------------------- */ int AtomVecBond::unpack_border_one(int i, double *buf) { molecule[i] = static_cast<int> (buf[0]); return 1; } /* ---------------------------------------------------------------------- pack data for atom I for sending to another proc xyz must be 1st 3 values, so comm::exchange() can test on them ------------------------------------------------------------------------- */ int AtomVecBond::pack_exchange(int i, double *buf) { int k; int m = 1; buf[m++] = x[i][0]; buf[m++] = x[i][1]; buf[m++] = x[i][2]; buf[m++] = v[i][0]; buf[m++] = v[i][1]; buf[m++] = v[i][2]; buf[m++] = tag[i]; buf[m++] = type[i]; buf[m++] = mask[i]; buf[m++] = image[i]; buf[m++] = molecule[i]; buf[m++] = num_bond[i]; for (k = 0; k < num_bond[i]; k++) { buf[m++] = bond_type[i][k]; buf[m++] = bond_atom[i][k]; } buf[m++] = nspecial[i][0]; buf[m++] = nspecial[i][1]; buf[m++] = nspecial[i][2]; for (k = 0; k < nspecial[i][2]; k++) buf[m++] = special[i][k]; if (atom->nextra_grow) for (int iextra = 0; iextra < atom->nextra_grow; iextra++) m += modify->fix[atom->extra_grow[iextra]]->pack_exchange(i,&buf[m]); buf[0] = m; return m; } /* ---------------------------------------------------------------------- */ int AtomVecBond::unpack_exchange(double *buf) { int k; int nlocal = atom->nlocal; if (nlocal == nmax) grow(0); int m = 1; x[nlocal][0] = buf[m++]; x[nlocal][1] = buf[m++]; x[nlocal][2] = buf[m++]; v[nlocal][0] = buf[m++]; v[nlocal][1] = buf[m++]; v[nlocal][2] = buf[m++]; tag[nlocal] = static_cast<int> (buf[m++]); type[nlocal] = static_cast<int> (buf[m++]); mask[nlocal] = static_cast<int> (buf[m++]); image[nlocal] = static_cast<int> (buf[m++]); molecule[nlocal] = static_cast<int> (buf[m++]); num_bond[nlocal] = static_cast<int> (buf[m++]); for (k = 0; k < num_bond[nlocal]; k++) { bond_type[nlocal][k] = static_cast<int> (buf[m++]); bond_atom[nlocal][k] = static_cast<int> (buf[m++]); } nspecial[nlocal][0] = static_cast<int> (buf[m++]); nspecial[nlocal][1] = static_cast<int> (buf[m++]); nspecial[nlocal][2] = static_cast<int> (buf[m++]); for (k = 0; k < nspecial[nlocal][2]; k++) special[nlocal][k] = static_cast<int> (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 AtomVecBond::size_restart() { int i; int nlocal = atom->nlocal; int n = 0; for (i = 0; i < nlocal; i++) n += 13 + 2*num_bond[i]; if (atom->nextra_restart) for (int iextra = 0; iextra < atom->nextra_restart; iextra++) for (i = 0; i < nlocal; i++) n += modify->fix[atom->extra_restart[iextra]]->size_restart(i); return n; } /* ---------------------------------------------------------------------- pack atom I's data for restart file including extra quantities xyz must be 1st 3 values, so that read_restart can test on them molecular types may be negative, but write as positive ------------------------------------------------------------------------- */ int AtomVecBond::pack_restart(int i, double *buf) { int k; int m = 1; buf[m++] = x[i][0]; buf[m++] = x[i][1]; buf[m++] = x[i][2]; buf[m++] = tag[i]; buf[m++] = type[i]; buf[m++] = mask[i]; buf[m++] = image[i]; buf[m++] = v[i][0]; buf[m++] = v[i][1]; buf[m++] = v[i][2]; buf[m++] = molecule[i]; buf[m++] = num_bond[i]; for (k = 0; k < num_bond[i]; k++) { buf[m++] = MAX(bond_type[i][k],-bond_type[i][k]); buf[m++] = bond_atom[i][k]; } if (atom->nextra_restart) for (int iextra = 0; iextra < atom->nextra_restart; iextra++) m += modify->fix[atom->extra_restart[iextra]]->pack_restart(i,&buf[m]); buf[0] = m; return m; } /* ---------------------------------------------------------------------- unpack data for one atom from restart file including extra quantities ------------------------------------------------------------------------- */ int AtomVecBond::unpack_restart(double *buf) { int k; int nlocal = atom->nlocal; if (nlocal == nmax) { grow(0); if (atom->nextra_store) atom->extra = memory->grow_2d_double_array(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] = static_cast<int> (buf[m++]); v[nlocal][0] = buf[m++]; v[nlocal][1] = buf[m++]; v[nlocal][2] = buf[m++]; molecule[nlocal] = static_cast<int> (buf[m++]); num_bond[nlocal] = static_cast<int> (buf[m++]); for (k = 0; k < num_bond[nlocal]; k++) { bond_type[nlocal][k] = static_cast<int> (buf[m++]); bond_atom[nlocal][k] = static_cast<int> (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 AtomVecBond::create_atom(int itype, double *coord) { int nlocal = atom->nlocal; if (nlocal == nmax) grow(0); tag[nlocal] = 0; type[nlocal] = itype; x[nlocal][0] = coord[0]; x[nlocal][1] = coord[1]; x[nlocal][2] = coord[2]; mask[nlocal] = 1; image[nlocal] = (512 << 20) | (512 << 10) | 512; v[nlocal][0] = 0.0; v[nlocal][1] = 0.0; v[nlocal][2] = 0.0; molecule[nlocal] = 0; num_bond[nlocal] = 0; nspecial[nlocal][0] = nspecial[nlocal][1] = nspecial[nlocal][2] = 0; atom->nlocal++; } /* ---------------------------------------------------------------------- unpack one line from Atoms section of data file initialize other atom quantities ------------------------------------------------------------------------- */ void AtomVecBond::data_atom(double *coord, int imagetmp, char **values) { int nlocal = atom->nlocal; if (nlocal == nmax) grow(0); tag[nlocal] = atoi(values[0]); if (tag[nlocal] <= 0) error->one("Invalid atom ID in Atoms section of data file"); molecule[nlocal] = atoi(values[1]); type[nlocal] = atoi(values[2]); if (type[nlocal] <= 0 || type[nlocal] > atom->ntypes) error->one("Invalid atom type in Atoms section of data file"); x[nlocal][0] = coord[0]; x[nlocal][1] = coord[1]; x[nlocal][2] = coord[2]; image[nlocal] = imagetmp; mask[nlocal] = 1; v[nlocal][0] = 0.0; v[nlocal][1] = 0.0; v[nlocal][2] = 0.0; num_bond[nlocal] = 0; atom->nlocal++; } /* ---------------------------------------------------------------------- unpack hybrid quantities from one line in Atoms section of data file initialize other atom quantities for this sub-style ------------------------------------------------------------------------- */ int AtomVecBond::data_atom_hybrid(int nlocal, char **values) { molecule[nlocal] = atoi(values[0]); num_bond[nlocal] = 0; return 1; } /* ---------------------------------------------------------------------- return # of bytes of allocated memory ------------------------------------------------------------------------- */ double AtomVecBond::memory_usage() { double bytes = 0.0; if (atom->memcheck("tag")) bytes += nmax * sizeof(int); if (atom->memcheck("type")) bytes += nmax * sizeof(int); if (atom->memcheck("mask")) bytes += nmax * sizeof(int); if (atom->memcheck("image")) bytes += nmax * sizeof(int); if (atom->memcheck("x")) bytes += nmax*3 * sizeof(double); if (atom->memcheck("v")) bytes += nmax*3 * sizeof(double); if (atom->memcheck("f")) bytes += nmax*3 * sizeof(double); if (atom->memcheck("molecule")) bytes += nmax * sizeof(int); if (atom->memcheck("nspecial")) bytes += nmax*3 * sizeof(int); if (atom->memcheck("special")) bytes += nmax*atom->maxspecial * sizeof(int); if (atom->memcheck("num_bond")) bytes += nmax * sizeof(int); if (atom->memcheck("bond_type")) bytes += nmax*atom->bond_per_atom * sizeof(int); if (atom->memcheck("bond_atom")) bytes += nmax*atom->bond_per_atom * sizeof(int); return bytes; } diff --git a/src/MOLECULE/atom_vec_full.cpp b/src/MOLECULE/atom_vec_full.cpp index 5815256fc..2d733ebf4 100644 --- a/src/MOLECULE/atom_vec_full.cpp +++ b/src/MOLECULE/atom_vec_full.cpp @@ -1,994 +1,997 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ #include "stdlib.h" #include "atom_vec_full.h" +#include "lmptype.h" #include "atom.h" #include "domain.h" #include "modify.h" #include "fix.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; #define MIN(A,B) ((A) < (B)) ? (A) : (B) #define MAX(A,B) ((A) > (B)) ? (A) : (B) #define DELTA 10000 /* ---------------------------------------------------------------------- */ AtomVecFull::AtomVecFull(LAMMPS *lmp, int narg, char **arg) : AtomVec(lmp, narg, arg) { molecular = 1; bonds_allow = angles_allow = dihedrals_allow = impropers_allow = 1; mass_type = 1; comm_x_only = comm_f_only = 1; size_forward = 3; size_reverse = 3; size_border = 8; size_velocity = 3; size_data_atom = 7; size_data_vel = 4; xcol_data = 5; atom->molecule_flag = atom->q_flag = 1; } /* ---------------------------------------------------------------------- grow atom arrays n = 0 grows arrays by DELTA n > 0 allocates arrays to size n ------------------------------------------------------------------------- */ void AtomVecFull::grow(int n) { if (n == 0) nmax += DELTA; else nmax = n; atom->nmax = nmax; + if (nmax < 0 || nmax > MAXSMALLINT) + error->one("Per-processor system is too big"); tag = atom->tag = (int *) memory->srealloc(atom->tag,nmax*sizeof(int),"atom:tag"); type = atom->type = (int *) memory->srealloc(atom->type,nmax*sizeof(int),"atom:type"); mask = atom->mask = (int *) memory->srealloc(atom->mask,nmax*sizeof(int),"atom:mask"); image = atom->image = (int *) memory->srealloc(atom->image,nmax*sizeof(int),"atom:image"); x = atom->x = memory->grow_2d_double_array(atom->x,nmax,3,"atom:x"); v = atom->v = memory->grow_2d_double_array(atom->v,nmax,3,"atom:v"); f = atom->f = memory->grow_2d_double_array(atom->f,nmax,3,"atom:f"); q = atom->q = (double *) memory->srealloc(atom->q,nmax*sizeof(double),"atom:q"); molecule = atom->molecule = (int *) memory->srealloc(atom->molecule,nmax*sizeof(int),"atom:molecule"); nspecial = atom->nspecial = memory->grow_2d_int_array(atom->nspecial,nmax,3,"atom:nspecial"); special = atom->special = memory->grow_2d_int_array(atom->special,nmax,atom->maxspecial, "atom:special"); num_bond = atom->num_bond = (int *) memory->srealloc(atom->num_bond,nmax*sizeof(int),"atom:num_bond"); bond_type = atom->bond_type = memory->grow_2d_int_array(atom->bond_type,nmax,atom->bond_per_atom, "atom:bond_type"); bond_atom = atom->bond_atom = memory->grow_2d_int_array(atom->bond_atom,nmax,atom->bond_per_atom, "atom:bond_atom"); num_angle = atom->num_angle = (int *) memory->srealloc(atom->num_angle,nmax*sizeof(int),"atom:num_angle"); angle_type = atom->angle_type = memory->grow_2d_int_array(atom->angle_type,nmax,atom->angle_per_atom, "atom:angle_type"); angle_atom1 = atom->angle_atom1 = memory->grow_2d_int_array(atom->angle_atom1,nmax,atom->angle_per_atom, "atom:angle_atom1"); angle_atom2 = atom->angle_atom2 = memory->grow_2d_int_array(atom->angle_atom2,nmax,atom->angle_per_atom, "atom:angle_atom2"); angle_atom3 = atom->angle_atom3 = memory->grow_2d_int_array(atom->angle_atom3,nmax,atom->angle_per_atom, "atom:angle_atom3"); num_dihedral = atom->num_dihedral = (int *) memory->srealloc(atom->num_dihedral,nmax*sizeof(int),"atom:num_dihedral"); dihedral_type = atom->dihedral_type = memory->grow_2d_int_array(atom->dihedral_type,nmax,atom->dihedral_per_atom, "atom:dihedral_type"); dihedral_atom1 = atom->dihedral_atom1 = memory->grow_2d_int_array(atom->dihedral_atom1,nmax, atom->dihedral_per_atom,"atom:dihedral_atom1"); dihedral_atom2 = atom->dihedral_atom2 = memory->grow_2d_int_array(atom->dihedral_atom2,nmax, atom->dihedral_per_atom,"atom:dihedral_atom2"); dihedral_atom3 = atom->dihedral_atom3 = memory->grow_2d_int_array(atom->dihedral_atom3,nmax, atom->dihedral_per_atom,"atom:dihedral_atom3"); dihedral_atom4 = atom->dihedral_atom4 = memory->grow_2d_int_array(atom->dihedral_atom4,nmax, atom->dihedral_per_atom,"atom:dihedral_atom4"); num_improper = atom->num_improper = (int *) memory->srealloc(atom->num_improper,nmax*sizeof(int),"atom:num_improper"); improper_type = atom->improper_type = memory->grow_2d_int_array(atom->improper_type,nmax,atom->improper_per_atom, "atom:improper_type"); improper_atom1 = atom->improper_atom1 = memory->grow_2d_int_array(atom->improper_atom1,nmax, atom->improper_per_atom,"atom:improper_atom1"); improper_atom2 = atom->improper_atom2 = memory->grow_2d_int_array(atom->improper_atom2,nmax, atom->improper_per_atom,"atom:improper_atom2"); improper_atom3 = atom->improper_atom3 = memory->grow_2d_int_array(atom->improper_atom3,nmax, atom->improper_per_atom,"atom:improper_atom3"); improper_atom4 = atom->improper_atom4 = memory->grow_2d_int_array(atom->improper_atom4,nmax, atom->improper_per_atom,"atom:improper_atom4"); if (atom->nextra_grow) for (int iextra = 0; iextra < atom->nextra_grow; iextra++) modify->fix[atom->extra_grow[iextra]]->grow_arrays(nmax); } /* ---------------------------------------------------------------------- reset local array ptrs ------------------------------------------------------------------------- */ void AtomVecFull::grow_reset() { tag = atom->tag; type = atom->type; mask = atom->mask; image = atom->image; x = atom->x; v = atom->v; f = atom->f; q = atom->q; molecule = atom->molecule; nspecial = atom->nspecial; special = atom->special; num_bond = atom->num_bond; bond_type = atom->bond_type; bond_atom = atom->bond_atom; num_angle = atom->num_angle; angle_type = atom->angle_type; angle_atom1 = atom->angle_atom1; angle_atom2 = atom->angle_atom2; angle_atom3 = atom->angle_atom3; num_dihedral = atom->num_dihedral; dihedral_type = atom->dihedral_type; dihedral_atom1 = atom->dihedral_atom1; dihedral_atom2 = atom->dihedral_atom2; dihedral_atom3 = atom->dihedral_atom3; dihedral_atom4 = atom->dihedral_atom4; num_improper = atom->num_improper; improper_type = atom->improper_type; improper_atom1 = atom->improper_atom1; improper_atom2 = atom->improper_atom2; improper_atom3 = atom->improper_atom3; improper_atom4 = atom->improper_atom4; } /* ---------------------------------------------------------------------- */ void AtomVecFull::copy(int i, int j) { int k; tag[j] = tag[i]; type[j] = type[i]; mask[j] = mask[i]; image[j] = image[i]; x[j][0] = x[i][0]; x[j][1] = x[i][1]; x[j][2] = x[i][2]; v[j][0] = v[i][0]; v[j][1] = v[i][1]; v[j][2] = v[i][2]; q[j] = q[i]; molecule[j] = molecule[i]; num_bond[j] = num_bond[i]; for (k = 0; k < num_bond[j]; k++) { bond_type[j][k] = bond_type[i][k]; bond_atom[j][k] = bond_atom[i][k]; } num_angle[j] = num_angle[i]; for (k = 0; k < num_angle[j]; k++) { angle_type[j][k] = angle_type[i][k]; angle_atom1[j][k] = angle_atom1[i][k]; angle_atom2[j][k] = angle_atom2[i][k]; angle_atom3[j][k] = angle_atom3[i][k]; } num_dihedral[j] = num_dihedral[i]; for (k = 0; k < num_dihedral[j]; k++) { dihedral_type[j][k] = dihedral_type[i][k]; dihedral_atom1[j][k] = dihedral_atom1[i][k]; dihedral_atom2[j][k] = dihedral_atom2[i][k]; dihedral_atom3[j][k] = dihedral_atom3[i][k]; dihedral_atom4[j][k] = dihedral_atom4[i][k]; } num_improper[j] = num_improper[i]; for (k = 0; k < num_improper[j]; k++) { improper_type[j][k] = improper_type[i][k]; improper_atom1[j][k] = improper_atom1[i][k]; improper_atom2[j][k] = improper_atom2[i][k]; improper_atom3[j][k] = improper_atom3[i][k]; improper_atom4[j][k] = improper_atom4[i][k]; } nspecial[j][0] = nspecial[i][0]; nspecial[j][1] = nspecial[i][1]; nspecial[j][2] = nspecial[i][2]; for (k = 0; k < nspecial[j][2]; k++) special[j][k] = special[i][k]; if (atom->nextra_grow) for (int iextra = 0; iextra < atom->nextra_grow; iextra++) modify->fix[atom->extra_grow[iextra]]->copy_arrays(i,j); } /* ---------------------------------------------------------------------- */ int AtomVecFull::pack_comm(int n, int *list, double *buf, int pbc_flag, int *pbc) { int i,j,m; double dx,dy,dz; m = 0; if (pbc_flag == 0) { for (i = 0; i < n; i++) { j = list[i]; buf[m++] = x[j][0]; buf[m++] = x[j][1]; buf[m++] = x[j][2]; } } else { if (domain->triclinic == 0) { dx = pbc[0]*domain->xprd; dy = pbc[1]*domain->yprd; dz = pbc[2]*domain->zprd; } else { dx = pbc[0]*domain->xprd + pbc[5]*domain->xy + pbc[4]*domain->xz; dy = pbc[1]*domain->yprd + pbc[3]*domain->yz; dz = pbc[2]*domain->zprd; } for (i = 0; i < n; i++) { j = list[i]; buf[m++] = x[j][0] + dx; buf[m++] = x[j][1] + dy; buf[m++] = x[j][2] + dz; } } return m; } /* ---------------------------------------------------------------------- */ int AtomVecFull::pack_comm_vel(int n, int *list, double *buf, int pbc_flag, int *pbc) { int i,j,m; double dx,dy,dz; m = 0; if (pbc_flag == 0) { for (i = 0; i < n; i++) { j = list[i]; buf[m++] = x[j][0]; buf[m++] = x[j][1]; buf[m++] = x[j][2]; buf[m++] = v[j][0]; buf[m++] = v[j][1]; buf[m++] = v[j][2]; } } else { if (domain->triclinic == 0) { dx = pbc[0]*domain->xprd; dy = pbc[1]*domain->yprd; dz = pbc[2]*domain->zprd; } else { dx = pbc[0]*domain->xprd + pbc[5]*domain->xy + pbc[4]*domain->xz; dy = pbc[1]*domain->yprd + pbc[3]*domain->yz; dz = pbc[2]*domain->zprd; } 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]; } } return m; } /* ---------------------------------------------------------------------- */ void AtomVecFull::unpack_comm(int n, int first, double *buf) { int i,m,last; m = 0; last = first + n; for (i = first; i < last; i++) { x[i][0] = buf[m++]; x[i][1] = buf[m++]; x[i][2] = buf[m++]; } } /* ---------------------------------------------------------------------- */ void AtomVecFull::unpack_comm_vel(int n, int first, double *buf) { int i,m,last; m = 0; last = first + n; for (i = first; i < last; i++) { x[i][0] = buf[m++]; x[i][1] = buf[m++]; x[i][2] = buf[m++]; v[i][0] = buf[m++]; v[i][1] = buf[m++]; v[i][2] = buf[m++]; } } /* ---------------------------------------------------------------------- */ int AtomVecFull::pack_reverse(int n, int first, double *buf) { int i,m,last; m = 0; last = first + n; for (i = first; i < last; i++) { buf[m++] = f[i][0]; buf[m++] = f[i][1]; buf[m++] = f[i][2]; } return m; } /* ---------------------------------------------------------------------- */ void AtomVecFull::unpack_reverse(int n, int *list, double *buf) { int i,j,m; m = 0; for (i = 0; i < n; i++) { j = list[i]; f[j][0] += buf[m++]; f[j][1] += buf[m++]; f[j][2] += buf[m++]; } } /* ---------------------------------------------------------------------- */ int AtomVecFull::pack_border(int n, int *list, double *buf, int pbc_flag, int *pbc) { int i,j,m; double dx,dy,dz; m = 0; if (pbc_flag == 0) { for (i = 0; i < n; i++) { j = list[i]; buf[m++] = x[j][0]; buf[m++] = x[j][1]; buf[m++] = x[j][2]; buf[m++] = tag[j]; buf[m++] = type[j]; buf[m++] = mask[j]; buf[m++] = q[j]; buf[m++] = molecule[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++] = q[j]; buf[m++] = molecule[j]; } } return m; } /* ---------------------------------------------------------------------- */ int AtomVecFull::pack_border_vel(int n, int *list, double *buf, int pbc_flag, int *pbc) { int i,j,m; double dx,dy,dz; 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++] = q[j]; buf[m++] = molecule[j]; buf[m++] = v[j][0]; buf[m++] = v[j][1]; buf[m++] = v[j][2]; } } else { if (domain->triclinic == 0) { dx = pbc[0]*domain->xprd; dy = pbc[1]*domain->yprd; dz = pbc[2]*domain->zprd; } else { dx = pbc[0]; dy = pbc[1]; dz = pbc[2]; } 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++] = q[j]; buf[m++] = molecule[j]; buf[m++] = v[j][0]; buf[m++] = v[j][1]; buf[m++] = v[j][2]; } } return m; } /* ---------------------------------------------------------------------- */ int AtomVecFull::pack_border_one(int i, double *buf) { buf[0] = q[i]; buf[1] = molecule[i]; return 2; } /* ---------------------------------------------------------------------- */ void AtomVecFull::unpack_border(int n, int first, double *buf) { int i,m,last; m = 0; last = first + n; for (i = first; i < last; i++) { if (i == nmax) grow(0); x[i][0] = buf[m++]; x[i][1] = buf[m++]; x[i][2] = buf[m++]; tag[i] = static_cast<int> (buf[m++]); type[i] = static_cast<int> (buf[m++]); mask[i] = static_cast<int> (buf[m++]); q[i] = buf[m++]; molecule[i] = static_cast<int> (buf[m++]); } } /* ---------------------------------------------------------------------- */ void AtomVecFull::unpack_border_vel(int n, int first, double *buf) { int i,m,last; m = 0; last = first + n; for (i = first; i < last; i++) { if (i == nmax) grow(0); x[i][0] = buf[m++]; x[i][1] = buf[m++]; x[i][2] = buf[m++]; tag[i] = static_cast<int> (buf[m++]); type[i] = static_cast<int> (buf[m++]); mask[i] = static_cast<int> (buf[m++]); q[i] = buf[m++]; molecule[i] = static_cast<int> (buf[m++]); v[i][0] = buf[m++]; v[i][1] = buf[m++]; v[i][2] = buf[m++]; } } /* ---------------------------------------------------------------------- */ int AtomVecFull::unpack_border_one(int i, double *buf) { q[i] = buf[0]; molecule[i] = static_cast<int> (buf[1]); return 2; } /* ---------------------------------------------------------------------- pack data for atom I for sending to another proc xyz must be 1st 3 values, so comm::exchange() can test on them ------------------------------------------------------------------------- */ int AtomVecFull::pack_exchange(int i, double *buf) { int k; int m = 1; buf[m++] = x[i][0]; buf[m++] = x[i][1]; buf[m++] = x[i][2]; buf[m++] = v[i][0]; buf[m++] = v[i][1]; buf[m++] = v[i][2]; buf[m++] = tag[i]; buf[m++] = type[i]; buf[m++] = mask[i]; buf[m++] = image[i]; buf[m++] = q[i]; buf[m++] = molecule[i]; buf[m++] = num_bond[i]; for (k = 0; k < num_bond[i]; k++) { buf[m++] = bond_type[i][k]; buf[m++] = bond_atom[i][k]; } buf[m++] = num_angle[i]; for (k = 0; k < num_angle[i]; k++) { buf[m++] = angle_type[i][k]; buf[m++] = angle_atom1[i][k]; buf[m++] = angle_atom2[i][k]; buf[m++] = angle_atom3[i][k]; } buf[m++] = num_dihedral[i]; for (k = 0; k < num_dihedral[i]; k++) { buf[m++] = dihedral_type[i][k]; buf[m++] = dihedral_atom1[i][k]; buf[m++] = dihedral_atom2[i][k]; buf[m++] = dihedral_atom3[i][k]; buf[m++] = dihedral_atom4[i][k]; } buf[m++] = num_improper[i]; for (k = 0; k < num_improper[i]; k++) { buf[m++] = improper_type[i][k]; buf[m++] = improper_atom1[i][k]; buf[m++] = improper_atom2[i][k]; buf[m++] = improper_atom3[i][k]; buf[m++] = improper_atom4[i][k]; } buf[m++] = nspecial[i][0]; buf[m++] = nspecial[i][1]; buf[m++] = nspecial[i][2]; for (k = 0; k < nspecial[i][2]; k++) buf[m++] = special[i][k]; if (atom->nextra_grow) for (int iextra = 0; iextra < atom->nextra_grow; iextra++) m += modify->fix[atom->extra_grow[iextra]]->pack_exchange(i,&buf[m]); buf[0] = m; return m; } /* ---------------------------------------------------------------------- */ int AtomVecFull::unpack_exchange(double *buf) { int k; int nlocal = atom->nlocal; if (nlocal == nmax) grow(0); int m = 1; x[nlocal][0] = buf[m++]; x[nlocal][1] = buf[m++]; x[nlocal][2] = buf[m++]; v[nlocal][0] = buf[m++]; v[nlocal][1] = buf[m++]; v[nlocal][2] = buf[m++]; tag[nlocal] = static_cast<int> (buf[m++]); type[nlocal] = static_cast<int> (buf[m++]); mask[nlocal] = static_cast<int> (buf[m++]); image[nlocal] = static_cast<int> (buf[m++]); q[nlocal] = buf[m++]; molecule[nlocal] = static_cast<int> (buf[m++]); num_bond[nlocal] = static_cast<int> (buf[m++]); for (k = 0; k < num_bond[nlocal]; k++) { bond_type[nlocal][k] = static_cast<int> (buf[m++]); bond_atom[nlocal][k] = static_cast<int> (buf[m++]); } num_angle[nlocal] = static_cast<int> (buf[m++]); for (k = 0; k < num_angle[nlocal]; k++) { angle_type[nlocal][k] = static_cast<int> (buf[m++]); angle_atom1[nlocal][k] = static_cast<int> (buf[m++]); angle_atom2[nlocal][k] = static_cast<int> (buf[m++]); angle_atom3[nlocal][k] = static_cast<int> (buf[m++]); } num_dihedral[nlocal] = static_cast<int> (buf[m++]); for (k = 0; k < num_dihedral[nlocal]; k++) { dihedral_type[nlocal][k] = static_cast<int> (buf[m++]); dihedral_atom1[nlocal][k] = static_cast<int> (buf[m++]); dihedral_atom2[nlocal][k] = static_cast<int> (buf[m++]); dihedral_atom3[nlocal][k] = static_cast<int> (buf[m++]); dihedral_atom4[nlocal][k] = static_cast<int> (buf[m++]); } num_improper[nlocal] = static_cast<int> (buf[m++]); for (k = 0; k < num_improper[nlocal]; k++) { improper_type[nlocal][k] = static_cast<int> (buf[m++]); improper_atom1[nlocal][k] = static_cast<int> (buf[m++]); improper_atom2[nlocal][k] = static_cast<int> (buf[m++]); improper_atom3[nlocal][k] = static_cast<int> (buf[m++]); improper_atom4[nlocal][k] = static_cast<int> (buf[m++]); } nspecial[nlocal][0] = static_cast<int> (buf[m++]); nspecial[nlocal][1] = static_cast<int> (buf[m++]); nspecial[nlocal][2] = static_cast<int> (buf[m++]); for (k = 0; k < nspecial[nlocal][2]; k++) special[nlocal][k] = static_cast<int> (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 AtomVecFull::size_restart() { int i; int nlocal = atom->nlocal; int n = 0; for (i = 0; i < nlocal; i++) n += 17 + 2*num_bond[i] + 4*num_angle[i] + 5*num_dihedral[i] + 5*num_improper[i]; if (atom->nextra_restart) for (int iextra = 0; iextra < atom->nextra_restart; iextra++) for (i = 0; i < nlocal; i++) n += modify->fix[atom->extra_restart[iextra]]->size_restart(i); return n; } /* ---------------------------------------------------------------------- pack atom I's data for restart file including extra quantities xyz must be 1st 3 values, so that read_restart can test on them molecular types may be negative, but write as positive ------------------------------------------------------------------------- */ int AtomVecFull::pack_restart(int i, double *buf) { int k; int m = 1; buf[m++] = x[i][0]; buf[m++] = x[i][1]; buf[m++] = x[i][2]; buf[m++] = tag[i]; buf[m++] = type[i]; buf[m++] = mask[i]; buf[m++] = image[i]; buf[m++] = v[i][0]; buf[m++] = v[i][1]; buf[m++] = v[i][2]; buf[m++] = q[i]; buf[m++] = molecule[i]; buf[m++] = num_bond[i]; for (k = 0; k < num_bond[i]; k++) { buf[m++] = MAX(bond_type[i][k],-bond_type[i][k]); buf[m++] = bond_atom[i][k]; } buf[m++] = num_angle[i]; for (k = 0; k < num_angle[i]; k++) { buf[m++] = MAX(angle_type[i][k],-angle_type[i][k]); buf[m++] = angle_atom1[i][k]; buf[m++] = angle_atom2[i][k]; buf[m++] = angle_atom3[i][k]; } buf[m++] = num_dihedral[i]; for (k = 0; k < num_dihedral[i]; k++) { buf[m++] = MAX(dihedral_type[i][k],-dihedral_type[i][k]); buf[m++] = dihedral_atom1[i][k]; buf[m++] = dihedral_atom2[i][k]; buf[m++] = dihedral_atom3[i][k]; buf[m++] = dihedral_atom4[i][k]; } buf[m++] = num_improper[i]; for (k = 0; k < num_improper[i]; k++) { buf[m++] = MAX(improper_type[i][k],-improper_type[i][k]); buf[m++] = improper_atom1[i][k]; buf[m++] = improper_atom2[i][k]; buf[m++] = improper_atom3[i][k]; buf[m++] = improper_atom4[i][k]; } if (atom->nextra_restart) for (int iextra = 0; iextra < atom->nextra_restart; iextra++) m += modify->fix[atom->extra_restart[iextra]]->pack_restart(i,&buf[m]); buf[0] = m; return m; } /* ---------------------------------------------------------------------- unpack data for one atom from restart file including extra quantities ------------------------------------------------------------------------- */ int AtomVecFull::unpack_restart(double *buf) { int k; int nlocal = atom->nlocal; if (nlocal == nmax) { grow(0); if (atom->nextra_store) atom->extra = memory->grow_2d_double_array(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] = static_cast<int> (buf[m++]); v[nlocal][0] = buf[m++]; v[nlocal][1] = buf[m++]; v[nlocal][2] = buf[m++]; q[nlocal] = buf[m++]; molecule[nlocal] = static_cast<int> (buf[m++]); num_bond[nlocal] = static_cast<int> (buf[m++]); for (k = 0; k < num_bond[nlocal]; k++) { bond_type[nlocal][k] = static_cast<int> (buf[m++]); bond_atom[nlocal][k] = static_cast<int> (buf[m++]); } num_angle[nlocal] = static_cast<int> (buf[m++]); for (k = 0; k < num_angle[nlocal]; k++) { angle_type[nlocal][k] = static_cast<int> (buf[m++]); angle_atom1[nlocal][k] = static_cast<int> (buf[m++]); angle_atom2[nlocal][k] = static_cast<int> (buf[m++]); angle_atom3[nlocal][k] = static_cast<int> (buf[m++]); } num_dihedral[nlocal] = static_cast<int> (buf[m++]); for (k = 0; k < num_dihedral[nlocal]; k++) { dihedral_type[nlocal][k] = static_cast<int> (buf[m++]); dihedral_atom1[nlocal][k] = static_cast<int> (buf[m++]); dihedral_atom2[nlocal][k] = static_cast<int> (buf[m++]); dihedral_atom3[nlocal][k] = static_cast<int> (buf[m++]); dihedral_atom4[nlocal][k] = static_cast<int> (buf[m++]); } num_improper[nlocal] = static_cast<int> (buf[m++]); for (k = 0; k < num_improper[nlocal]; k++) { improper_type[nlocal][k] = static_cast<int> (buf[m++]); improper_atom1[nlocal][k] = static_cast<int> (buf[m++]); improper_atom2[nlocal][k] = static_cast<int> (buf[m++]); improper_atom3[nlocal][k] = static_cast<int> (buf[m++]); improper_atom4[nlocal][k] = static_cast<int> (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 AtomVecFull::create_atom(int itype, double *coord) { int nlocal = atom->nlocal; if (nlocal == nmax) grow(0); tag[nlocal] = 0; type[nlocal] = itype; x[nlocal][0] = coord[0]; x[nlocal][1] = coord[1]; x[nlocal][2] = coord[2]; mask[nlocal] = 1; image[nlocal] = (512 << 20) | (512 << 10) | 512; v[nlocal][0] = 0.0; v[nlocal][1] = 0.0; v[nlocal][2] = 0.0; q[nlocal] = 0.0; molecule[nlocal] = 0; num_bond[nlocal] = 0; num_angle[nlocal] = 0; num_dihedral[nlocal] = 0; num_improper[nlocal] = 0; nspecial[nlocal][0] = nspecial[nlocal][1] = nspecial[nlocal][2] = 0; atom->nlocal++; } /* ---------------------------------------------------------------------- unpack one line from Atoms section of data file initialize other atom quantities ------------------------------------------------------------------------- */ void AtomVecFull::data_atom(double *coord, int imagetmp, char **values) { int nlocal = atom->nlocal; if (nlocal == nmax) grow(0); tag[nlocal] = atoi(values[0]); if (tag[nlocal] <= 0) error->one("Invalid atom ID in Atoms section of data file"); molecule[nlocal] = atoi(values[1]); type[nlocal] = atoi(values[2]); if (type[nlocal] <= 0 || type[nlocal] > atom->ntypes) error->one("Invalid atom type in Atoms section of data file"); q[nlocal] = atof(values[3]); x[nlocal][0] = coord[0]; x[nlocal][1] = coord[1]; x[nlocal][2] = coord[2]; image[nlocal] = imagetmp; mask[nlocal] = 1; v[nlocal][0] = 0.0; v[nlocal][1] = 0.0; v[nlocal][2] = 0.0; num_bond[nlocal] = 0; num_angle[nlocal] = 0; num_dihedral[nlocal] = 0; num_improper[nlocal] = 0; atom->nlocal++; } /* ---------------------------------------------------------------------- unpack hybrid quantities from one line in Atoms section of data file initialize other atom quantities for this sub-style ------------------------------------------------------------------------- */ int AtomVecFull::data_atom_hybrid(int nlocal, char **values) { molecule[nlocal] = atoi(values[1]); q[nlocal] = atof(values[3]); num_bond[nlocal] = 0; num_angle[nlocal] = 0; num_dihedral[nlocal] = 0; num_improper[nlocal] = 0; return 2; } /* ---------------------------------------------------------------------- return # of bytes of allocated memory ------------------------------------------------------------------------- */ double AtomVecFull::memory_usage() { double bytes = 0.0; if (atom->memcheck("tag")) bytes += nmax * sizeof(int); if (atom->memcheck("type")) bytes += nmax * sizeof(int); if (atom->memcheck("mask")) bytes += nmax * sizeof(int); if (atom->memcheck("image")) bytes += nmax * sizeof(int); if (atom->memcheck("x")) bytes += nmax*3 * sizeof(double); if (atom->memcheck("v")) bytes += nmax*3 * sizeof(double); if (atom->memcheck("f")) bytes += nmax*3 * sizeof(double); if (atom->memcheck("q")) bytes += nmax * sizeof(double); if (atom->memcheck("molecule")) bytes += nmax * sizeof(int); if (atom->memcheck("nspecial")) bytes += nmax*3 * sizeof(int); if (atom->memcheck("special")) bytes += nmax*atom->maxspecial * sizeof(int); if (atom->memcheck("num_bond")) bytes += nmax * sizeof(int); if (atom->memcheck("bond_type")) bytes += nmax*atom->bond_per_atom * sizeof(int); if (atom->memcheck("bond_atom")) bytes += nmax*atom->bond_per_atom * sizeof(int); if (atom->memcheck("num_angle")) bytes += nmax * sizeof(int); if (atom->memcheck("angle_type")) bytes += nmax*atom->angle_per_atom * sizeof(int); if (atom->memcheck("angle_atom1")) bytes += nmax*atom->angle_per_atom * sizeof(int); if (atom->memcheck("angle_atom2")) bytes += nmax*atom->angle_per_atom * sizeof(int); if (atom->memcheck("angle_atom3")) bytes += nmax*atom->angle_per_atom * sizeof(int); if (atom->memcheck("num_dihedral")) bytes += nmax * sizeof(int); if (atom->memcheck("dihedral_type")) bytes += nmax*atom->dihedral_per_atom * sizeof(int); if (atom->memcheck("dihedral_atom1")) bytes += nmax*atom->dihedral_per_atom * sizeof(int); if (atom->memcheck("dihedral_atom2")) bytes += nmax*atom->dihedral_per_atom * sizeof(int); if (atom->memcheck("dihedral_atom3")) bytes += nmax*atom->dihedral_per_atom * sizeof(int); if (atom->memcheck("dihedral_atom4")) bytes += nmax*atom->dihedral_per_atom * sizeof(int); if (atom->memcheck("num_improper")) bytes += nmax * sizeof(int); if (atom->memcheck("improper_type")) bytes += nmax*atom->improper_per_atom * sizeof(int); if (atom->memcheck("improper_atom1")) bytes += nmax*atom->improper_per_atom * sizeof(int); if (atom->memcheck("improper_atom2")) bytes += nmax*atom->improper_per_atom * sizeof(int); if (atom->memcheck("improper_atom3")) bytes += nmax*atom->improper_per_atom * sizeof(int); if (atom->memcheck("improper_atom4")) bytes += nmax*atom->improper_per_atom * sizeof(int); return bytes; } diff --git a/src/MOLECULE/atom_vec_molecular.cpp b/src/MOLECULE/atom_vec_molecular.cpp index 131e80c59..07c46724a 100644 --- a/src/MOLECULE/atom_vec_molecular.cpp +++ b/src/MOLECULE/atom_vec_molecular.cpp @@ -1,974 +1,977 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ #include "stdlib.h" #include "atom_vec_molecular.h" +#include "lmptype.h" #include "atom.h" #include "domain.h" #include "modify.h" #include "fix.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; #define MIN(A,B) ((A) < (B)) ? (A) : (B) #define MAX(A,B) ((A) > (B)) ? (A) : (B) #define DELTA 10000 /* ---------------------------------------------------------------------- */ AtomVecMolecular::AtomVecMolecular(LAMMPS *lmp, int narg, char **arg) : AtomVec(lmp, narg, arg) { molecular = 1; bonds_allow = angles_allow = dihedrals_allow = impropers_allow = 1; mass_type = 1; comm_x_only = comm_f_only = 1; size_forward = 3; size_reverse = 3; size_border = 7; size_velocity = 3; size_data_atom = 6; size_data_vel = 4; xcol_data = 4; atom->molecule_flag = 1; } /* ---------------------------------------------------------------------- grow atom arrays n = 0 grows arrays by DELTA n > 0 allocates arrays to size n ------------------------------------------------------------------------- */ void AtomVecMolecular::grow(int n) { if (n == 0) nmax += DELTA; else nmax = n; atom->nmax = nmax; + if (nmax < 0 || nmax > MAXSMALLINT) + error->one("Per-processor system is too big"); tag = atom->tag = (int *) memory->srealloc(atom->tag,nmax*sizeof(int),"atom:tag"); type = atom->type = (int *) memory->srealloc(atom->type,nmax*sizeof(int),"atom:type"); mask = atom->mask = (int *) memory->srealloc(atom->mask,nmax*sizeof(int),"atom:mask"); image = atom->image = (int *) memory->srealloc(atom->image,nmax*sizeof(int),"atom:image"); x = atom->x = memory->grow_2d_double_array(atom->x,nmax,3,"atom:x"); v = atom->v = memory->grow_2d_double_array(atom->v,nmax,3,"atom:v"); f = atom->f = memory->grow_2d_double_array(atom->f,nmax,3,"atom:f"); molecule = atom->molecule = (int *) memory->srealloc(atom->molecule,nmax*sizeof(int),"atom:molecule"); nspecial = atom->nspecial = memory->grow_2d_int_array(atom->nspecial,nmax,3,"atom:nspecial"); special = atom->special = memory->grow_2d_int_array(atom->special,nmax,atom->maxspecial, "atom:special"); num_bond = atom->num_bond = (int *) memory->srealloc(atom->num_bond,nmax*sizeof(int),"atom:num_bond"); bond_type = atom->bond_type = memory->grow_2d_int_array(atom->bond_type,nmax,atom->bond_per_atom, "atom:bond_type"); bond_atom = atom->bond_atom = memory->grow_2d_int_array(atom->bond_atom,nmax,atom->bond_per_atom, "atom:bond_atom"); num_angle = atom->num_angle = (int *) memory->srealloc(atom->num_angle,nmax*sizeof(int),"atom:num_angle"); angle_type = atom->angle_type = memory->grow_2d_int_array(atom->angle_type,nmax,atom->angle_per_atom, "atom:angle_type"); angle_atom1 = atom->angle_atom1 = memory->grow_2d_int_array(atom->angle_atom1,nmax,atom->angle_per_atom, "atom:angle_atom1"); angle_atom2 = atom->angle_atom2 = memory->grow_2d_int_array(atom->angle_atom2,nmax,atom->angle_per_atom, "atom:angle_atom2"); angle_atom3 = atom->angle_atom3 = memory->grow_2d_int_array(atom->angle_atom3,nmax,atom->angle_per_atom, "atom:angle_atom3"); num_dihedral = atom->num_dihedral = (int *) memory->srealloc(atom->num_dihedral,nmax*sizeof(int),"atom:num_dihedral"); dihedral_type = atom->dihedral_type = memory->grow_2d_int_array(atom->dihedral_type,nmax,atom->dihedral_per_atom, "atom:dihedral_type"); dihedral_atom1 = atom->dihedral_atom1 = memory->grow_2d_int_array(atom->dihedral_atom1,nmax, atom->dihedral_per_atom,"atom:dihedral_atom1"); dihedral_atom2 = atom->dihedral_atom2 = memory->grow_2d_int_array(atom->dihedral_atom2,nmax, atom->dihedral_per_atom,"atom:dihedral_atom2"); dihedral_atom3 = atom->dihedral_atom3 = memory->grow_2d_int_array(atom->dihedral_atom3,nmax, atom->dihedral_per_atom,"atom:dihedral_atom3"); dihedral_atom4 = atom->dihedral_atom4 = memory->grow_2d_int_array(atom->dihedral_atom4,nmax, atom->dihedral_per_atom,"atom:dihedral_atom4"); num_improper = atom->num_improper = (int *) memory->srealloc(atom->num_improper,nmax*sizeof(int),"atom:num_improper"); improper_type = atom->improper_type = memory->grow_2d_int_array(atom->improper_type,nmax,atom->improper_per_atom, "atom:improper_type"); improper_atom1 = atom->improper_atom1 = memory->grow_2d_int_array(atom->improper_atom1,nmax, atom->improper_per_atom,"atom:improper_atom1"); improper_atom2 = atom->improper_atom2 = memory->grow_2d_int_array(atom->improper_atom2,nmax, atom->improper_per_atom,"atom:improper_atom2"); improper_atom3 = atom->improper_atom3 = memory->grow_2d_int_array(atom->improper_atom3,nmax, atom->improper_per_atom,"atom:improper_atom3"); improper_atom4 = atom->improper_atom4 = memory->grow_2d_int_array(atom->improper_atom4,nmax, atom->improper_per_atom,"atom:improper_atom4"); if (atom->nextra_grow) for (int iextra = 0; iextra < atom->nextra_grow; iextra++) modify->fix[atom->extra_grow[iextra]]->grow_arrays(nmax); } /* ---------------------------------------------------------------------- reset local array ptrs ------------------------------------------------------------------------- */ void AtomVecMolecular::grow_reset() { tag = atom->tag; type = atom->type; mask = atom->mask; image = atom->image; x = atom->x; v = atom->v; f = atom->f; molecule = atom->molecule; nspecial = atom->nspecial; special = atom->special; num_bond = atom->num_bond; bond_type = atom->bond_type; bond_atom = atom->bond_atom; num_angle = atom->num_angle; angle_type = atom->angle_type; angle_atom1 = atom->angle_atom1; angle_atom2 = atom->angle_atom2; angle_atom3 = atom->angle_atom3; num_dihedral = atom->num_dihedral; dihedral_type = atom->dihedral_type; dihedral_atom1 = atom->dihedral_atom1; dihedral_atom2 = atom->dihedral_atom2; dihedral_atom3 = atom->dihedral_atom3; dihedral_atom4 = atom->dihedral_atom4; num_improper = atom->num_improper; improper_type = atom->improper_type; improper_atom1 = atom->improper_atom1; improper_atom2 = atom->improper_atom2; improper_atom3 = atom->improper_atom3; improper_atom4 = atom->improper_atom4; } /* ---------------------------------------------------------------------- */ void AtomVecMolecular::copy(int i, int j) { int k; tag[j] = tag[i]; type[j] = type[i]; mask[j] = mask[i]; image[j] = image[i]; x[j][0] = x[i][0]; x[j][1] = x[i][1]; x[j][2] = x[i][2]; v[j][0] = v[i][0]; v[j][1] = v[i][1]; v[j][2] = v[i][2]; molecule[j] = molecule[i]; num_bond[j] = num_bond[i]; for (k = 0; k < num_bond[j]; k++) { bond_type[j][k] = bond_type[i][k]; bond_atom[j][k] = bond_atom[i][k]; } num_angle[j] = num_angle[i]; for (k = 0; k < num_angle[j]; k++) { angle_type[j][k] = angle_type[i][k]; angle_atom1[j][k] = angle_atom1[i][k]; angle_atom2[j][k] = angle_atom2[i][k]; angle_atom3[j][k] = angle_atom3[i][k]; } num_dihedral[j] = num_dihedral[i]; for (k = 0; k < num_dihedral[j]; k++) { dihedral_type[j][k] = dihedral_type[i][k]; dihedral_atom1[j][k] = dihedral_atom1[i][k]; dihedral_atom2[j][k] = dihedral_atom2[i][k]; dihedral_atom3[j][k] = dihedral_atom3[i][k]; dihedral_atom4[j][k] = dihedral_atom4[i][k]; } num_improper[j] = num_improper[i]; for (k = 0; k < num_improper[j]; k++) { improper_type[j][k] = improper_type[i][k]; improper_atom1[j][k] = improper_atom1[i][k]; improper_atom2[j][k] = improper_atom2[i][k]; improper_atom3[j][k] = improper_atom3[i][k]; improper_atom4[j][k] = improper_atom4[i][k]; } nspecial[j][0] = nspecial[i][0]; nspecial[j][1] = nspecial[i][1]; nspecial[j][2] = nspecial[i][2]; for (k = 0; k < nspecial[j][2]; k++) special[j][k] = special[i][k]; if (atom->nextra_grow) for (int iextra = 0; iextra < atom->nextra_grow; iextra++) modify->fix[atom->extra_grow[iextra]]->copy_arrays(i,j); } /* ---------------------------------------------------------------------- */ int AtomVecMolecular::pack_comm(int n, int *list, double *buf, int pbc_flag, int *pbc) { int i,j,m; double dx,dy,dz; m = 0; if (pbc_flag == 0) { for (i = 0; i < n; i++) { j = list[i]; buf[m++] = x[j][0]; buf[m++] = x[j][1]; buf[m++] = x[j][2]; } } else { if (domain->triclinic == 0) { dx = pbc[0]*domain->xprd; dy = pbc[1]*domain->yprd; dz = pbc[2]*domain->zprd; } else { dx = pbc[0]*domain->xprd + pbc[5]*domain->xy + pbc[4]*domain->xz; dy = pbc[1]*domain->yprd + pbc[3]*domain->yz; dz = pbc[2]*domain->zprd; } for (i = 0; i < n; i++) { j = list[i]; buf[m++] = x[j][0] + dx; buf[m++] = x[j][1] + dy; buf[m++] = x[j][2] + dz; } } return m; } /* ---------------------------------------------------------------------- */ int AtomVecMolecular::pack_comm_vel(int n, int *list, double *buf, int pbc_flag, int *pbc) { int i,j,m; double dx,dy,dz; m = 0; if (pbc_flag == 0) { for (i = 0; i < n; i++) { j = list[i]; buf[m++] = x[j][0]; buf[m++] = x[j][1]; buf[m++] = x[j][2]; buf[m++] = v[j][0]; buf[m++] = v[j][1]; buf[m++] = v[j][2]; } } else { if (domain->triclinic == 0) { dx = pbc[0]*domain->xprd; dy = pbc[1]*domain->yprd; dz = pbc[2]*domain->zprd; } else { dx = pbc[0]*domain->xprd + pbc[5]*domain->xy + pbc[4]*domain->xz; dy = pbc[1]*domain->yprd + pbc[3]*domain->yz; dz = pbc[2]*domain->zprd; } 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]; } } return m; } /* ---------------------------------------------------------------------- */ void AtomVecMolecular::unpack_comm(int n, int first, double *buf) { int i,m,last; m = 0; last = first + n; for (i = first; i < last; i++) { x[i][0] = buf[m++]; x[i][1] = buf[m++]; x[i][2] = buf[m++]; } } /* ---------------------------------------------------------------------- */ void AtomVecMolecular::unpack_comm_vel(int n, int first, double *buf) { int i,m,last; m = 0; last = first + n; for (i = first; i < last; i++) { x[i][0] = buf[m++]; x[i][1] = buf[m++]; x[i][2] = buf[m++]; v[i][0] = buf[m++]; v[i][1] = buf[m++]; v[i][2] = buf[m++]; } } /* ---------------------------------------------------------------------- */ int AtomVecMolecular::pack_reverse(int n, int first, double *buf) { int i,m,last; m = 0; last = first + n; for (i = first; i < last; i++) { buf[m++] = f[i][0]; buf[m++] = f[i][1]; buf[m++] = f[i][2]; } return m; } /* ---------------------------------------------------------------------- */ void AtomVecMolecular::unpack_reverse(int n, int *list, double *buf) { int i,j,m; m = 0; for (i = 0; i < n; i++) { j = list[i]; f[j][0] += buf[m++]; f[j][1] += buf[m++]; f[j][2] += buf[m++]; } } /* ---------------------------------------------------------------------- */ int AtomVecMolecular::pack_border(int n, int *list, double *buf, int pbc_flag, int *pbc) { int i,j,m; double dx,dy,dz; m = 0; if (pbc_flag == 0) { for (i = 0; i < n; i++) { j = list[i]; buf[m++] = x[j][0]; buf[m++] = x[j][1]; buf[m++] = x[j][2]; buf[m++] = tag[j]; buf[m++] = type[j]; buf[m++] = mask[j]; buf[m++] = molecule[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++] = molecule[j]; } } return m; } /* ---------------------------------------------------------------------- */ int AtomVecMolecular::pack_border_vel(int n, int *list, double *buf, int pbc_flag, int *pbc) { int i,j,m; double dx,dy,dz; 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++] = molecule[j]; buf[m++] = v[j][0]; buf[m++] = v[j][1]; buf[m++] = v[j][2]; } } else { if (domain->triclinic == 0) { dx = pbc[0]*domain->xprd; dy = pbc[1]*domain->yprd; dz = pbc[2]*domain->zprd; } else { dx = pbc[0]; dy = pbc[1]; dz = pbc[2]; } 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++] = molecule[j]; buf[m++] = v[j][0]; buf[m++] = v[j][1]; buf[m++] = v[j][2]; } } return m; } /* ---------------------------------------------------------------------- */ int AtomVecMolecular::pack_border_one(int i, double *buf) { buf[0] = molecule[i]; return 1; } /* ---------------------------------------------------------------------- */ void AtomVecMolecular::unpack_border(int n, int first, double *buf) { int i,m,last; m = 0; last = first + n; for (i = first; i < last; i++) { if (i == nmax) grow(0); x[i][0] = buf[m++]; x[i][1] = buf[m++]; x[i][2] = buf[m++]; tag[i] = static_cast<int> (buf[m++]); type[i] = static_cast<int> (buf[m++]); mask[i] = static_cast<int> (buf[m++]); molecule[i] = static_cast<int> (buf[m++]); } } /* ---------------------------------------------------------------------- */ void AtomVecMolecular::unpack_border_vel(int n, int first, double *buf) { int i,m,last; m = 0; last = first + n; for (i = first; i < last; i++) { if (i == nmax) grow(0); x[i][0] = buf[m++]; x[i][1] = buf[m++]; x[i][2] = buf[m++]; tag[i] = static_cast<int> (buf[m++]); type[i] = static_cast<int> (buf[m++]); mask[i] = static_cast<int> (buf[m++]); molecule[i] = static_cast<int> (buf[m++]); v[i][0] = buf[m++]; v[i][1] = buf[m++]; v[i][2] = buf[m++]; } } /* ---------------------------------------------------------------------- */ int AtomVecMolecular::unpack_border_one(int i, double *buf) { molecule[i] = static_cast<int> (buf[0]); return 1; } /* ---------------------------------------------------------------------- pack data for atom I for sending to another proc xyz must be 1st 3 values, so comm::exchange() can test on them ------------------------------------------------------------------------- */ int AtomVecMolecular::pack_exchange(int i, double *buf) { int k; int m = 1; buf[m++] = x[i][0]; buf[m++] = x[i][1]; buf[m++] = x[i][2]; buf[m++] = v[i][0]; buf[m++] = v[i][1]; buf[m++] = v[i][2]; buf[m++] = tag[i]; buf[m++] = type[i]; buf[m++] = mask[i]; buf[m++] = image[i]; buf[m++] = molecule[i]; buf[m++] = num_bond[i]; for (k = 0; k < num_bond[i]; k++) { buf[m++] = bond_type[i][k]; buf[m++] = bond_atom[i][k]; } buf[m++] = num_angle[i]; for (k = 0; k < num_angle[i]; k++) { buf[m++] = angle_type[i][k]; buf[m++] = angle_atom1[i][k]; buf[m++] = angle_atom2[i][k]; buf[m++] = angle_atom3[i][k]; } buf[m++] = num_dihedral[i]; for (k = 0; k < num_dihedral[i]; k++) { buf[m++] = dihedral_type[i][k]; buf[m++] = dihedral_atom1[i][k]; buf[m++] = dihedral_atom2[i][k]; buf[m++] = dihedral_atom3[i][k]; buf[m++] = dihedral_atom4[i][k]; } buf[m++] = num_improper[i]; for (k = 0; k < num_improper[i]; k++) { buf[m++] = improper_type[i][k]; buf[m++] = improper_atom1[i][k]; buf[m++] = improper_atom2[i][k]; buf[m++] = improper_atom3[i][k]; buf[m++] = improper_atom4[i][k]; } buf[m++] = nspecial[i][0]; buf[m++] = nspecial[i][1]; buf[m++] = nspecial[i][2]; for (k = 0; k < nspecial[i][2]; k++) buf[m++] = special[i][k]; if (atom->nextra_grow) for (int iextra = 0; iextra < atom->nextra_grow; iextra++) m += modify->fix[atom->extra_grow[iextra]]->pack_exchange(i,&buf[m]); buf[0] = m; return m; } /* ---------------------------------------------------------------------- */ int AtomVecMolecular::unpack_exchange(double *buf) { int k; int nlocal = atom->nlocal; if (nlocal == nmax) grow(0); int m = 1; x[nlocal][0] = buf[m++]; x[nlocal][1] = buf[m++]; x[nlocal][2] = buf[m++]; v[nlocal][0] = buf[m++]; v[nlocal][1] = buf[m++]; v[nlocal][2] = buf[m++]; tag[nlocal] = static_cast<int> (buf[m++]); type[nlocal] = static_cast<int> (buf[m++]); mask[nlocal] = static_cast<int> (buf[m++]); image[nlocal] = static_cast<int> (buf[m++]); molecule[nlocal] = static_cast<int> (buf[m++]); num_bond[nlocal] = static_cast<int> (buf[m++]); for (k = 0; k < num_bond[nlocal]; k++) { bond_type[nlocal][k] = static_cast<int> (buf[m++]); bond_atom[nlocal][k] = static_cast<int> (buf[m++]); } num_angle[nlocal] = static_cast<int> (buf[m++]); for (k = 0; k < num_angle[nlocal]; k++) { angle_type[nlocal][k] = static_cast<int> (buf[m++]); angle_atom1[nlocal][k] = static_cast<int> (buf[m++]); angle_atom2[nlocal][k] = static_cast<int> (buf[m++]); angle_atom3[nlocal][k] = static_cast<int> (buf[m++]); } num_dihedral[nlocal] = static_cast<int> (buf[m++]); for (k = 0; k < num_dihedral[nlocal]; k++) { dihedral_type[nlocal][k] = static_cast<int> (buf[m++]); dihedral_atom1[nlocal][k] = static_cast<int> (buf[m++]); dihedral_atom2[nlocal][k] = static_cast<int> (buf[m++]); dihedral_atom3[nlocal][k] = static_cast<int> (buf[m++]); dihedral_atom4[nlocal][k] = static_cast<int> (buf[m++]); } num_improper[nlocal] = static_cast<int> (buf[m++]); for (k = 0; k < num_improper[nlocal]; k++) { improper_type[nlocal][k] = static_cast<int> (buf[m++]); improper_atom1[nlocal][k] = static_cast<int> (buf[m++]); improper_atom2[nlocal][k] = static_cast<int> (buf[m++]); improper_atom3[nlocal][k] = static_cast<int> (buf[m++]); improper_atom4[nlocal][k] = static_cast<int> (buf[m++]); } nspecial[nlocal][0] = static_cast<int> (buf[m++]); nspecial[nlocal][1] = static_cast<int> (buf[m++]); nspecial[nlocal][2] = static_cast<int> (buf[m++]); for (k = 0; k < nspecial[nlocal][2]; k++) special[nlocal][k] = static_cast<int> (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 AtomVecMolecular::size_restart() { int i; int nlocal = atom->nlocal; int n = 0; for (i = 0; i < nlocal; i++) n += 16 + 2*num_bond[i] + 4*num_angle[i] + 5*num_dihedral[i] + 5*num_improper[i]; if (atom->nextra_restart) for (int iextra = 0; iextra < atom->nextra_restart; iextra++) for (i = 0; i < nlocal; i++) n += modify->fix[atom->extra_restart[iextra]]->size_restart(i); return n; } /* ---------------------------------------------------------------------- pack atom I's data for restart file including extra quantities xyz must be 1st 3 values, so that read_restart can test on them molecular types may be negative, but write as positive ------------------------------------------------------------------------- */ int AtomVecMolecular::pack_restart(int i, double *buf) { int k; int m = 1; buf[m++] = x[i][0]; buf[m++] = x[i][1]; buf[m++] = x[i][2]; buf[m++] = tag[i]; buf[m++] = type[i]; buf[m++] = mask[i]; buf[m++] = image[i]; buf[m++] = v[i][0]; buf[m++] = v[i][1]; buf[m++] = v[i][2]; buf[m++] = molecule[i]; buf[m++] = num_bond[i]; for (k = 0; k < num_bond[i]; k++) { buf[m++] = MAX(bond_type[i][k],-bond_type[i][k]); buf[m++] = bond_atom[i][k]; } buf[m++] = num_angle[i]; for (k = 0; k < num_angle[i]; k++) { buf[m++] = MAX(angle_type[i][k],-angle_type[i][k]); buf[m++] = angle_atom1[i][k]; buf[m++] = angle_atom2[i][k]; buf[m++] = angle_atom3[i][k]; } buf[m++] = num_dihedral[i]; for (k = 0; k < num_dihedral[i]; k++) { buf[m++] = MAX(dihedral_type[i][k],-dihedral_type[i][k]); buf[m++] = dihedral_atom1[i][k]; buf[m++] = dihedral_atom2[i][k]; buf[m++] = dihedral_atom3[i][k]; buf[m++] = dihedral_atom4[i][k]; } buf[m++] = num_improper[i]; for (k = 0; k < num_improper[i]; k++) { buf[m++] = MAX(improper_type[i][k],-improper_type[i][k]); buf[m++] = improper_atom1[i][k]; buf[m++] = improper_atom2[i][k]; buf[m++] = improper_atom3[i][k]; buf[m++] = improper_atom4[i][k]; } if (atom->nextra_restart) for (int iextra = 0; iextra < atom->nextra_restart; iextra++) m += modify->fix[atom->extra_restart[iextra]]->pack_restart(i,&buf[m]); buf[0] = m; return m; } /* ---------------------------------------------------------------------- unpack data for one atom from restart file including extra quantities ------------------------------------------------------------------------- */ int AtomVecMolecular::unpack_restart(double *buf) { int k; int nlocal = atom->nlocal; if (nlocal == nmax) { grow(0); if (atom->nextra_store) atom->extra = memory->grow_2d_double_array(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] = static_cast<int> (buf[m++]); v[nlocal][0] = buf[m++]; v[nlocal][1] = buf[m++]; v[nlocal][2] = buf[m++]; molecule[nlocal] = static_cast<int> (buf[m++]); num_bond[nlocal] = static_cast<int> (buf[m++]); for (k = 0; k < num_bond[nlocal]; k++) { bond_type[nlocal][k] = static_cast<int> (buf[m++]); bond_atom[nlocal][k] = static_cast<int> (buf[m++]); } num_angle[nlocal] = static_cast<int> (buf[m++]); for (k = 0; k < num_angle[nlocal]; k++) { angle_type[nlocal][k] = static_cast<int> (buf[m++]); angle_atom1[nlocal][k] = static_cast<int> (buf[m++]); angle_atom2[nlocal][k] = static_cast<int> (buf[m++]); angle_atom3[nlocal][k] = static_cast<int> (buf[m++]); } num_dihedral[nlocal] = static_cast<int> (buf[m++]); for (k = 0; k < num_dihedral[nlocal]; k++) { dihedral_type[nlocal][k] = static_cast<int> (buf[m++]); dihedral_atom1[nlocal][k] = static_cast<int> (buf[m++]); dihedral_atom2[nlocal][k] = static_cast<int> (buf[m++]); dihedral_atom3[nlocal][k] = static_cast<int> (buf[m++]); dihedral_atom4[nlocal][k] = static_cast<int> (buf[m++]); } num_improper[nlocal] = static_cast<int> (buf[m++]); for (k = 0; k < num_improper[nlocal]; k++) { improper_type[nlocal][k] = static_cast<int> (buf[m++]); improper_atom1[nlocal][k] = static_cast<int> (buf[m++]); improper_atom2[nlocal][k] = static_cast<int> (buf[m++]); improper_atom3[nlocal][k] = static_cast<int> (buf[m++]); improper_atom4[nlocal][k] = static_cast<int> (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 AtomVecMolecular::create_atom(int itype, double *coord) { int nlocal = atom->nlocal; if (nlocal == nmax) grow(0); tag[nlocal] = 0; type[nlocal] = itype; x[nlocal][0] = coord[0]; x[nlocal][1] = coord[1]; x[nlocal][2] = coord[2]; mask[nlocal] = 1; image[nlocal] = (512 << 20) | (512 << 10) | 512; v[nlocal][0] = 0.0; v[nlocal][1] = 0.0; v[nlocal][2] = 0.0; molecule[nlocal] = 0; num_bond[nlocal] = 0; num_angle[nlocal] = 0; num_dihedral[nlocal] = 0; num_improper[nlocal] = 0; nspecial[nlocal][0] = nspecial[nlocal][1] = nspecial[nlocal][2] = 0; atom->nlocal++; } /* ---------------------------------------------------------------------- unpack one line from Atoms section of data file initialize other atom quantities ------------------------------------------------------------------------- */ void AtomVecMolecular::data_atom(double *coord, int imagetmp, char **values) { int nlocal = atom->nlocal; if (nlocal == nmax) grow(0); tag[nlocal] = atoi(values[0]); if (tag[nlocal] <= 0) error->one("Invalid atom ID in Atoms section of data file"); molecule[nlocal] = atoi(values[1]); type[nlocal] = atoi(values[2]); if (type[nlocal] <= 0 || type[nlocal] > atom->ntypes) error->one("Invalid atom type in Atoms section of data file"); x[nlocal][0] = coord[0]; x[nlocal][1] = coord[1]; x[nlocal][2] = coord[2]; image[nlocal] = imagetmp; mask[nlocal] = 1; v[nlocal][0] = 0.0; v[nlocal][1] = 0.0; v[nlocal][2] = 0.0; num_bond[nlocal] = 0; num_angle[nlocal] = 0; num_dihedral[nlocal] = 0; num_improper[nlocal] = 0; atom->nlocal++; } /* ---------------------------------------------------------------------- unpack hybrid quantities from one line in Atoms section of data file initialize other atom quantities for this sub-style ------------------------------------------------------------------------- */ int AtomVecMolecular::data_atom_hybrid(int nlocal, char **values) { molecule[nlocal] = atoi(values[0]); num_bond[nlocal] = 0; num_angle[nlocal] = 0; num_dihedral[nlocal] = 0; num_improper[nlocal] = 0; return 1; } /* ---------------------------------------------------------------------- return # of bytes of allocated memory ------------------------------------------------------------------------- */ double AtomVecMolecular::memory_usage() { double bytes = 0.0; if (atom->memcheck("tag")) bytes += nmax * sizeof(int); if (atom->memcheck("type")) bytes += nmax * sizeof(int); if (atom->memcheck("mask")) bytes += nmax * sizeof(int); if (atom->memcheck("image")) bytes += nmax * sizeof(int); if (atom->memcheck("x")) bytes += nmax*3 * sizeof(double); if (atom->memcheck("v")) bytes += nmax*3 * sizeof(double); if (atom->memcheck("f")) bytes += nmax*3 * sizeof(double); if (atom->memcheck("molecule")) bytes += nmax * sizeof(int); if (atom->memcheck("nspecial")) bytes += nmax*3 * sizeof(int); if (atom->memcheck("special")) bytes += nmax*atom->maxspecial * sizeof(int); if (atom->memcheck("num_bond")) bytes += nmax * sizeof(int); if (atom->memcheck("bond_type")) bytes += nmax*atom->bond_per_atom * sizeof(int); if (atom->memcheck("bond_atom")) bytes += nmax*atom->bond_per_atom * sizeof(int); if (atom->memcheck("num_angle")) bytes += nmax * sizeof(int); if (atom->memcheck("angle_type")) bytes += nmax*atom->angle_per_atom * sizeof(int); if (atom->memcheck("angle_atom1")) bytes += nmax*atom->angle_per_atom * sizeof(int); if (atom->memcheck("angle_atom2")) bytes += nmax*atom->angle_per_atom * sizeof(int); if (atom->memcheck("angle_atom3")) bytes += nmax*atom->angle_per_atom * sizeof(int); if (atom->memcheck("num_dihedral")) bytes += nmax * sizeof(int); if (atom->memcheck("dihedral_type")) bytes += nmax*atom->dihedral_per_atom * sizeof(int); if (atom->memcheck("dihedral_atom1")) bytes += nmax*atom->dihedral_per_atom * sizeof(int); if (atom->memcheck("dihedral_atom2")) bytes += nmax*atom->dihedral_per_atom * sizeof(int); if (atom->memcheck("dihedral_atom3")) bytes += nmax*atom->dihedral_per_atom * sizeof(int); if (atom->memcheck("dihedral_atom4")) bytes += nmax*atom->dihedral_per_atom * sizeof(int); if (atom->memcheck("num_improper")) bytes += nmax * sizeof(int); if (atom->memcheck("improper_type")) bytes += nmax*atom->improper_per_atom * sizeof(int); if (atom->memcheck("improper_atom1")) bytes += nmax*atom->improper_per_atom * sizeof(int); if (atom->memcheck("improper_atom2")) bytes += nmax*atom->improper_per_atom * sizeof(int); if (atom->memcheck("improper_atom3")) bytes += nmax*atom->improper_per_atom * sizeof(int); if (atom->memcheck("improper_atom4")) bytes += nmax*atom->improper_per_atom * sizeof(int); return bytes; } diff --git a/src/MOLECULE/bond_fene.cpp b/src/MOLECULE/bond_fene.cpp index babb22689..f1c7b7782 100644 --- a/src/MOLECULE/bond_fene.cpp +++ b/src/MOLECULE/bond_fene.cpp @@ -1,261 +1,263 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ #include "math.h" #include "stdlib.h" #include "bond_fene.h" +#include "lmptype.h" #include "atom.h" #include "neighbor.h" #include "domain.h" #include "comm.h" #include "update.h" #include "force.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; /* ---------------------------------------------------------------------- */ BondFENE::BondFENE(LAMMPS *lmp) : Bond(lmp) { TWO_1_3 = pow(2.0,(1.0/3.0)); } /* ---------------------------------------------------------------------- */ BondFENE::~BondFENE() { if (allocated) { memory->sfree(setflag); memory->sfree(k); memory->sfree(r0); memory->sfree(epsilon); memory->sfree(sigma); } } /* ---------------------------------------------------------------------- */ void BondFENE::compute(int eflag, int vflag) { int i1,i2,n,type; double delx,dely,delz,ebond,fbond; double rsq,r0sq,rlogarg,sr2,sr6; ebond = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = 0; double **x = atom->x; double **f = atom->f; int **bondlist = neighbor->bondlist; int nbondlist = neighbor->nbondlist; int nlocal = atom->nlocal; int newton_bond = force->newton_bond; for (n = 0; n < nbondlist; n++) { i1 = bondlist[n][0]; i2 = bondlist[n][1]; type = bondlist[n][2]; delx = x[i1][0] - x[i2][0]; dely = x[i1][1] - x[i2][1]; delz = x[i1][2] - x[i2][2]; domain->minimum_image(delx,dely,delz); // force from log term rsq = delx*delx + dely*dely + delz*delz; r0sq = r0[type] * r0[type]; rlogarg = 1.0 - rsq/r0sq; // if r -> r0, then rlogarg < 0.0 which is an error // issue a warning and reset rlogarg = epsilon // if r > 2*r0 something serious is wrong, abort if (rlogarg < 0.1) { - char str[128]; - sprintf(str,"FENE bond too long: %d %d %d %g", - update->ntimestep,atom->tag[i1],atom->tag[i2],sqrt(rsq)); + char str[128],fstr[64]; + sprintf(fstr,"FENE bond too long: %s %%d %%d %%g",BIGINT_FORMAT); + sprintf(str,fstr,update->ntimestep,atom->tag[i1],atom->tag[i2],sqrt(rsq)); error->warning(str,0); if (rlogarg <= -3.0) error->one("Bad FENE bond"); rlogarg = 0.1; } fbond = -k[type]/rlogarg; // force from LJ term if (rsq < TWO_1_3*sigma[type]*sigma[type]) { sr2 = sigma[type]*sigma[type]/rsq; sr6 = sr2*sr2*sr2; fbond += 48.0*epsilon[type]*sr6*(sr6-0.5)/rsq; } // energy if (eflag) { ebond = -0.5 * k[type]*r0sq*log(rlogarg); if (rsq < TWO_1_3*sigma[type]*sigma[type]) ebond += 4.0*epsilon[type]*sr6*(sr6-1.0) + epsilon[type]; } // apply force to each of 2 atoms if (newton_bond || i1 < nlocal) { f[i1][0] += delx*fbond; f[i1][1] += dely*fbond; f[i1][2] += delz*fbond; } if (newton_bond || i2 < nlocal) { f[i2][0] -= delx*fbond; f[i2][1] -= dely*fbond; f[i2][2] -= delz*fbond; } if (evflag) ev_tally(i1,i2,nlocal,newton_bond,ebond,fbond,delx,dely,delz); } } /* ---------------------------------------------------------------------- */ void BondFENE::allocate() { allocated = 1; int n = atom->nbondtypes; k = (double *) memory->smalloc((n+1)*sizeof(double),"bond:k"); r0 = (double *) memory->smalloc((n+1)*sizeof(double),"bond:r0"); epsilon = (double *) memory->smalloc((n+1)*sizeof(double),"bond:epsilon"); sigma = (double *) memory->smalloc((n+1)*sizeof(double),"bond:sigma"); setflag = (int *) memory->smalloc((n+1)*sizeof(int),"bond:setflag"); for (int i = 1; i <= n; i++) setflag[i] = 0; } /* ---------------------------------------------------------------------- set coeffs for one type ------------------------------------------------------------------------- */ void BondFENE::coeff(int narg, char **arg) { if (narg != 5) error->all("Incorrect args for bond coefficients"); if (!allocated) allocate(); int ilo,ihi; force->bounds(arg[0],atom->nbondtypes,ilo,ihi); double k_one = force->numeric(arg[1]); double r0_one = force->numeric(arg[2]); double epsilon_one = force->numeric(arg[3]); double sigma_one = force->numeric(arg[4]); int count = 0; for (int i = ilo; i <= ihi; i++) { k[i] = k_one; r0[i] = r0_one; epsilon[i] = epsilon_one; sigma[i] = sigma_one; setflag[i] = 1; count++; } if (count == 0) error->all("Incorrect args for bond coefficients"); } /* ---------------------------------------------------------------------- check if special_bond settings are valid ------------------------------------------------------------------------- */ void BondFENE::init_style() { // special bonds should be 0 1 1 if (force->special_lj[1] != 0.0 || force->special_lj[2] != 1.0 || force->special_lj[3] != 1.0) { if (comm->me == 0) error->warning("Use special bonds = 0,1,1 with bond style fene"); } } /* ---------------------------------------------------------------------- */ double BondFENE::equilibrium_distance(int i) { return 0.97*sigma[i]; } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void BondFENE::write_restart(FILE *fp) { fwrite(&k[1],sizeof(double),atom->nbondtypes,fp); fwrite(&r0[1],sizeof(double),atom->nbondtypes,fp); fwrite(&epsilon[1],sizeof(double),atom->nbondtypes,fp); fwrite(&sigma[1],sizeof(double),atom->nbondtypes,fp); } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void BondFENE::read_restart(FILE *fp) { allocate(); if (comm->me == 0) { fread(&k[1],sizeof(double),atom->nbondtypes,fp); fread(&r0[1],sizeof(double),atom->nbondtypes,fp); fread(&epsilon[1],sizeof(double),atom->nbondtypes,fp); fread(&sigma[1],sizeof(double),atom->nbondtypes,fp); } MPI_Bcast(&k[1],atom->nbondtypes,MPI_DOUBLE,0,world); MPI_Bcast(&r0[1],atom->nbondtypes,MPI_DOUBLE,0,world); MPI_Bcast(&epsilon[1],atom->nbondtypes,MPI_DOUBLE,0,world); MPI_Bcast(&sigma[1],atom->nbondtypes,MPI_DOUBLE,0,world); for (int i = 1; i <= atom->nbondtypes; i++) setflag[i] = 1; } /* ---------------------------------------------------------------------- */ double BondFENE::single(int type, double rsq, int i, int j) { double r0sq = r0[type] * r0[type]; double rlogarg = 1.0 - rsq/r0sq; // if r -> r0, then rlogarg < 0.0 which is an error // issue a warning and reset rlogarg = epsilon // if r > 2*r0 something serious is wrong, abort if (rlogarg < 0.1) { - char str[128]; - sprintf(str,"FENE bond too long: %d %g",update->ntimestep,sqrt(rsq)); + char str[128],fstr[64]; + sprintf(fstr,"FENE bond too long: %s %%g",BIGINT_FORMAT); + sprintf(str,fstr,update->ntimestep,sqrt(rsq)); error->warning(str,0); if (rlogarg <= -3.0) error->one("Bad FENE bond"); rlogarg = 0.1; } double eng = -0.5 * k[type]*r0sq*log(rlogarg); if (rsq < TWO_1_3*sigma[type]*sigma[type]) { double sr2,sr6; sr2 = sigma[type]*sigma[type]/rsq; sr6 = sr2*sr2*sr2; eng += 4.0*epsilon[type]*sr6*(sr6-1.0) + epsilon[type]; } return eng; } diff --git a/src/MOLECULE/bond_fene_expand.cpp b/src/MOLECULE/bond_fene_expand.cpp index 960786156..588bc3f30 100644 --- a/src/MOLECULE/bond_fene_expand.cpp +++ b/src/MOLECULE/bond_fene_expand.cpp @@ -1,275 +1,277 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ #include "math.h" #include "stdlib.h" #include "bond_fene_expand.h" +#include "lmptype.h" #include "atom.h" #include "neighbor.h" #include "domain.h" #include "comm.h" #include "update.h" #include "force.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; /* ---------------------------------------------------------------------- */ BondFENEExpand::BondFENEExpand(LAMMPS *lmp) : Bond(lmp) { TWO_1_3 = pow(2.0,(1.0/3.0)); } /* ---------------------------------------------------------------------- */ BondFENEExpand::~BondFENEExpand() { if (allocated) { memory->sfree(setflag); memory->sfree(k); memory->sfree(r0); memory->sfree(epsilon); memory->sfree(sigma); memory->sfree(shift); } } /* ---------------------------------------------------------------------- */ void BondFENEExpand::compute(int eflag, int vflag) { int i1,i2,n,type; double delx,dely,delz,ebond,fbond; double rsq,r0sq,rlogarg,sr2,sr6; double r,rshift,rshiftsq; ebond = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = 0; double **x = atom->x; double **f = atom->f; int **bondlist = neighbor->bondlist; int nbondlist = neighbor->nbondlist; int nlocal = atom->nlocal; int newton_bond = force->newton_bond; for (n = 0; n < nbondlist; n++) { i1 = bondlist[n][0]; i2 = bondlist[n][1]; type = bondlist[n][2]; delx = x[i1][0] - x[i2][0]; dely = x[i1][1] - x[i2][1]; delz = x[i1][2] - x[i2][2]; domain->minimum_image(delx,dely,delz); // force from log term rsq = delx*delx + dely*dely + delz*delz; r = sqrt(rsq); rshift = r - shift[type]; rshiftsq = rshift*rshift; r0sq = r0[type] * r0[type]; rlogarg = 1.0 - rshiftsq/r0sq; // if r -> r0, then rlogarg < 0.0 which is an error // issue a warning and reset rlogarg = epsilon // if r > 2*r0 something serious is wrong, abort if (rlogarg < 0.1) { - char str[128]; - sprintf(str,"FENE bond too long: %d %d %d %g", - update->ntimestep,atom->tag[i1],atom->tag[i2],sqrt(rsq)); + char str[128],fstr[64]; + sprintf(fstr,"FENE bond too long: %s %%d %%d %%g",BIGINT_FORMAT); + sprintf(str,fstr,update->ntimestep,atom->tag[i1],atom->tag[i2],sqrt(rsq)); error->warning(str,0); if (rlogarg <= -3.0) error->one("Bad FENE bond"); rlogarg = 0.1; } fbond = -k[type]*rshift/rlogarg/r; // force from LJ term if (rshiftsq < TWO_1_3*sigma[type]*sigma[type]) { sr2 = sigma[type]*sigma[type]/rshiftsq; sr6 = sr2*sr2*sr2; fbond += 48.0*epsilon[type]*sr6*(sr6-0.5)/rshift/r; } // energy if (eflag) { ebond = -0.5 * k[type]*r0sq*log(rlogarg); if (rshiftsq < TWO_1_3*sigma[type]*sigma[type]) ebond += 4.0*epsilon[type]*sr6*(sr6-1.0) + epsilon[type]; } // apply force to each of 2 atoms if (newton_bond || i1 < nlocal) { f[i1][0] += delx*fbond; f[i1][1] += dely*fbond; f[i1][2] += delz*fbond; } if (newton_bond || i2 < nlocal) { f[i2][0] -= delx*fbond; f[i2][1] -= dely*fbond; f[i2][2] -= delz*fbond; } if (evflag) ev_tally(i1,i2,nlocal,newton_bond,ebond,fbond,delx,dely,delz); } } /* ---------------------------------------------------------------------- */ void BondFENEExpand::allocate() { allocated = 1; int n = atom->nbondtypes; k = (double *) memory->smalloc((n+1)*sizeof(double),"bond:k"); r0 = (double *) memory->smalloc((n+1)*sizeof(double),"bond:r0"); epsilon = (double *) memory->smalloc((n+1)*sizeof(double),"bond:epsilon"); sigma = (double *) memory->smalloc((n+1)*sizeof(double),"bond:sigma"); shift = (double *) memory->smalloc((n+1)*sizeof(double),"bond:shift"); setflag = (int *) memory->smalloc((n+1)*sizeof(int),"bond:setflag"); for (int i = 1; i <= n; i++) setflag[i] = 0; } /* ---------------------------------------------------------------------- set coeffs for one type ------------------------------------------------------------------------- */ void BondFENEExpand::coeff(int narg, char **arg) { if (narg != 6) error->all("Incorrect args for bond coefficients"); if (!allocated) allocate(); int ilo,ihi; force->bounds(arg[0],atom->nbondtypes,ilo,ihi); double k_one = force->numeric(arg[1]); double r0_one = force->numeric(arg[2]); double epsilon_one = force->numeric(arg[3]); double sigma_one = force->numeric(arg[4]); double shift_one = force->numeric(arg[5]); int count = 0; for (int i = ilo; i <= ihi; i++) { k[i] = k_one; r0[i] = r0_one; epsilon[i] = epsilon_one; sigma[i] = sigma_one; shift[i] = shift_one; setflag[i] = 1; count++; } if (count == 0) error->all("Incorrect args for bond coefficients"); } /* ---------------------------------------------------------------------- check if special_bond settings are valid ------------------------------------------------------------------------- */ void BondFENEExpand::init_style() { // special bonds should be 0 1 1 if (force->special_lj[1] != 0.0 || force->special_lj[2] != 1.0 || force->special_lj[3] != 1.0) { if (comm->me == 0) error->warning("Use special bonds = 0,1,1 with bond style fene/expand"); } } /* ---------------------------------------------------------------------- */ double BondFENEExpand::equilibrium_distance(int i) { return 0.97*sigma[i] + shift[i]; } /* ---------------------------------------------------------------------- proc 0 writes to restart file ------------------------------------------------------------------------- */ void BondFENEExpand::write_restart(FILE *fp) { fwrite(&k[1],sizeof(double),atom->nbondtypes,fp); fwrite(&r0[1],sizeof(double),atom->nbondtypes,fp); fwrite(&epsilon[1],sizeof(double),atom->nbondtypes,fp); fwrite(&sigma[1],sizeof(double),atom->nbondtypes,fp); fwrite(&shift[1],sizeof(double),atom->nbondtypes,fp); } /* ---------------------------------------------------------------------- proc 0 reads from restart file, bcasts ------------------------------------------------------------------------- */ void BondFENEExpand::read_restart(FILE *fp) { allocate(); if (comm->me == 0) { fread(&k[1],sizeof(double),atom->nbondtypes,fp); fread(&r0[1],sizeof(double),atom->nbondtypes,fp); fread(&epsilon[1],sizeof(double),atom->nbondtypes,fp); fread(&sigma[1],sizeof(double),atom->nbondtypes,fp); fread(&shift[1],sizeof(double),atom->nbondtypes,fp); } MPI_Bcast(&k[1],atom->nbondtypes,MPI_DOUBLE,0,world); MPI_Bcast(&r0[1],atom->nbondtypes,MPI_DOUBLE,0,world); MPI_Bcast(&epsilon[1],atom->nbondtypes,MPI_DOUBLE,0,world); MPI_Bcast(&sigma[1],atom->nbondtypes,MPI_DOUBLE,0,world); MPI_Bcast(&shift[1],atom->nbondtypes,MPI_DOUBLE,0,world); for (int i = 1; i <= atom->nbondtypes; i++) setflag[i] = 1; } /* ---------------------------------------------------------------------- */ double BondFENEExpand::single(int type, double rsq, int i, int j) { double r = sqrt(rsq); double rshift = r - shift[type]; double rshiftsq = rshift*rshift; double r0sq = r0[type] * r0[type]; double rlogarg = 1.0 - rshiftsq/r0sq; // if r -> r0, then rlogarg < 0.0 which is an error // issue a warning and reset rlogarg = epsilon // if r > 2*r0 something serious is wrong, abort if (rlogarg < 0.1) { - char str[128]; - sprintf(str,"FENE bond too long: %d %g",update->ntimestep,sqrt(rsq)); + char str[128],fstr[64]; + sprintf(fstr,"FENE bond too long: %s %%g",BIGINT_FORMAT); + sprintf(str,fstr,update->ntimestep,sqrt(rsq)); error->warning(str,0); if (rlogarg <= -3.0) error->one("Bad FENE bond"); rlogarg = 0.1; } double eng = -0.5 * k[type]*r0sq*log(rlogarg); if (rshiftsq < TWO_1_3*sigma[type]*sigma[type]) { double sr2,sr6; sr2 = sigma[type]*sigma[type]/rshiftsq; sr6 = sr2*sr2*sr2; eng += 4.0*epsilon[type]*sr6*(sr6-1.0) + epsilon[type]; } return eng; } diff --git a/src/MOLECULE/dihedral_charmm.cpp b/src/MOLECULE/dihedral_charmm.cpp index f2b7d4945..2aae7fd3e 100644 --- a/src/MOLECULE/dihedral_charmm.cpp +++ b/src/MOLECULE/dihedral_charmm.cpp @@ -1,432 +1,433 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- Contributing author: Paul Crozier (SNL) ------------------------------------------------------------------------- */ #include "mpi.h" #include "math.h" #include "stdlib.h" #include "dihedral_charmm.h" +#include "lmptype.h" #include "atom.h" #include "comm.h" #include "neighbor.h" #include "domain.h" #include "force.h" #include "pair.h" #include "update.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; #define TOLERANCE 0.05 /* ---------------------------------------------------------------------- */ DihedralCharmm::DihedralCharmm(LAMMPS *lmp) : Dihedral(lmp) {} /* ---------------------------------------------------------------------- */ DihedralCharmm::~DihedralCharmm() { if (allocated) { memory->sfree(setflag); memory->sfree(k); memory->sfree(multiplicity); memory->sfree(shift); memory->sfree(cos_shift); memory->sfree(sin_shift); memory->sfree(weight); } } /* ---------------------------------------------------------------------- */ void DihedralCharmm::compute(int eflag, int vflag) { int i1,i2,i3,i4,i,m,n,type; double vb1x,vb1y,vb1z,vb2x,vb2y,vb2z,vb3x,vb3y,vb3z,vb2xm,vb2ym,vb2zm; double edihedral,f1[3],f2[3],f3[3],f4[3]; double ax,ay,az,bx,by,bz,rasq,rbsq,rgsq,rg,rginv,ra2inv,rb2inv,rabinv; double df,df1,ddf1,fg,hg,fga,hgb,gaa,gbb; double dtfx,dtfy,dtfz,dtgx,dtgy,dtgz,dthx,dthy,dthz; double c,s,p,sx2,sy2,sz2; int itype,jtype; double delx,dely,delz,rsq,r2inv,r6inv; double forcecoul,forcelj,fpair,ecoul,evdwl; edihedral = evdwl = ecoul = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = 0; // insure pair->ev_tally() will use 1-4 virial contribution if (weightflag && vflag_global == 2) force->pair->vflag_either = force->pair->vflag_global = 1; double **x = atom->x; double **f = atom->f; double *q = atom->q; int *atomtype = atom->type; int **dihedrallist = neighbor->dihedrallist; int ndihedrallist = neighbor->ndihedrallist; int nlocal = atom->nlocal; int newton_bond = force->newton_bond; double qqrd2e = force->qqrd2e; for (n = 0; n < ndihedrallist; n++) { i1 = dihedrallist[n][0]; i2 = dihedrallist[n][1]; i3 = dihedrallist[n][2]; i4 = dihedrallist[n][3]; type = dihedrallist[n][4]; // 1st bond vb1x = x[i1][0] - x[i2][0]; vb1y = x[i1][1] - x[i2][1]; vb1z = x[i1][2] - x[i2][2]; domain->minimum_image(vb1x,vb1y,vb1z); // 2nd bond vb2x = x[i3][0] - x[i2][0]; vb2y = x[i3][1] - x[i2][1]; vb2z = x[i3][2] - x[i2][2]; domain->minimum_image(vb2x,vb2y,vb2z); vb2xm = -vb2x; vb2ym = -vb2y; vb2zm = -vb2z; domain->minimum_image(vb2xm,vb2ym,vb2zm); // 3rd bond vb3x = x[i4][0] - x[i3][0]; vb3y = x[i4][1] - x[i3][1]; vb3z = x[i4][2] - x[i3][2]; domain->minimum_image(vb3x,vb3y,vb3z); ax = vb1y*vb2zm - vb1z*vb2ym; ay = vb1z*vb2xm - vb1x*vb2zm; az = vb1x*vb2ym - vb1y*vb2xm; bx = vb3y*vb2zm - vb3z*vb2ym; by = vb3z*vb2xm - vb3x*vb2zm; bz = vb3x*vb2ym - vb3y*vb2xm; rasq = ax*ax + ay*ay + az*az; rbsq = bx*bx + by*by + bz*bz; rgsq = vb2xm*vb2xm + vb2ym*vb2ym + vb2zm*vb2zm; rg = sqrt(rgsq); rginv = ra2inv = rb2inv = 0.0; if (rg > 0) rginv = 1.0/rg; if (rasq > 0) ra2inv = 1.0/rasq; if (rbsq > 0) rb2inv = 1.0/rbsq; rabinv = sqrt(ra2inv*rb2inv); c = (ax*bx + ay*by + az*bz)*rabinv; s = rg*rabinv*(ax*vb3x + ay*vb3y + az*vb3z); // error check if (c > 1.0 + TOLERANCE || c < (-1.0 - TOLERANCE)) { int me; MPI_Comm_rank(world,&me); if (screen) { - char str[128]; - sprintf(str,"Dihedral problem: %d %d %d %d %d %d", - me,update->ntimestep, + char str[128],fstr[64]; + sprintf(fstr,"Dihedral problem: %%d %s %%d %%d %%d %%d",BIGINT_FORMAT); + sprintf(str,fstr,me,update->ntimestep, atom->tag[i1],atom->tag[i2],atom->tag[i3],atom->tag[i4]); error->warning(str,0); fprintf(screen," 1st atom: %d %g %g %g\n", me,x[i1][0],x[i1][1],x[i1][2]); fprintf(screen," 2nd atom: %d %g %g %g\n", me,x[i2][0],x[i2][1],x[i2][2]); fprintf(screen," 3rd atom: %d %g %g %g\n", me,x[i3][0],x[i3][1],x[i3][2]); fprintf(screen," 4th atom: %d %g %g %g\n", me,x[i4][0],x[i4][1],x[i4][2]); } } if (c > 1.0) c = 1.0; if (c < -1.0) c = -1.0; m = multiplicity[type]; p = 1.0; df1 = 0.0; for (i = 0; i < m; i++) { ddf1 = p*c - df1*s; df1 = p*s + df1*c; p = ddf1; } p = p*cos_shift[type] + df1*sin_shift[type]; df1 = df1*cos_shift[type] - ddf1*sin_shift[type]; df1 *= -m; p += 1.0; if (m == 0) { p = 1.0 + cos_shift[type]; df1 = 0.0; } if (eflag) edihedral = k[type] * p; fg = vb1x*vb2xm + vb1y*vb2ym + vb1z*vb2zm; hg = vb3x*vb2xm + vb3y*vb2ym + vb3z*vb2zm; fga = fg*ra2inv*rginv; hgb = hg*rb2inv*rginv; gaa = -ra2inv*rg; gbb = rb2inv*rg; dtfx = gaa*ax; dtfy = gaa*ay; dtfz = gaa*az; dtgx = fga*ax - hgb*bx; dtgy = fga*ay - hgb*by; dtgz = fga*az - hgb*bz; dthx = gbb*bx; dthy = gbb*by; dthz = gbb*bz; df = -k[type] * df1; sx2 = df*dtgx; sy2 = df*dtgy; sz2 = df*dtgz; f1[0] = df*dtfx; f1[1] = df*dtfy; f1[2] = df*dtfz; f2[0] = sx2 - f1[0]; f2[1] = sy2 - f1[1]; f2[2] = sz2 - f1[2]; f4[0] = df*dthx; f4[1] = df*dthy; f4[2] = df*dthz; f3[0] = -sx2 - f4[0]; f3[1] = -sy2 - f4[1]; f3[2] = -sz2 - f4[2]; // apply force to each of 4 atoms if (newton_bond || i1 < nlocal) { f[i1][0] += f1[0]; f[i1][1] += f1[1]; f[i1][2] += f1[2]; } if (newton_bond || i2 < nlocal) { f[i2][0] += f2[0]; f[i2][1] += f2[1]; f[i2][2] += f2[2]; } if (newton_bond || i3 < nlocal) { f[i3][0] += f3[0]; f[i3][1] += f3[1]; f[i3][2] += f3[2]; } if (newton_bond || i4 < nlocal) { f[i4][0] += f4[0]; f[i4][1] += f4[1]; f[i4][2] += f4[2]; } if (evflag) ev_tally(i1,i2,i3,i4,nlocal,newton_bond,edihedral,f1,f3,f4, vb1x,vb1y,vb1z,vb2x,vb2y,vb2z,vb3x,vb3y,vb3z); // 1-4 LJ and Coulomb interactions // tally energy/virial in pair, using newton_bond as newton flag if (weight[type] > 0.0) { itype = atomtype[i1]; jtype = atomtype[i4]; delx = x[i1][0] - x[i4][0]; dely = x[i1][1] - x[i4][1]; delz = x[i1][2] - x[i4][2]; domain->minimum_image(delx,dely,delz); rsq = delx*delx + dely*dely + delz*delz; r2inv = 1.0/rsq; r6inv = r2inv*r2inv*r2inv; if (implicit) forcecoul = qqrd2e * q[i1]*q[i4]*r2inv; else forcecoul = qqrd2e * q[i1]*q[i4]*sqrt(r2inv); forcelj = r6inv * (lj14_1[itype][jtype]*r6inv - lj14_2[itype][jtype]); fpair = weight[type] * (forcelj+forcecoul)*r2inv; if (eflag) { ecoul = weight[type] * forcecoul; evdwl = r6inv * (lj14_3[itype][jtype]*r6inv - lj14_4[itype][jtype]); evdwl *= weight[type]; } if (newton_bond || i1 < nlocal) { f[i1][0] += delx*fpair; f[i1][1] += dely*fpair; f[i1][2] += delz*fpair; } if (newton_bond || i4 < nlocal) { f[i4][0] -= delx*fpair; f[i4][1] -= dely*fpair; f[i4][2] -= delz*fpair; } if (evflag) force->pair->ev_tally(i1,i4,nlocal,newton_bond, evdwl,ecoul,fpair,delx,dely,delz); } } } /* ---------------------------------------------------------------------- */ void DihedralCharmm::allocate() { allocated = 1; int n = atom->ndihedraltypes; k = (double *) memory->smalloc((n+1)*sizeof(double),"dihedral:k"); multiplicity = (int *) memory->smalloc((n+1)*sizeof(double),"dihedral:multiplicity"); shift = (int *) memory->smalloc((n+1)*sizeof(double),"dihedral:shift"); cos_shift = (double *) memory->smalloc((n+1)*sizeof(double),"dihedral:cos_shift"); sin_shift = (double *) memory->smalloc((n+1)*sizeof(double),"dihedral:sin_shift"); weight = (double *) memory->smalloc((n+1)*sizeof(double),"dihedral:weight"); setflag = (int *) memory->smalloc((n+1)*sizeof(int),"dihedral:setflag"); for (int i = 1; i <= n; i++) setflag[i] = 0; } /* ---------------------------------------------------------------------- set coeffs for one type ------------------------------------------------------------------------- */ void DihedralCharmm::coeff(int narg, char **arg) { if (narg != 5) error->all("Incorrect args for dihedral coefficients"); if (!allocated) allocate(); int ilo,ihi; force->bounds(arg[0],atom->ndihedraltypes,ilo,ihi); // require integer values of shift for backwards compatibility // arbitrary phase angle shift could be allowed, but would break // backwards compatibility and is probably not needed double k_one = force->numeric(arg[1]); int multiplicity_one = force->inumeric(arg[2]); int shift_one = force->inumeric(arg[3]); double weight_one = force->numeric(arg[4]); if (multiplicity_one < 0) error->all("Incorrect multiplicity arg for dihedral coefficients"); if (weight_one < 0.0 || weight_one > 1.0) error->all("Incorrect weight arg for dihedral coefficients"); double PI = 4.0*atan(1.0); int count = 0; for (int i = ilo; i <= ihi; i++) { k[i] = k_one; shift[i] = shift_one; cos_shift[i] = cos(PI*shift_one/180.0); sin_shift[i] = sin(PI*shift_one/180.0); multiplicity[i] = multiplicity_one; weight[i] = weight_one; setflag[i] = 1; count++; } if (count == 0) error->all("Incorrect args for dihedral coefficients"); } /* ---------------------------------------------------------------------- error check and initialize all values needed for force computation ------------------------------------------------------------------------- */ void DihedralCharmm::init_style() { // insure use of CHARMM pair_style if any weight factors are non-zero // set local ptrs to LJ 14 arrays setup by Pair weightflag = 0; for (int i = 1; i <= atom->ndihedraltypes; i++) if (weight[i] > 0.0) weightflag = 1; if (weightflag) { int itmp; if (force->pair == NULL) error->all("Dihedral charmm is incompatible with Pair style"); lj14_1 = (double **) force->pair->extract("lj14_1",itmp); lj14_2 = (double **) force->pair->extract("lj14_2",itmp); lj14_3 = (double **) force->pair->extract("lj14_3",itmp); lj14_4 = (double **) force->pair->extract("lj14_4",itmp); int *ptr = (int *) force->pair->extract("implicit",itmp); if (!lj14_1 || !lj14_2 || !lj14_3 || !lj14_4 || !ptr) error->all("Dihedral charmm is incompatible with Pair style"); implicit = *ptr; } } /* ---------------------------------------------------------------------- proc 0 writes out coeffs to restart file ------------------------------------------------------------------------- */ void DihedralCharmm::write_restart(FILE *fp) { fwrite(&k[1],sizeof(double),atom->ndihedraltypes,fp); fwrite(&multiplicity[1],sizeof(int),atom->ndihedraltypes,fp); fwrite(&shift[1],sizeof(int),atom->ndihedraltypes,fp); fwrite(&weight[1],sizeof(double),atom->ndihedraltypes,fp); } /* ---------------------------------------------------------------------- proc 0 reads coeffs from restart file, bcasts them ------------------------------------------------------------------------- */ void DihedralCharmm::read_restart(FILE *fp) { allocate(); if (comm->me == 0) { fread(&k[1],sizeof(double),atom->ndihedraltypes,fp); fread(&multiplicity[1],sizeof(int),atom->ndihedraltypes,fp); fread(&shift[1],sizeof(int),atom->ndihedraltypes,fp); fread(&weight[1],sizeof(double),atom->ndihedraltypes,fp); } MPI_Bcast(&k[1],atom->ndihedraltypes,MPI_DOUBLE,0,world); MPI_Bcast(&multiplicity[1],atom->ndihedraltypes,MPI_INT,0,world); MPI_Bcast(&shift[1],atom->ndihedraltypes,MPI_INT,0,world); MPI_Bcast(&weight[1],atom->ndihedraltypes,MPI_DOUBLE,0,world); double PI = 4.0*atan(1.0); for (int i = 1; i <= atom->ndihedraltypes; i++) { setflag[i] = 1; cos_shift[i] = cos(PI*shift[i]/180.0); sin_shift[i] = sin(PI*shift[i]/180.0); } } diff --git a/src/MOLECULE/dihedral_harmonic.cpp b/src/MOLECULE/dihedral_harmonic.cpp index 6e76a66dd..a2f62f5b4 100644 --- a/src/MOLECULE/dihedral_harmonic.cpp +++ b/src/MOLECULE/dihedral_harmonic.cpp @@ -1,353 +1,354 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- Contributing author: Paul Crozier (SNL) ------------------------------------------------------------------------- */ #include "mpi.h" #include "math.h" #include "stdlib.h" #include "dihedral_harmonic.h" +#include "lmptype.h" #include "atom.h" #include "comm.h" #include "neighbor.h" #include "domain.h" #include "force.h" #include "update.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; #define TOLERANCE 0.05 #define SMALL 0.001 /* ---------------------------------------------------------------------- */ DihedralHarmonic::DihedralHarmonic(LAMMPS *lmp) : Dihedral(lmp) {} /* ---------------------------------------------------------------------- */ DihedralHarmonic::~DihedralHarmonic() { if (allocated) { memory->sfree(setflag); memory->sfree(k); memory->sfree(sign); memory->sfree(multiplicity); memory->sfree(cos_shift); memory->sfree(sin_shift); } } /* ---------------------------------------------------------------------- */ void DihedralHarmonic::compute(int eflag, int vflag) { int i1,i2,i3,i4,i,m,n,type; double vb1x,vb1y,vb1z,vb2x,vb2y,vb2z,vb3x,vb3y,vb3z,vb2xm,vb2ym,vb2zm; double edihedral,f1[3],f2[3],f3[3],f4[3]; double ax,ay,az,bx,by,bz,rasq,rbsq,rgsq,rg,rginv,ra2inv,rb2inv,rabinv; double df,df1,ddf1,fg,hg,fga,hgb,gaa,gbb; double dtfx,dtfy,dtfz,dtgx,dtgy,dtgz,dthx,dthy,dthz; double c,s,p,sx2,sy2,sz2; edihedral = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = 0; double **x = atom->x; double **f = atom->f; int **dihedrallist = neighbor->dihedrallist; int ndihedrallist = neighbor->ndihedrallist; int nlocal = atom->nlocal; int newton_bond = force->newton_bond; for (n = 0; n < ndihedrallist; n++) { i1 = dihedrallist[n][0]; i2 = dihedrallist[n][1]; i3 = dihedrallist[n][2]; i4 = dihedrallist[n][3]; type = dihedrallist[n][4]; // 1st bond vb1x = x[i1][0] - x[i2][0]; vb1y = x[i1][1] - x[i2][1]; vb1z = x[i1][2] - x[i2][2]; domain->minimum_image(vb1x,vb1y,vb1z); // 2nd bond vb2x = x[i3][0] - x[i2][0]; vb2y = x[i3][1] - x[i2][1]; vb2z = x[i3][2] - x[i2][2]; domain->minimum_image(vb2x,vb2y,vb2z); vb2xm = -vb2x; vb2ym = -vb2y; vb2zm = -vb2z; domain->minimum_image(vb2xm,vb2ym,vb2zm); // 3rd bond vb3x = x[i4][0] - x[i3][0]; vb3y = x[i4][1] - x[i3][1]; vb3z = x[i4][2] - x[i3][2]; domain->minimum_image(vb3x,vb3y,vb3z); // c,s calculation ax = vb1y*vb2zm - vb1z*vb2ym; ay = vb1z*vb2xm - vb1x*vb2zm; az = vb1x*vb2ym - vb1y*vb2xm; bx = vb3y*vb2zm - vb3z*vb2ym; by = vb3z*vb2xm - vb3x*vb2zm; bz = vb3x*vb2ym - vb3y*vb2xm; rasq = ax*ax + ay*ay + az*az; rbsq = bx*bx + by*by + bz*bz; rgsq = vb2xm*vb2xm + vb2ym*vb2ym + vb2zm*vb2zm; rg = sqrt(rgsq); rginv = ra2inv = rb2inv = 0.0; if (rg > 0) rginv = 1.0/rg; if (rasq > 0) ra2inv = 1.0/rasq; if (rbsq > 0) rb2inv = 1.0/rbsq; rabinv = sqrt(ra2inv*rb2inv); c = (ax*bx + ay*by + az*bz)*rabinv; s = rg*rabinv*(ax*vb3x + ay*vb3y + az*vb3z); // error check if (c > 1.0 + TOLERANCE || c < (-1.0 - TOLERANCE)) { int me; MPI_Comm_rank(world,&me); if (screen) { - char str[128]; - sprintf(str,"Dihedral problem: %d %d %d %d %d %d", - me,update->ntimestep, + char str[128],fstr[64]; + sprintf(fstr,"Dihedral problem: %%d %s %%d %%d %%d %%d",BIGINT_FORMAT); + sprintf(str,fstr,me,update->ntimestep, atom->tag[i1],atom->tag[i2],atom->tag[i3],atom->tag[i4]); error->warning(str,0); fprintf(screen," 1st atom: %d %g %g %g\n", me,x[i1][0],x[i1][1],x[i1][2]); fprintf(screen," 2nd atom: %d %g %g %g\n", me,x[i2][0],x[i2][1],x[i2][2]); fprintf(screen," 3rd atom: %d %g %g %g\n", me,x[i3][0],x[i3][1],x[i3][2]); fprintf(screen," 4th atom: %d %g %g %g\n", me,x[i4][0],x[i4][1],x[i4][2]); } } if (c > 1.0) c = 1.0; if (c < -1.0) c = -1.0; m = multiplicity[type]; p = 1.0; df1 = 0.0; for (i = 0; i < m; i++) { ddf1 = p*c - df1*s; df1 = p*s + df1*c; p = ddf1; } p = p*cos_shift[type] + df1*sin_shift[type]; df1 = df1*cos_shift[type] - ddf1*sin_shift[type]; df1 *= -m; p += 1.0; if (m == 0) { p = 1.0 + cos_shift[type]; df1 = 0.0; } if (eflag) edihedral = k[type] * p; fg = vb1x*vb2xm + vb1y*vb2ym + vb1z*vb2zm; hg = vb3x*vb2xm + vb3y*vb2ym + vb3z*vb2zm; fga = fg*ra2inv*rginv; hgb = hg*rb2inv*rginv; gaa = -ra2inv*rg; gbb = rb2inv*rg; dtfx = gaa*ax; dtfy = gaa*ay; dtfz = gaa*az; dtgx = fga*ax - hgb*bx; dtgy = fga*ay - hgb*by; dtgz = fga*az - hgb*bz; dthx = gbb*bx; dthy = gbb*by; dthz = gbb*bz; df = -k[type] * df1; sx2 = df*dtgx; sy2 = df*dtgy; sz2 = df*dtgz; f1[0] = df*dtfx; f1[1] = df*dtfy; f1[2] = df*dtfz; f2[0] = sx2 - f1[0]; f2[1] = sy2 - f1[1]; f2[2] = sz2 - f1[2]; f4[0] = df*dthx; f4[1] = df*dthy; f4[2] = df*dthz; f3[0] = -sx2 - f4[0]; f3[1] = -sy2 - f4[1]; f3[2] = -sz2 - f4[2]; // apply force to each of 4 atoms if (newton_bond || i1 < nlocal) { f[i1][0] += f1[0]; f[i1][1] += f1[1]; f[i1][2] += f1[2]; } if (newton_bond || i2 < nlocal) { f[i2][0] += f2[0]; f[i2][1] += f2[1]; f[i2][2] += f2[2]; } if (newton_bond || i3 < nlocal) { f[i3][0] += f3[0]; f[i3][1] += f3[1]; f[i3][2] += f3[2]; } if (newton_bond || i4 < nlocal) { f[i4][0] += f4[0]; f[i4][1] += f4[1]; f[i4][2] += f4[2]; } if (evflag) ev_tally(i1,i2,i3,i4,nlocal,newton_bond,edihedral,f1,f3,f4, vb1x,vb1y,vb1z,vb2x,vb2y,vb2z,vb3x,vb3y,vb3z); } } /* ---------------------------------------------------------------------- */ void DihedralHarmonic::allocate() { allocated = 1; int n = atom->ndihedraltypes; k = (double *) memory->smalloc((n+1)*sizeof(double),"dihedral:k"); sign = (int *) memory->smalloc((n+1)*sizeof(double),"dihedral:sign"); multiplicity = (int *) memory->smalloc((n+1)*sizeof(double),"dihedral:multiplicity"); cos_shift = (double *) memory->smalloc((n+1)*sizeof(double),"dihedral:cos_shift"); sin_shift = (double *) memory->smalloc((n+1)*sizeof(double),"dihedral:sin_shift"); setflag = (int *) memory->smalloc((n+1)*sizeof(int),"dihedral:setflag"); for (int i = 1; i <= n; i++) setflag[i] = 0; } /* ---------------------------------------------------------------------- set coeffs for one type ------------------------------------------------------------------------- */ void DihedralHarmonic::coeff(int narg, char **arg) { if (narg != 4) error->all("Incorrect args for dihedral coefficients"); if (!allocated) allocate(); int ilo,ihi; force->bounds(arg[0],atom->ndihedraltypes,ilo,ihi); double k_one = force->numeric(arg[1]); int sign_one = force->inumeric(arg[2]); int multiplicity_one = force->inumeric(arg[3]); // require sign = +/- 1 for backwards compatibility // arbitrary phase angle shift could be allowed, but would break // backwards compatibility and is probably not needed if (sign_one != -1 && sign_one != 1) error->all("Incorrect sign arg for dihedral coefficients"); if (multiplicity_one < 0) error->all("Incorrect multiplicity arg for dihedral coefficients"); int count = 0; for (int i = ilo; i <= ihi; i++) { k[i] = k_one; sign[i] = sign_one; if (sign[i] == 1) { cos_shift[i] = 1; sin_shift[i] = 0; } else { cos_shift[i] = -1; sin_shift[i] = 0; } multiplicity[i] = multiplicity_one; setflag[i] = 1; count++; } if (count == 0) error->all("Incorrect args for dihedral coefficients"); } /* ---------------------------------------------------------------------- proc 0 writes out coeffs to restart file ------------------------------------------------------------------------- */ void DihedralHarmonic::write_restart(FILE *fp) { fwrite(&k[1],sizeof(double),atom->ndihedraltypes,fp); fwrite(&sign[1],sizeof(int),atom->ndihedraltypes,fp); fwrite(&multiplicity[1],sizeof(int),atom->ndihedraltypes,fp); } /* ---------------------------------------------------------------------- proc 0 reads coeffs from restart file, bcasts them ------------------------------------------------------------------------- */ void DihedralHarmonic::read_restart(FILE *fp) { allocate(); if (comm->me == 0) { fread(&k[1],sizeof(double),atom->ndihedraltypes,fp); fread(&sign[1],sizeof(int),atom->ndihedraltypes,fp); fread(&multiplicity[1],sizeof(int),atom->ndihedraltypes,fp); } MPI_Bcast(&k[1],atom->ndihedraltypes,MPI_DOUBLE,0,world); MPI_Bcast(&sign[1],atom->ndihedraltypes,MPI_INT,0,world); MPI_Bcast(&multiplicity[1],atom->ndihedraltypes,MPI_INT,0,world); for (int i = 1; i <= atom->ndihedraltypes; i++) { setflag[i] = 1; if (sign[i] == 1) { cos_shift[i] = 1; sin_shift[i] = 0; } else { cos_shift[i] = -1; sin_shift[i] = 0; } } } diff --git a/src/MOLECULE/dihedral_helix.cpp b/src/MOLECULE/dihedral_helix.cpp index f5b56b3e4..6b9520339 100644 --- a/src/MOLECULE/dihedral_helix.cpp +++ b/src/MOLECULE/dihedral_helix.cpp @@ -1,337 +1,338 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- Contributing authors: Naveen Michaud-Agrawal (Johns Hopkins U) and Mark Stevens (Sandia) ------------------------------------------------------------------------- */ #include "math.h" #include "stdlib.h" #include "mpi.h" #include "dihedral_helix.h" +#include "lmptype.h" #include "atom.h" #include "neighbor.h" #include "domain.h" #include "comm.h" #include "force.h" #include "update.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; #define MIN(A,B) ((A) < (B)) ? (A) : (B) #define MAX(A,B) ((A) > (B)) ? (A) : (B) #define TOLERANCE 0.05 #define SMALL 0.001 #define SMALLER 0.00001 /* ---------------------------------------------------------------------- */ DihedralHelix::DihedralHelix(LAMMPS *lmp) : Dihedral(lmp) {} /* ---------------------------------------------------------------------- */ DihedralHelix::~DihedralHelix() { if (allocated) { memory->sfree(setflag); memory->sfree(aphi); memory->sfree(bphi); memory->sfree(cphi); } } /* ---------------------------------------------------------------------- */ void DihedralHelix::compute(int eflag, int vflag) { int i1,i2,i3,i4,n,type; double vb1x,vb1y,vb1z,vb2x,vb2y,vb2z,vb3x,vb3y,vb3z,vb2xm,vb2ym,vb2zm; double edihedral,f1[3],f2[3],f3[3],f4[3]; double sb1,sb2,sb3,rb1,rb3,c0,b1mag2,b1mag,b2mag2; double b2mag,b3mag2,b3mag,ctmp,r12c1,c1mag,r12c2; double c2mag,sc1,sc2,s1,s12,c,p,pd,a,a11,a22; double a33,a12,a13,a23,sx2,sy2,sz2; double s2,cx,cy,cz,cmag,dx,phi,si,siinv,sin2; edihedral = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = 0; double **x = atom->x; double **f = atom->f; int **dihedrallist = neighbor->dihedrallist; int ndihedrallist = neighbor->ndihedrallist; int nlocal = atom->nlocal; int newton_bond = force->newton_bond; for (n = 0; n < ndihedrallist; n++) { i1 = dihedrallist[n][0]; i2 = dihedrallist[n][1]; i3 = dihedrallist[n][2]; i4 = dihedrallist[n][3]; type = dihedrallist[n][4]; // 1st bond vb1x = x[i1][0] - x[i2][0]; vb1y = x[i1][1] - x[i2][1]; vb1z = x[i1][2] - x[i2][2]; domain->minimum_image(vb1x,vb1y,vb1z); // 2nd bond vb2x = x[i3][0] - x[i2][0]; vb2y = x[i3][1] - x[i2][1]; vb2z = x[i3][2] - x[i2][2]; domain->minimum_image(vb2x,vb2y,vb2z); vb2xm = -vb2x; vb2ym = -vb2y; vb2zm = -vb2z; domain->minimum_image(vb2xm,vb2ym,vb2zm); // 3rd bond vb3x = x[i4][0] - x[i3][0]; vb3y = x[i4][1] - x[i3][1]; vb3z = x[i4][2] - x[i3][2]; domain->minimum_image(vb3x,vb3y,vb3z); // c0 calculation sb1 = 1.0 / (vb1x*vb1x + vb1y*vb1y + vb1z*vb1z); sb2 = 1.0 / (vb2x*vb2x + vb2y*vb2y + vb2z*vb2z); sb3 = 1.0 / (vb3x*vb3x + vb3y*vb3y + vb3z*vb3z); rb1 = sqrt(sb1); rb3 = sqrt(sb3); c0 = (vb1x*vb3x + vb1y*vb3y + vb1z*vb3z) * rb1*rb3; // 1st and 2nd angle b1mag2 = vb1x*vb1x + vb1y*vb1y + vb1z*vb1z; b1mag = sqrt(b1mag2); b2mag2 = vb2x*vb2x + vb2y*vb2y + vb2z*vb2z; b2mag = sqrt(b2mag2); b3mag2 = vb3x*vb3x + vb3y*vb3y + vb3z*vb3z; b3mag = sqrt(b3mag2); ctmp = vb1x*vb2x + vb1y*vb2y + vb1z*vb2z; r12c1 = 1.0 / (b1mag*b2mag); c1mag = ctmp * r12c1; ctmp = vb2xm*vb3x + vb2ym*vb3y + vb2zm*vb3z; r12c2 = 1.0 / (b2mag*b3mag); c2mag = ctmp * r12c2; // cos and sin of 2 angles and final c sin2 = MAX(1.0 - c1mag*c1mag,0.0); sc1 = sqrt(sin2); if (sc1 < SMALL) sc1 = SMALL; sc1 = 1.0/sc1; sin2 = MAX(1.0 - c2mag*c2mag,0.0); sc2 = sqrt(sin2); if (sc2 < SMALL) sc2 = SMALL; sc2 = 1.0/sc2; s1 = sc1 * sc1; s2 = sc2 * sc2; s12 = sc1 * sc2; c = (c0 + c1mag*c2mag) * s12; cx = vb1y*vb2z - vb1z*vb2y; cy = vb1z*vb2x - vb1x*vb2z; cz = vb1x*vb2y - vb1y*vb2x; cmag = sqrt(cx*cx + cy*cy + cz*cz); dx = (cx*vb3x + cy*vb3y + cz*vb3z)/cmag/b3mag; // error check if (c > 1.0 + TOLERANCE || c < (-1.0 - TOLERANCE)) { int me; MPI_Comm_rank(world,&me); if (screen) { - char str[128]; - sprintf(str,"Dihedral problem: %d %d %d %d %d %d", - me,update->ntimestep, + char str[128],fstr[64]; + sprintf(fstr,"Dihedral problem: %%d %s %%d %%d %%d %%d",BIGINT_FORMAT); + sprintf(str,fstr,me,update->ntimestep, atom->tag[i1],atom->tag[i2],atom->tag[i3],atom->tag[i4]); error->warning(str,0); fprintf(screen," 1st atom: %d %g %g %g\n", me,x[i1][0],x[i1][1],x[i1][2]); fprintf(screen," 2nd atom: %d %g %g %g\n", me,x[i2][0],x[i2][1],x[i2][2]); fprintf(screen," 3rd atom: %d %g %g %g\n", me,x[i3][0],x[i3][1],x[i3][2]); fprintf(screen," 4th atom: %d %g %g %g\n", me,x[i4][0],x[i4][1],x[i4][2]); } } if (c > 1.0) c = 1.0; if (c < -1.0) c = -1.0; phi = acos(c); if (dx < 0.0) phi *= -1.0; si = sin(phi); if (fabs(si) < SMALLER) si = SMALLER; siinv = 1.0/si; p = aphi[type]*(1.0 - c) + bphi[type]*(1.0 + cos(3.0*phi)) + cphi[type]*(1.0 + cos(phi + 0.25*PI)); pd = -aphi[type] + 3.0*bphi[type]*sin(3.0*phi)*siinv + cphi[type]*sin(phi + 0.25*PI)*siinv; if (eflag) edihedral = p; a = pd; c = c * a; s12 = s12 * a; a11 = c*sb1*s1; a22 = -sb2 * (2.0*c0*s12 - c*(s1+s2)); a33 = c*sb3*s2; a12 = -r12c1 * (c1mag*c*s1 + c2mag*s12); a13 = -rb1*rb3*s12; a23 = r12c2 * (c2mag*c*s2 + c1mag*s12); sx2 = a12*vb1x + a22*vb2x + a23*vb3x; sy2 = a12*vb1y + a22*vb2y + a23*vb3y; sz2 = a12*vb1z + a22*vb2z + a23*vb3z; f1[0] = a11*vb1x + a12*vb2x + a13*vb3x; f1[1] = a11*vb1y + a12*vb2y + a13*vb3y; f1[2] = a11*vb1z + a12*vb2z + a13*vb3z; f2[0] = -sx2 - f1[0]; f2[1] = -sy2 - f1[1]; f2[2] = -sz2 - f1[2]; f4[0] = a13*vb1x + a23*vb2x + a33*vb3x; f4[1] = a13*vb1y + a23*vb2y + a33*vb3y; f4[2] = a13*vb1z + a23*vb2z + a33*vb3z; f3[0] = sx2 - f4[0]; f3[1] = sy2 - f4[1]; f3[2] = sz2 - f4[2]; // apply force to each of 4 atoms if (newton_bond || i1 < nlocal) { f[i1][0] += f1[0]; f[i1][1] += f1[1]; f[i1][2] += f1[2]; } if (newton_bond || i2 < nlocal) { f[i2][0] += f2[0]; f[i2][1] += f2[1]; f[i2][2] += f2[2]; } if (newton_bond || i3 < nlocal) { f[i3][0] += f3[0]; f[i3][1] += f3[1]; f[i3][2] += f3[2]; } if (newton_bond || i4 < nlocal) { f[i4][0] += f4[0]; f[i4][1] += f4[1]; f[i4][2] += f4[2]; } if (evflag) ev_tally(i1,i2,i3,i4,nlocal,newton_bond,edihedral,f1,f3,f4, vb1x,vb1y,vb1z,vb2x,vb2y,vb2z,vb3x,vb3y,vb3z); } } /* ---------------------------------------------------------------------- */ void DihedralHelix::allocate() { allocated = 1; int n = atom->ndihedraltypes; aphi = (double *) memory->smalloc((n+1)*sizeof(double),"dihedral:aphi"); bphi = (double *) memory->smalloc((n+1)*sizeof(double),"dihedral:bphi"); cphi = (double *) memory->smalloc((n+1)*sizeof(double),"dihedral:cphi"); setflag = (int *) memory->smalloc((n+1)*sizeof(int),"dihedral:setflag"); for (int i = 1; i <= n; i++) setflag[i] = 0; } /* ---------------------------------------------------------------------- set coeffs from one line in input script ------------------------------------------------------------------------- */ void DihedralHelix::coeff(int narg, char **arg) { if (narg != 4) error->all("Incorrect args for dihedral coefficients"); if (!allocated) allocate(); int ilo,ihi; force->bounds(arg[0],atom->ndihedraltypes,ilo,ihi); double aphi_one = force->numeric(arg[1]); double bphi_one = force->numeric(arg[2]); double cphi_one = force->numeric(arg[3]); int count = 0; for (int i = ilo; i <= ihi; i++) { aphi[i] = aphi_one; bphi[i] = bphi_one; cphi[i] = cphi_one; setflag[i] = 1; count++; } if (count == 0) error->all("Incorrect args for dihedral coefficients"); } /* ---------------------------------------------------------------------- proc 0 writes out coeffs to restart file ------------------------------------------------------------------------- */ void DihedralHelix::write_restart(FILE *fp) { fwrite(&aphi[1],sizeof(double),atom->ndihedraltypes,fp); fwrite(&bphi[1],sizeof(double),atom->ndihedraltypes,fp); fwrite(&cphi[1],sizeof(double),atom->ndihedraltypes,fp); } /* ---------------------------------------------------------------------- proc 0 reads coeffs from restart file, bcasts them ------------------------------------------------------------------------- */ void DihedralHelix::read_restart(FILE *fp) { allocate(); if (comm->me == 0) { fread(&aphi[1],sizeof(double),atom->ndihedraltypes,fp); fread(&bphi[1],sizeof(double),atom->ndihedraltypes,fp); fread(&cphi[1],sizeof(double),atom->ndihedraltypes,fp); } MPI_Bcast(&aphi[1],atom->ndihedraltypes,MPI_DOUBLE,0,world); MPI_Bcast(&bphi[1],atom->ndihedraltypes,MPI_DOUBLE,0,world); MPI_Bcast(&cphi[1],atom->ndihedraltypes,MPI_DOUBLE,0,world); for (int i = 1; i <= atom->ndihedraltypes; i++) setflag[i] = 1; } diff --git a/src/MOLECULE/dihedral_multi_harmonic.cpp b/src/MOLECULE/dihedral_multi_harmonic.cpp index e9758cf47..d369db203 100644 --- a/src/MOLECULE/dihedral_multi_harmonic.cpp +++ b/src/MOLECULE/dihedral_multi_harmonic.cpp @@ -1,336 +1,339 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- Contributing author: Mathias Puetz (SNL) and friends ------------------------------------------------------------------------- */ #include "math.h" #include "stdlib.h" #include "dihedral_multi_harmonic.h" +#include "lmptype.h" #include "atom.h" #include "neighbor.h" #include "domain.h" #include "comm.h" #include "force.h" #include "update.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; #define MIN(A,B) ((A) < (B)) ? (A) : (B) #define MAX(A,B) ((A) > (B)) ? (A) : (B) #define TOLERANCE 0.05 #define SMALL 0.001 /* ---------------------------------------------------------------------- */ DihedralMultiHarmonic::DihedralMultiHarmonic(LAMMPS *lmp) : Dihedral(lmp) {} /* ---------------------------------------------------------------------- */ DihedralMultiHarmonic::~DihedralMultiHarmonic() { if (allocated) { memory->sfree(setflag); memory->sfree(a1); memory->sfree(a2); memory->sfree(a3); memory->sfree(a4); memory->sfree(a5); } } /* ---------------------------------------------------------------------- */ void DihedralMultiHarmonic::compute(int eflag, int vflag) { int i1,i2,i3,i4,n,type; double vb1x,vb1y,vb1z,vb2x,vb2y,vb2z,vb3x,vb3y,vb3z,vb2xm,vb2ym,vb2zm; double edihedral,f1[3],f2[3],f3[3],f4[3]; double sb1,sb2,sb3,rb1,rb3,c0,b1mag2,b1mag,b2mag2; double b2mag,b3mag2,b3mag,ctmp,r12c1,c1mag,r12c2; double c2mag,sc1,sc2,s1,s12,c,p,pd,a,a11,a22; double a33,a12,a13,a23,sx2,sy2,sz2; double s2,sin2; edihedral = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = 0; double **x = atom->x; double **f = atom->f; int **dihedrallist = neighbor->dihedrallist; int ndihedrallist = neighbor->ndihedrallist; int nlocal = atom->nlocal; int newton_bond = force->newton_bond; for (n = 0; n < ndihedrallist; n++) { i1 = dihedrallist[n][0]; i2 = dihedrallist[n][1]; i3 = dihedrallist[n][2]; i4 = dihedrallist[n][3]; type = dihedrallist[n][4]; // 1st bond vb1x = x[i1][0] - x[i2][0]; vb1y = x[i1][1] - x[i2][1]; vb1z = x[i1][2] - x[i2][2]; domain->minimum_image(vb1x,vb1y,vb1z); // 2nd bond vb2x = x[i3][0] - x[i2][0]; vb2y = x[i3][1] - x[i2][1]; vb2z = x[i3][2] - x[i2][2]; domain->minimum_image(vb2x,vb2y,vb2z); vb2xm = -vb2x; vb2ym = -vb2y; vb2zm = -vb2z; domain->minimum_image(vb2xm,vb2ym,vb2zm); // 3rd bond vb3x = x[i4][0] - x[i3][0]; vb3y = x[i4][1] - x[i3][1]; vb3z = x[i4][2] - x[i3][2]; domain->minimum_image(vb3x,vb3y,vb3z); // c0 calculation sb1 = 1.0 / (vb1x*vb1x + vb1y*vb1y + vb1z*vb1z); sb2 = 1.0 / (vb2x*vb2x + vb2y*vb2y + vb2z*vb2z); sb3 = 1.0 / (vb3x*vb3x + vb3y*vb3y + vb3z*vb3z); rb1 = sqrt(sb1); rb3 = sqrt(sb3); c0 = (vb1x*vb3x + vb1y*vb3y + vb1z*vb3z) * rb1*rb3; // 1st and 2nd angle b1mag2 = vb1x*vb1x + vb1y*vb1y + vb1z*vb1z; b1mag = sqrt(b1mag2); b2mag2 = vb2x*vb2x + vb2y*vb2y + vb2z*vb2z; b2mag = sqrt(b2mag2); b3mag2 = vb3x*vb3x + vb3y*vb3y + vb3z*vb3z; b3mag = sqrt(b3mag2); ctmp = vb1x*vb2x + vb1y*vb2y + vb1z*vb2z; r12c1 = 1.0 / (b1mag*b2mag); c1mag = ctmp * r12c1; ctmp = vb2xm*vb3x + vb2ym*vb3y + vb2zm*vb3z; r12c2 = 1.0 / (b2mag*b3mag); c2mag = ctmp * r12c2; // cos and sin of 2 angles and final c sin2 = MAX(1.0 - c1mag*c1mag,0.0); sc1 = sqrt(sin2); if (sc1 < SMALL) sc1 = SMALL; sc1 = 1.0/sc1; sin2 = MAX(1.0 - c2mag*c2mag,0.0); sc2 = sqrt(sin2); if (sc2 < SMALL) sc2 = SMALL; sc2 = 1.0/sc2; s1 = sc1 * sc1; s2 = sc2 * sc2; s12 = sc1 * sc2; c = (c0 + c1mag*c2mag) * s12; // error check if (c > 1.0 + TOLERANCE || c < (-1.0 - TOLERANCE)) { + int me; + MPI_Comm_rank(world,&me); if (screen) { - char str[128]; - sprintf(str,"Dihedral problem: %d %d %d %d %d %d", - comm->me,update->ntimestep, + char str[128],fstr[64]; + sprintf(fstr,"Dihedral problem: %%d %s %%d %%d %%d %%d",BIGINT_FORMAT); + sprintf(str,fstr,me,update->ntimestep, atom->tag[i1],atom->tag[i2],atom->tag[i3],atom->tag[i4]); error->warning(str,0); fprintf(screen," 1st atom: %d %g %g %g\n", - comm->me,x[i1][0],x[i1][1],x[i1][2]); + me,x[i1][0],x[i1][1],x[i1][2]); fprintf(screen," 2nd atom: %d %g %g %g\n", - comm->me,x[i2][0],x[i2][1],x[i2][2]); + me,x[i2][0],x[i2][1],x[i2][2]); fprintf(screen," 3rd atom: %d %g %g %g\n", - comm->me,x[i3][0],x[i3][1],x[i3][2]); + me,x[i3][0],x[i3][1],x[i3][2]); fprintf(screen," 4th atom: %d %g %g %g\n", - comm->me,x[i4][0],x[i4][1],x[i4][2]); + me,x[i4][0],x[i4][1],x[i4][2]); } } if (c > 1.0) c = 1.0; if (c < -1.0) c = -1.0; // force & energy // p = sum (i=1,5) a_i * c**(i-1) // pd = dp/dc p = a1[type] + c*(a2[type] + c*(a3[type] + c*(a4[type] + c*a5[type]))); pd = a2[type] + c*(2.0*a3[type] + c*(3.0*a4[type] + c*4.0*a5[type])); if (eflag) edihedral = p; a = pd; c = c * a; s12 = s12 * a; a11 = c*sb1*s1; a22 = -sb2 * (2.0*c0*s12 - c*(s1+s2)); a33 = c*sb3*s2; a12 = -r12c1*(c1mag*c*s1 + c2mag*s12); a13 = -rb1*rb3*s12; a23 = r12c2*(c2mag*c*s2 + c1mag*s12); sx2 = a12*vb1x + a22*vb2x + a23*vb3x; sy2 = a12*vb1y + a22*vb2y + a23*vb3y; sz2 = a12*vb1z + a22*vb2z + a23*vb3z; f1[0] = a11*vb1x + a12*vb2x + a13*vb3x; f1[1] = a11*vb1y + a12*vb2y + a13*vb3y; f1[2] = a11*vb1z + a12*vb2z + a13*vb3z; f2[0] = -sx2 - f1[0]; f2[1] = -sy2 - f1[1]; f2[2] = -sz2 - f1[2]; f4[0] = a13*vb1x + a23*vb2x + a33*vb3x; f4[1] = a13*vb1y + a23*vb2y + a33*vb3y; f4[2] = a13*vb1z + a23*vb2z + a33*vb3z; f3[0] = sx2 - f4[0]; f3[1] = sy2 - f4[1]; f3[2] = sz2 - f4[2]; // apply force to each of 4 atoms if (newton_bond || i1 < nlocal) { f[i1][0] += f1[0]; f[i1][1] += f1[1]; f[i1][2] += f1[2]; } if (newton_bond || i2 < nlocal) { f[i2][0] += f2[0]; f[i2][1] += f2[1]; f[i2][2] += f2[2]; } if (newton_bond || i3 < nlocal) { f[i3][0] += f3[0]; f[i3][1] += f3[1]; f[i3][2] += f3[2]; } if (newton_bond || i4 < nlocal) { f[i4][0] += f4[0]; f[i4][1] += f4[1]; f[i4][2] += f4[2]; } if (evflag) ev_tally(i1,i2,i3,i4,nlocal,newton_bond,edihedral,f1,f3,f4, vb1x,vb1y,vb1z,vb2x,vb2y,vb2z,vb3x,vb3y,vb3z); } } /* ---------------------------------------------------------------------- */ void DihedralMultiHarmonic::allocate() { allocated = 1; int n = atom->ndihedraltypes; a1 = (double *) memory->smalloc((n+1)*sizeof(double),"dihedral:a1"); a2 = (double *) memory->smalloc((n+1)*sizeof(double),"dihedral:a2"); a3 = (double *) memory->smalloc((n+1)*sizeof(double),"dihedral:a3"); a4 = (double *) memory->smalloc((n+1)*sizeof(double),"dihedral:a4"); a5 = (double *) memory->smalloc((n+1)*sizeof(double),"dihedral:a5"); setflag = (int *) memory->smalloc((n+1)*sizeof(int),"dihedral:setflag"); for (int i = 1; i <= n; i++) setflag[i] = 0; } /* ---------------------------------------------------------------------- set coeffs for one type ------------------------------------------------------------------------- */ void DihedralMultiHarmonic::coeff(int narg, char **arg) { if (narg != 6) error->all("Incorrect args for dihedral coefficients"); if (!allocated) allocate(); int ilo,ihi; force->bounds(arg[0],atom->ndihedraltypes,ilo,ihi); double a1_one = force->numeric(arg[1]); double a2_one = force->numeric(arg[2]); double a3_one = force->numeric(arg[3]); double a4_one = force->numeric(arg[4]); double a5_one = force->numeric(arg[5]); int count = 0; for (int i = ilo; i <= ihi; i++) { a1[i] = a1_one; a2[i] = a2_one; a3[i] = a3_one; a4[i] = a4_one; a5[i] = a5_one; setflag[i] = 1; count++; } if (count == 0) error->all("Incorrect args for dihedral coefficients"); } /* ---------------------------------------------------------------------- proc 0 writes out coeffs to restart file ------------------------------------------------------------------------- */ void DihedralMultiHarmonic::write_restart(FILE *fp) { fwrite(&a1[1],sizeof(double),atom->ndihedraltypes,fp); fwrite(&a2[1],sizeof(double),atom->ndihedraltypes,fp); fwrite(&a3[1],sizeof(double),atom->ndihedraltypes,fp); fwrite(&a4[1],sizeof(double),atom->ndihedraltypes,fp); fwrite(&a5[1],sizeof(double),atom->ndihedraltypes,fp); } /* ---------------------------------------------------------------------- proc 0 reads coeffs from restart file, bcasts them ------------------------------------------------------------------------- */ void DihedralMultiHarmonic::read_restart(FILE *fp) { allocate(); if (comm->me == 0) { fread(&a1[1],sizeof(double),atom->ndihedraltypes,fp); fread(&a2[1],sizeof(double),atom->ndihedraltypes,fp); fread(&a3[1],sizeof(double),atom->ndihedraltypes,fp); fread(&a4[1],sizeof(double),atom->ndihedraltypes,fp); fread(&a5[1],sizeof(double),atom->ndihedraltypes,fp); } MPI_Bcast(&a1[1],atom->ndihedraltypes,MPI_DOUBLE,0,world); MPI_Bcast(&a2[1],atom->ndihedraltypes,MPI_DOUBLE,0,world); MPI_Bcast(&a3[1],atom->ndihedraltypes,MPI_DOUBLE,0,world); MPI_Bcast(&a4[1],atom->ndihedraltypes,MPI_DOUBLE,0,world); MPI_Bcast(&a5[1],atom->ndihedraltypes,MPI_DOUBLE,0,world); for (int i = 1; i <= atom->ndihedraltypes; i++) setflag[i] = 1; } diff --git a/src/MOLECULE/dihedral_opls.cpp b/src/MOLECULE/dihedral_opls.cpp index bb3579e1c..576f6ca4e 100644 --- a/src/MOLECULE/dihedral_opls.cpp +++ b/src/MOLECULE/dihedral_opls.cpp @@ -1,346 +1,349 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- Contributing author: Mark Stevens (SNL) ------------------------------------------------------------------------- */ #include "math.h" #include "stdlib.h" #include "dihedral_opls.h" +#include "lmptype.h" #include "atom.h" #include "comm.h" #include "neighbor.h" #include "domain.h" #include "force.h" #include "update.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; #define MIN(A,B) ((A) < (B)) ? (A) : (B) #define MAX(A,B) ((A) > (B)) ? (A) : (B) #define TOLERANCE 0.05 #define SMALL 0.001 #define SMALLER 0.00001 /* ---------------------------------------------------------------------- */ DihedralOPLS::DihedralOPLS(LAMMPS *lmp) : Dihedral(lmp) {} /* ---------------------------------------------------------------------- */ DihedralOPLS::~DihedralOPLS() { if (allocated) { memory->sfree(setflag); memory->sfree(k1); memory->sfree(k2); memory->sfree(k3); memory->sfree(k4); } } /* ---------------------------------------------------------------------- */ void DihedralOPLS::compute(int eflag, int vflag) { int i1,i2,i3,i4,n,type; double vb1x,vb1y,vb1z,vb2x,vb2y,vb2z,vb3x,vb3y,vb3z,vb2xm,vb2ym,vb2zm; double edihedral,f1[3],f2[3],f3[3],f4[3]; double sb1,sb2,sb3,rb1,rb3,c0,b1mag2,b1mag,b2mag2; double b2mag,b3mag2,b3mag,ctmp,r12c1,c1mag,r12c2; double c2mag,sc1,sc2,s1,s12,c,p,pd,a,a11,a22; double a33,a12,a13,a23,sx2,sy2,sz2; double s2,cx,cy,cz,cmag,dx,phi,si,siinv,sin2; edihedral = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = 0; double **x = atom->x; double **f = atom->f; int **dihedrallist = neighbor->dihedrallist; int ndihedrallist = neighbor->ndihedrallist; int nlocal = atom->nlocal; int newton_bond = force->newton_bond; for (n = 0; n < ndihedrallist; n++) { i1 = dihedrallist[n][0]; i2 = dihedrallist[n][1]; i3 = dihedrallist[n][2]; i4 = dihedrallist[n][3]; type = dihedrallist[n][4]; // 1st bond vb1x = x[i1][0] - x[i2][0]; vb1y = x[i1][1] - x[i2][1]; vb1z = x[i1][2] - x[i2][2]; domain->minimum_image(vb1x,vb1y,vb1z); // 2nd bond vb2x = x[i3][0] - x[i2][0]; vb2y = x[i3][1] - x[i2][1]; vb2z = x[i3][2] - x[i2][2]; domain->minimum_image(vb2x,vb2y,vb2z); vb2xm = -vb2x; vb2ym = -vb2y; vb2zm = -vb2z; domain->minimum_image(vb2xm,vb2ym,vb2zm); // 3rd bond vb3x = x[i4][0] - x[i3][0]; vb3y = x[i4][1] - x[i3][1]; vb3z = x[i4][2] - x[i3][2]; domain->minimum_image(vb3x,vb3y,vb3z); // c0 calculation sb1 = 1.0 / (vb1x*vb1x + vb1y*vb1y + vb1z*vb1z); sb2 = 1.0 / (vb2x*vb2x + vb2y*vb2y + vb2z*vb2z); sb3 = 1.0 / (vb3x*vb3x + vb3y*vb3y + vb3z*vb3z); rb1 = sqrt(sb1); rb3 = sqrt(sb3); c0 = (vb1x*vb3x + vb1y*vb3y + vb1z*vb3z) * rb1*rb3; // 1st and 2nd angle b1mag2 = vb1x*vb1x + vb1y*vb1y + vb1z*vb1z; b1mag = sqrt(b1mag2); b2mag2 = vb2x*vb2x + vb2y*vb2y + vb2z*vb2z; b2mag = sqrt(b2mag2); b3mag2 = vb3x*vb3x + vb3y*vb3y + vb3z*vb3z; b3mag = sqrt(b3mag2); ctmp = vb1x*vb2x + vb1y*vb2y + vb1z*vb2z; r12c1 = 1.0 / (b1mag*b2mag); c1mag = ctmp * r12c1; ctmp = vb2xm*vb3x + vb2ym*vb3y + vb2zm*vb3z; r12c2 = 1.0 / (b2mag*b3mag); c2mag = ctmp * r12c2; // cos and sin of 2 angles and final c sin2 = MAX(1.0 - c1mag*c1mag,0.0); sc1 = sqrt(sin2); if (sc1 < SMALL) sc1 = SMALL; sc1 = 1.0/sc1; sin2 = MAX(1.0 - c2mag*c2mag,0.0); sc2 = sqrt(sin2); if (sc2 < SMALL) sc2 = SMALL; sc2 = 1.0/sc2; s1 = sc1 * sc1; s2 = sc2 * sc2; s12 = sc1 * sc2; c = (c0 + c1mag*c2mag) * s12; cx = vb1y*vb2z - vb1z*vb2y; cy = vb1z*vb2x - vb1x*vb2z; cz = vb1x*vb2y - vb1y*vb2x; cmag = sqrt(cx*cx + cy*cy + cz*cz); dx = (cx*vb3x + cy*vb3y + cz*vb3z)/cmag/b3mag; // error check if (c > 1.0 + TOLERANCE || c < (-1.0 - TOLERANCE)) { + int me; + MPI_Comm_rank(world,&me); if (screen) { - char str[128]; - sprintf(str,"Dihedral problem: %d %d %d %d %d %d", - comm->me,update->ntimestep, + char str[128],fstr[64]; + sprintf(fstr,"Dihedral problem: %%d %s %%d %%d %%d %%d",BIGINT_FORMAT); + sprintf(str,fstr,me,update->ntimestep, atom->tag[i1],atom->tag[i2],atom->tag[i3],atom->tag[i4]); error->warning(str,0); fprintf(screen," 1st atom: %d %g %g %g\n", - comm->me,x[i1][0],x[i1][1],x[i1][2]); + me,x[i1][0],x[i1][1],x[i1][2]); fprintf(screen," 2nd atom: %d %g %g %g\n", - comm->me,x[i2][0],x[i2][1],x[i2][2]); + me,x[i2][0],x[i2][1],x[i2][2]); fprintf(screen," 3rd atom: %d %g %g %g\n", - comm->me,x[i3][0],x[i3][1],x[i3][2]); + me,x[i3][0],x[i3][1],x[i3][2]); fprintf(screen," 4th atom: %d %g %g %g\n", - comm->me,x[i4][0],x[i4][1],x[i4][2]); + me,x[i4][0],x[i4][1],x[i4][2]); } } if (c > 1.0) c = 1.0; if (c < -1.0) c = -1.0; // force & energy // p = sum (i=1,4) k_i * (1 + (-1)**(i+1)*cos(i*phi) ) // pd = dp/dc phi = acos(c); if (dx < 0.0) phi *= -1.0; si = sin(phi); if (fabs(si) < SMALLER) si = SMALLER; siinv = 1.0/si; p = k1[type]*(1.0 + c) + k2[type]*(1.0 - cos(2.0*phi)) + k3[type]*(1.0 + cos(3.0*phi)) + k4[type]*(1.0 - cos(4.0*phi)) ; pd = k1[type] - 2.0*k2[type]*sin(2.0*phi)*siinv + 3.0*k3[type]*sin(3.0*phi)*siinv - 4.0*k4[type]*sin(4.0*phi)*siinv; if (eflag) edihedral = p; a = pd; c = c * a; s12 = s12 * a; a11 = c*sb1*s1; a22 = -sb2 * (2.0*c0*s12 - c*(s1+s2)); a33 = c*sb3*s2; a12 = -r12c1 * (c1mag*c*s1 + c2mag*s12); a13 = -rb1*rb3*s12; a23 = r12c2 * (c2mag*c*s2 + c1mag*s12); sx2 = a12*vb1x + a22*vb2x + a23*vb3x; sy2 = a12*vb1y + a22*vb2y + a23*vb3y; sz2 = a12*vb1z + a22*vb2z + a23*vb3z; f1[0] = a11*vb1x + a12*vb2x + a13*vb3x; f1[1] = a11*vb1y + a12*vb2y + a13*vb3y; f1[2] = a11*vb1z + a12*vb2z + a13*vb3z; f2[0] = -sx2 - f1[0]; f2[1] = -sy2 - f1[1]; f2[2] = -sz2 - f1[2]; f4[0] = a13*vb1x + a23*vb2x + a33*vb3x; f4[1] = a13*vb1y + a23*vb2y + a33*vb3y; f4[2] = a13*vb1z + a23*vb2z + a33*vb3z; f3[0] = sx2 - f4[0]; f3[1] = sy2 - f4[1]; f3[2] = sz2 - f4[2]; // apply force to each of 4 atoms if (newton_bond || i1 < nlocal) { f[i1][0] += f1[0]; f[i1][1] += f1[1]; f[i1][2] += f1[2]; } if (newton_bond || i2 < nlocal) { f[i2][0] += f2[0]; f[i2][1] += f2[1]; f[i2][2] += f2[2]; } if (newton_bond || i3 < nlocal) { f[i3][0] += f3[0]; f[i3][1] += f3[1]; f[i3][2] += f3[2]; } if (newton_bond || i4 < nlocal) { f[i4][0] += f4[0]; f[i4][1] += f4[1]; f[i4][2] += f4[2]; } if (evflag) ev_tally(i1,i2,i3,i4,nlocal,newton_bond,edihedral,f1,f3,f4, vb1x,vb1y,vb1z,vb2x,vb2y,vb2z,vb3x,vb3y,vb3z); } } /* ---------------------------------------------------------------------- */ void DihedralOPLS::allocate() { allocated = 1; int n = atom->ndihedraltypes; k1 = (double *) memory->smalloc((n+1)*sizeof(double),"dihedral:k1"); k2 = (double *) memory->smalloc((n+1)*sizeof(double),"dihedral:k2"); k3 = (double *) memory->smalloc((n+1)*sizeof(double),"dihedral:k3"); k4 = (double *) memory->smalloc((n+1)*sizeof(double),"dihedral:k4"); setflag = (int *) memory->smalloc((n+1)*sizeof(int),"dihedral:setflag"); for (int i = 1; i <= n; i++) setflag[i] = 0; } /* ---------------------------------------------------------------------- set coeffs for one type ------------------------------------------------------------------------- */ void DihedralOPLS::coeff(int narg, char **arg) { if (narg != 5) error->all("Incorrect args for dihedral coefficients"); if (!allocated) allocate(); int ilo,ihi; force->bounds(arg[0],atom->ndihedraltypes,ilo,ihi); double k1_one = force->numeric(arg[1]); double k2_one = force->numeric(arg[2]); double k3_one = force->numeric(arg[3]); double k4_one = force->numeric(arg[4]); // store 1/2 factor with prefactor int count = 0; for (int i = ilo; i <= ihi; i++) { k1[i] = 0.5*k1_one; k2[i] = 0.5*k2_one; k3[i] = 0.5*k3_one; k4[i] = 0.5*k4_one; setflag[i] = 1; count++; } if (count == 0) error->all("Incorrect args for dihedral coefficients"); } /* ---------------------------------------------------------------------- proc 0 writes out coeffs to restart file ------------------------------------------------------------------------- */ void DihedralOPLS::write_restart(FILE *fp) { fwrite(&k1[1],sizeof(double),atom->ndihedraltypes,fp); fwrite(&k2[1],sizeof(double),atom->ndihedraltypes,fp); fwrite(&k3[1],sizeof(double),atom->ndihedraltypes,fp); fwrite(&k4[1],sizeof(double),atom->ndihedraltypes,fp); } /* ---------------------------------------------------------------------- proc 0 reads coeffs from restart file, bcasts them ------------------------------------------------------------------------- */ void DihedralOPLS::read_restart(FILE *fp) { allocate(); if (comm->me == 0) { fread(&k1[1],sizeof(double),atom->ndihedraltypes,fp); fread(&k2[1],sizeof(double),atom->ndihedraltypes,fp); fread(&k3[1],sizeof(double),atom->ndihedraltypes,fp); fread(&k4[1],sizeof(double),atom->ndihedraltypes,fp); } MPI_Bcast(&k1[1],atom->ndihedraltypes,MPI_DOUBLE,0,world); MPI_Bcast(&k2[1],atom->ndihedraltypes,MPI_DOUBLE,0,world); MPI_Bcast(&k3[1],atom->ndihedraltypes,MPI_DOUBLE,0,world); MPI_Bcast(&k4[1],atom->ndihedraltypes,MPI_DOUBLE,0,world); for (int i = 1; i <= atom->ndihedraltypes; i++) setflag[i] = 1; } diff --git a/src/MOLECULE/improper_cvff.cpp b/src/MOLECULE/improper_cvff.cpp index 6ce9e7fd5..a4a662449 100644 --- a/src/MOLECULE/improper_cvff.cpp +++ b/src/MOLECULE/improper_cvff.cpp @@ -1,348 +1,349 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ #include "mpi.h" #include "math.h" #include "stdlib.h" #include "improper_cvff.h" +#include "lmptype.h" #include "atom.h" #include "comm.h" #include "neighbor.h" #include "domain.h" #include "force.h" #include "update.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; #define TOLERANCE 0.05 #define SMALL 0.001 /* ---------------------------------------------------------------------- */ ImproperCvff::ImproperCvff(LAMMPS *lmp) : Improper(lmp) {} /* ---------------------------------------------------------------------- */ ImproperCvff::~ImproperCvff() { if (allocated) { memory->sfree(setflag); memory->sfree(k); memory->sfree(sign); memory->sfree(multiplicity); } } /* ---------------------------------------------------------------------- */ void ImproperCvff::compute(int eflag, int vflag) { int i1,i2,i3,i4,m,n,type; double vb1x,vb1y,vb1z,vb2x,vb2y,vb2z,vb3x,vb3y,vb3z,vb2xm,vb2ym,vb2zm; double eimproper,f1[3],f2[3],f3[3],f4[3]; double sb1,sb2,sb3,rb1,rb3,c0,b1mag2,b1mag,b2mag2; double b2mag,b3mag2,b3mag,ctmp,r12c1,c1mag,r12c2; double c2mag,sc1,sc2,s1,s2,s12,c,p,pd,rc2,a,a11,a22; double a33,a12,a13,a23,sx2,sy2,sz2; eimproper = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = 0; double **x = atom->x; double **f = atom->f; int **improperlist = neighbor->improperlist; int nimproperlist = neighbor->nimproperlist; int nlocal = atom->nlocal; int newton_bond = force->newton_bond; for (n = 0; n < nimproperlist; n++) { i1 = improperlist[n][0]; i2 = improperlist[n][1]; i3 = improperlist[n][2]; i4 = improperlist[n][3]; type = improperlist[n][4]; // 1st bond vb1x = x[i1][0] - x[i2][0]; vb1y = x[i1][1] - x[i2][1]; vb1z = x[i1][2] - x[i2][2]; domain->minimum_image(vb1x,vb1y,vb1z); // 2nd bond vb2x = x[i3][0] - x[i2][0]; vb2y = x[i3][1] - x[i2][1]; vb2z = x[i3][2] - x[i2][2]; domain->minimum_image(vb2x,vb2y,vb2z); vb2xm = -vb2x; vb2ym = -vb2y; vb2zm = -vb2z; domain->minimum_image(vb2xm,vb2ym,vb2zm); // 3rd bond vb3x = x[i4][0] - x[i3][0]; vb3y = x[i4][1] - x[i3][1]; vb3z = x[i4][2] - x[i3][2]; domain->minimum_image(vb3x,vb3y,vb3z); // c0 calculation sb1 = 1.0 / (vb1x*vb1x + vb1y*vb1y + vb1z*vb1z); sb2 = 1.0 / (vb2x*vb2x + vb2y*vb2y + vb2z*vb2z); sb3 = 1.0 / (vb3x*vb3x + vb3y*vb3y + vb3z*vb3z); rb1 = sqrt(sb1); rb3 = sqrt(sb3); c0 = (vb1x*vb3x + vb1y*vb3y + vb1z*vb3z) * rb1*rb3; // 1st and 2nd angle b1mag2 = vb1x*vb1x + vb1y*vb1y + vb1z*vb1z; b1mag = sqrt(b1mag2); b2mag2 = vb2x*vb2x + vb2y*vb2y + vb2z*vb2z; b2mag = sqrt(b2mag2); b3mag2 = vb3x*vb3x + vb3y*vb3y + vb3z*vb3z; b3mag = sqrt(b3mag2); ctmp = vb1x*vb2x + vb1y*vb2y + vb1z*vb2z; r12c1 = 1.0 / (b1mag*b2mag); c1mag = ctmp * r12c1; ctmp = vb2xm*vb3x + vb2ym*vb3y + vb2zm*vb3z; r12c2 = 1.0 / (b2mag*b3mag); c2mag = ctmp * r12c2; // cos and sin of 2 angles and final c sc1 = sqrt(1.0 - c1mag*c1mag); if (sc1 < SMALL) sc1 = SMALL; sc1 = 1.0/sc1; sc2 = sqrt(1.0 - c2mag*c2mag); if (sc2 < SMALL) sc2 = SMALL; sc2 = 1.0/sc2; s1 = sc1 * sc1; s2 = sc2 * sc2; s12 = sc1 * sc2; c = (c0 + c1mag*c2mag) * s12; // error check if (c > 1.0 + TOLERANCE || c < (-1.0 - TOLERANCE)) { int me; MPI_Comm_rank(world,&me); if (screen) { - char str[128]; - sprintf(str,"Improper problem: %d %d %d %d %d %d", - me,update->ntimestep, + char str[128],fstr[64]; + sprintf(fstr,"Improper problem: %%d %s %%d %%d %%d %%d",BIGINT_FORMAT); + sprintf(str,fstr,me,update->ntimestep, atom->tag[i1],atom->tag[i2],atom->tag[i3],atom->tag[i4]); error->warning(str,0); fprintf(screen," 1st atom: %d %g %g %g\n", me,x[i1][0],x[i1][1],x[i1][2]); fprintf(screen," 2nd atom: %d %g %g %g\n", me,x[i2][0],x[i2][1],x[i2][2]); fprintf(screen," 3rd atom: %d %g %g %g\n", me,x[i3][0],x[i3][1],x[i3][2]); fprintf(screen," 4th atom: %d %g %g %g\n", me,x[i4][0],x[i4][1],x[i4][2]); } } if (c > 1.0) c = 1.0; if (c < -1.0) c = -1.0; // force & energy // p = 1 + cos(n*phi) for d = 1 // p = 1 - cos(n*phi) for d = -1 // pd = dp/dc / 2 m = multiplicity[type]; if (m == 2) { p = 2.0*c*c; pd = 2.0*c; } else if (m == 3) { rc2 = c*c; p = (4.0*rc2-3.0)*c + 1.0; pd = 6.0*rc2 - 1.5; } else if (m == 4) { rc2 = c*c; p = 8.0*(rc2-1)*rc2 + 2.0; pd = (16.0*rc2-8.0)*c; } else if (m == 6) { rc2 = c*c; p = ((32.0*rc2-48.0)*rc2 + 18.0)*rc2; pd = (96.0*(rc2-1.0)*rc2 + 18.0)*c; } else if (m == 1) { p = c + 1.0; pd = 0.5; } else if (m == 5) { rc2 = c*c; p = ((16.0*rc2-20.0)*rc2 + 5.0)*c + 1.0; pd = (40.0*rc2-30.0)*rc2 + 2.5; } else if (m == 0) { p = 2.0; pd = 0.0; } if (sign[type] == -1) { p = 2.0 - p; pd = -pd; } if (eflag) eimproper = k[type]*p; a = 2.0 * k[type] * pd; c = c * a; s12 = s12 * a; a11 = c*sb1*s1; a22 = -sb2*(2.0*c0*s12 - c*(s1+s2)); a33 = c*sb3*s2; a12 = -r12c1*(c1mag*c*s1 + c2mag*s12); a13 = -rb1*rb3*s12; a23 = r12c2*(c2mag*c*s2 + c1mag*s12); sx2 = a12*vb1x + a22*vb2x + a23*vb3x; sy2 = a12*vb1y + a22*vb2y + a23*vb3y; sz2 = a12*vb1z + a22*vb2z + a23*vb3z; f1[0] = a11*vb1x + a12*vb2x + a13*vb3x; f1[1] = a11*vb1y + a12*vb2y + a13*vb3y; f1[2] = a11*vb1z + a12*vb2z + a13*vb3z; f2[0] = -sx2 - f1[0]; f2[1] = -sy2 - f1[1]; f2[2] = -sz2 - f1[2]; f4[0] = a13*vb1x + a23*vb2x + a33*vb3x; f4[1] = a13*vb1y + a23*vb2y + a33*vb3y; f4[2] = a13*vb1z + a23*vb2z + a33*vb3z; f3[0] = sx2 - f4[0]; f3[1] = sy2 - f4[1]; f3[2] = sz2 - f4[2]; // apply force to each of 4 atoms if (newton_bond || i1 < nlocal) { f[i1][0] += f1[0]; f[i1][1] += f1[1]; f[i1][2] += f1[2]; } if (newton_bond || i2 < nlocal) { f[i2][0] += f2[0]; f[i2][1] += f2[1]; f[i2][2] += f2[2]; } if (newton_bond || i3 < nlocal) { f[i3][0] += f3[0]; f[i3][1] += f3[1]; f[i3][2] += f3[2]; } if (newton_bond || i4 < nlocal) { f[i4][0] += f4[0]; f[i4][1] += f4[1]; f[i4][2] += f4[2]; } if (evflag) ev_tally(i1,i2,i3,i4,nlocal,newton_bond,eimproper,f1,f3,f4, vb1x,vb1y,vb1z,vb2x,vb2y,vb2z,vb3x,vb3y,vb3z); } } /* ---------------------------------------------------------------------- */ void ImproperCvff::allocate() { allocated = 1; int n = atom->nimpropertypes; k = (double *) memory->smalloc((n+1)*sizeof(double),"improper:k"); sign = (int *) memory->smalloc((n+1)*sizeof(int),"improper:sign"); multiplicity = (int *) memory->smalloc((n+1)*sizeof(int),"improper:multiplicity"); setflag = (int *) memory->smalloc((n+1)*sizeof(int),"improper:setflag"); for (int i = 1; i <= n; i++) setflag[i] = 0; } /* ---------------------------------------------------------------------- set coeffs for one type ------------------------------------------------------------------------- */ void ImproperCvff::coeff(int narg, char **arg) { if (narg != 4) error->all("Incorrect args for improper coefficients"); if (!allocated) allocate(); int ilo,ihi; force->bounds(arg[0],atom->nimpropertypes,ilo,ihi); double k_one = force->numeric(arg[1]); int sign_one = force->inumeric(arg[2]); int multiplicity_one = force->inumeric(arg[3]); int count = 0; for (int i = ilo; i <= ihi; i++) { k[i] = k_one; sign[i] = sign_one; multiplicity[i] = multiplicity_one; setflag[i] = 1; count++; } if (count == 0) error->all("Incorrect args for improper coefficients"); } /* ---------------------------------------------------------------------- proc 0 writes out coeffs to restart file ------------------------------------------------------------------------- */ void ImproperCvff::write_restart(FILE *fp) { fwrite(&k[1],sizeof(double),atom->nimpropertypes,fp); fwrite(&sign[1],sizeof(int),atom->nimpropertypes,fp); fwrite(&multiplicity[1],sizeof(int),atom->nimpropertypes,fp); } /* ---------------------------------------------------------------------- proc 0 reads coeffs from restart file, bcasts them ------------------------------------------------------------------------- */ void ImproperCvff::read_restart(FILE *fp) { allocate(); if (comm->me == 0) { fread(&k[1],sizeof(double),atom->nimpropertypes,fp); fread(&sign[1],sizeof(int),atom->nimpropertypes,fp); fread(&multiplicity[1],sizeof(int),atom->nimpropertypes,fp); } MPI_Bcast(&k[1],atom->nimpropertypes,MPI_DOUBLE,0,world); MPI_Bcast(&sign[1],atom->nimpropertypes,MPI_INT,0,world); MPI_Bcast(&multiplicity[1],atom->nimpropertypes,MPI_INT,0,world); for (int i = 1; i <= atom->nimpropertypes; i++) setflag[i] = 1; } diff --git a/src/MOLECULE/improper_harmonic.cpp b/src/MOLECULE/improper_harmonic.cpp index 4487b9e7a..0174ce3c9 100644 --- a/src/MOLECULE/improper_harmonic.cpp +++ b/src/MOLECULE/improper_harmonic.cpp @@ -1,283 +1,284 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ #include "mpi.h" #include "math.h" #include "stdlib.h" #include "improper_harmonic.h" +#include "lmptype.h" #include "atom.h" #include "comm.h" #include "neighbor.h" #include "domain.h" #include "force.h" #include "update.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; #define TOLERANCE 0.05 #define SMALL 0.001 /* ---------------------------------------------------------------------- */ ImproperHarmonic::ImproperHarmonic(LAMMPS *lmp) : Improper(lmp) {} /* ---------------------------------------------------------------------- */ ImproperHarmonic::~ImproperHarmonic() { if (allocated) { memory->sfree(setflag); memory->sfree(k); memory->sfree(chi); } } /* ---------------------------------------------------------------------- */ void ImproperHarmonic::compute(int eflag, int vflag) { int i1,i2,i3,i4,n,type; double vb1x,vb1y,vb1z,vb2x,vb2y,vb2z,vb3x,vb3y,vb3z; double eimproper,f1[3],f2[3],f3[3],f4[3]; double ss1,ss2,ss3,r1,r2,r3,c0,c1,c2,s1,s2; double s12,c,s,domega,a,a11,a22,a33,a12,a13,a23; double sx2,sy2,sz2; eimproper = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = 0; double **x = atom->x; double **f = atom->f; int **improperlist = neighbor->improperlist; int nimproperlist = neighbor->nimproperlist; int nlocal = atom->nlocal; int newton_bond = force->newton_bond; for (n = 0; n < nimproperlist; n++) { i1 = improperlist[n][0]; i2 = improperlist[n][1]; i3 = improperlist[n][2]; i4 = improperlist[n][3]; type = improperlist[n][4]; // geometry of 4-body vb1x = x[i1][0] - x[i2][0]; vb1y = x[i1][1] - x[i2][1]; vb1z = x[i1][2] - x[i2][2]; domain->minimum_image(vb1x,vb1y,vb1z); vb2x = x[i3][0] - x[i2][0]; vb2y = x[i3][1] - x[i2][1]; vb2z = x[i3][2] - x[i2][2]; domain->minimum_image(vb2x,vb2y,vb2z); vb3x = x[i4][0] - x[i3][0]; vb3y = x[i4][1] - x[i3][1]; vb3z = x[i4][2] - x[i3][2]; domain->minimum_image(vb3x,vb3y,vb3z); ss1 = 1.0 / (vb1x*vb1x + vb1y*vb1y + vb1z*vb1z); ss2 = 1.0 / (vb2x*vb2x + vb2y*vb2y + vb2z*vb2z); ss3 = 1.0 / (vb3x*vb3x + vb3y*vb3y + vb3z*vb3z); r1 = sqrt(ss1); r2 = sqrt(ss2); r3 = sqrt(ss3); // sin and cos of angle c0 = (vb1x * vb3x + vb1y * vb3y + vb1z * vb3z) * r1 * r3; c1 = (vb1x * vb2x + vb1y * vb2y + vb1z * vb2z) * r1 * r2; c2 = -(vb3x * vb2x + vb3y * vb2y + vb3z * vb2z) * r3 * r2; s1 = 1.0 - c1*c1; if (s1 < SMALL) s1 = SMALL; s1 = 1.0 / s1; s2 = 1.0 - c2*c2; if (s2 < SMALL) s2 = SMALL; s2 = 1.0 / s2; s12 = sqrt(s1*s2); c = (c1*c2 + c0) * s12; // error check if (c > 1.0 + TOLERANCE || c < (-1.0 - TOLERANCE)) { int me; MPI_Comm_rank(world,&me); if (screen) { - char str[128]; - sprintf(str,"Improper problem: %d %d %d %d %d %d", - me,update->ntimestep, + char str[128],fstr[64]; + sprintf(fstr,"Improper problem: %%d %s %%d %%d %%d %%d",BIGINT_FORMAT); + sprintf(str,fstr,me,update->ntimestep, atom->tag[i1],atom->tag[i2],atom->tag[i3],atom->tag[i4]); error->warning(str,0); fprintf(screen," 1st atom: %d %g %g %g\n", me,x[i1][0],x[i1][1],x[i1][2]); fprintf(screen," 2nd atom: %d %g %g %g\n", me,x[i2][0],x[i2][1],x[i2][2]); fprintf(screen," 3rd atom: %d %g %g %g\n", me,x[i3][0],x[i3][1],x[i3][2]); fprintf(screen," 4th atom: %d %g %g %g\n", me,x[i4][0],x[i4][1],x[i4][2]); } } if (c > 1.0) c = 1.0; if (c < -1.0) c = -1.0; s = sqrt(1.0 - c*c); if (s < SMALL) s = SMALL; // force & energy domega = acos(c) - chi[type]; a = k[type] * domega; if (eflag) eimproper = a*domega; a = -a * 2.0/s; c = c * a; s12 = s12 * a; a11 = c*ss1*s1; a22 = -ss2 * (2.0*c0*s12 - c*(s1+s2)); a33 = c*ss3*s2; a12 = -r1*r2*(c1*c*s1 + c2*s12); a13 = -r1*r3*s12; a23 = r2*r3*(c2*c*s2 + c1*s12); sx2 = a22*vb2x + a23*vb3x + a12*vb1x; sy2 = a22*vb2y + a23*vb3y + a12*vb1y; sz2 = a22*vb2z + a23*vb3z + a12*vb1z; f1[0] = a12*vb2x + a13*vb3x + a11*vb1x; f1[1] = a12*vb2y + a13*vb3y + a11*vb1y; f1[2] = a12*vb2z + a13*vb3z + a11*vb1z; f2[0] = -sx2 - f1[0]; f2[1] = -sy2 - f1[1]; f2[2] = -sz2 - f1[2]; f4[0] = a23*vb2x + a33*vb3x + a13*vb1x; f4[1] = a23*vb2y + a33*vb3y + a13*vb1y; f4[2] = a23*vb2z + a33*vb3z + a13*vb1z; f3[0] = sx2 - f4[0]; f3[1] = sy2 - f4[1]; f3[2] = sz2 - f4[2]; // apply force to each of 4 atoms if (newton_bond || i1 < nlocal) { f[i1][0] += f1[0]; f[i1][1] += f1[1]; f[i1][2] += f1[2]; } if (newton_bond || i2 < nlocal) { f[i2][0] += f2[0]; f[i2][1] += f2[1]; f[i2][2] += f2[2]; } if (newton_bond || i3 < nlocal) { f[i3][0] += f3[0]; f[i3][1] += f3[1]; f[i3][2] += f3[2]; } if (newton_bond || i4 < nlocal) { f[i4][0] += f4[0]; f[i4][1] += f4[1]; f[i4][2] += f4[2]; } if (evflag) ev_tally(i1,i2,i3,i4,nlocal,newton_bond,eimproper,f1,f3,f4, vb1x,vb1y,vb1z,vb2x,vb2y,vb2z,vb3x,vb3y,vb3z); } } /* ---------------------------------------------------------------------- */ void ImproperHarmonic::allocate() { allocated = 1; int n = atom->nimpropertypes; k = (double *) memory->smalloc((n+1)*sizeof(double),"improper:k"); chi = (double *) memory->smalloc((n+1)*sizeof(double),"improper:chi"); setflag = (int *) memory->smalloc((n+1)*sizeof(int),"improper:setflag"); for (int i = 1; i <= n; i++) setflag[i] = 0; } /* ---------------------------------------------------------------------- set coeffs for one type ------------------------------------------------------------------------- */ void ImproperHarmonic::coeff(int narg, char **arg) { if (narg != 3) error->all("Incorrect args for improper coefficients"); if (!allocated) allocate(); int ilo,ihi; force->bounds(arg[0],atom->nimpropertypes,ilo,ihi); double k_one = force->numeric(arg[1]); double chi_one = force->numeric(arg[2]); // convert chi from degrees to radians int count = 0; for (int i = ilo; i <= ihi; i++) { k[i] = k_one; chi[i] = chi_one/180.0 * PI; setflag[i] = 1; count++; } if (count == 0) error->all("Incorrect args for improper coefficients"); } /* ---------------------------------------------------------------------- proc 0 writes out coeffs to restart file ------------------------------------------------------------------------- */ void ImproperHarmonic::write_restart(FILE *fp) { fwrite(&k[1],sizeof(double),atom->nimpropertypes,fp); fwrite(&chi[1],sizeof(double),atom->nimpropertypes,fp); } /* ---------------------------------------------------------------------- proc 0 reads coeffs from restart file, bcasts them ------------------------------------------------------------------------- */ void ImproperHarmonic::read_restart(FILE *fp) { allocate(); if (comm->me == 0) { fread(&k[1],sizeof(double),atom->nimpropertypes,fp); fread(&chi[1],sizeof(double),atom->nimpropertypes,fp); } MPI_Bcast(&k[1],atom->nimpropertypes,MPI_DOUBLE,0,world); MPI_Bcast(&chi[1],atom->nimpropertypes,MPI_DOUBLE,0,world); for (int i = 1; i <= atom->nimpropertypes; i++) setflag[i] = 1; } diff --git a/src/MOLECULE/improper_umbrella.cpp b/src/MOLECULE/improper_umbrella.cpp index 9d2cc9cba..3fc2aad60 100644 --- a/src/MOLECULE/improper_umbrella.cpp +++ b/src/MOLECULE/improper_umbrella.cpp @@ -1,308 +1,310 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- Contributing author: Tod A Pascal (Caltech) ------------------------------------------------------------------------- */ #include "mpi.h" #include "math.h" #include "stdlib.h" #include "improper_umbrella.h" #include "atom.h" #include "comm.h" #include "neighbor.h" #include "domain.h" #include "force.h" #include "update.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; #define TOLERANCE 0.05 #define SMALL 0.001 /* ---------------------------------------------------------------------- */ ImproperUmbrella::ImproperUmbrella(LAMMPS *lmp) : Improper(lmp) {} /* ---------------------------------------------------------------------- */ ImproperUmbrella::~ImproperUmbrella() { if (allocated) { memory->sfree(setflag); memory->sfree(kw); memory->sfree(w0); memory->sfree(C); } } /* ---------------------------------------------------------------------- */ void ImproperUmbrella::compute(int eflag, int vflag) { int i1,i2,i3,i4,n,type; double eimproper,f1[3],f2[3],f3[3],f4[3]; double vb1x,vb1y,vb1z,vb2x,vb2y,vb2z,vb3x,vb3y,vb3z; double domega,c,a,s,projhfg,dhax,dhay,dhaz,dahx,dahy,dahz,cotphi; double ax,ay,az,ra2,rh2,ra,rh,rar,rhr,arx,ary,arz,hrx,hry,hrz; eimproper = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = 0; double **x = atom->x; double **f = atom->f; int **improperlist = neighbor->improperlist; int nimproperlist = neighbor->nimproperlist; int nlocal = atom->nlocal; int newton_bond = force->newton_bond; for (n = 0; n < nimproperlist; n++) { i1 = improperlist[n][0]; i2 = improperlist[n][1]; i3 = improperlist[n][2]; i4 = improperlist[n][3]; type = improperlist[n][4]; // 1st bond vb1x = x[i2][0] - x[i1][0]; vb1y = x[i2][1] - x[i1][1]; vb1z = x[i2][2] - x[i1][2]; domain->minimum_image(vb1x,vb1y,vb1z); // 2nd bond vb2x = x[i3][0] - x[i1][0]; vb2y = x[i3][1] - x[i1][1]; vb2z = x[i3][2] - x[i1][2]; domain->minimum_image(vb2x,vb2y,vb2z); // 3rd bond vb3x = x[i4][0] - x[i1][0]; vb3y = x[i4][1] - x[i1][1]; vb3z = x[i4][2] - x[i1][2]; domain->minimum_image(vb3x,vb3y,vb3z); // c0 calculation // A = vb1 X vb2 is perpendicular to IJK plane ax = vb1y*vb2z-vb1z*vb2y; ay = vb1z*vb2x-vb1x*vb2z; az = vb1x*vb2y-vb1y*vb2x; ra2 = ax*ax+ay*ay+az*az; rh2 = vb3x*vb3x+vb3y*vb3y+vb3z*vb3z; ra = sqrt(ra2); rh = sqrt(rh2); if (ra < SMALL) ra = SMALL; if (rh < SMALL) rh = SMALL; rar = 1/ra; rhr = 1/rh; arx = ax*rar; ary = ay*rar; arz = az*rar; hrx = vb3x*rhr; hry = vb3y*rhr; hrz = vb3z*rhr; c = arx*hrx+ary*hry+arz*hrz; // error check if (c > 1.0 + TOLERANCE || c < (-1.0 - TOLERANCE)) { int me; MPI_Comm_rank(world,&me); if (screen) { - fprintf(screen,"Improper problem: %d %d %d %d %d %d\n", - me,update->ntimestep, + char str[128],fstr[64]; + sprintf(fstr,"Improper problem: %%d %s %%d %%d %%d %%d",BIGINT_FORMAT); + sprintf(str,fstr,me,update->ntimestep, atom->tag[i1],atom->tag[i2],atom->tag[i3],atom->tag[i4]); + error->warning(str,0); fprintf(screen," 1st atom: %d %g %g %g\n", me,x[i1][0],x[i1][1],x[i1][2]); fprintf(screen," 2nd atom: %d %g %g %g\n", me,x[i2][0],x[i2][1],x[i2][2]); fprintf(screen," 3rd atom: %d %g %g %g\n", me,x[i3][0],x[i3][1],x[i3][2]); fprintf(screen," 4th atom: %d %g %g %g\n", me,x[i4][0],x[i4][1],x[i4][2]); } } if (c > 1.0) s = 1.0; if (c < -1.0) s = -1.0; s = sqrt(1.0 - c*c); if (s < SMALL) s = SMALL; cotphi = c/s; projhfg = (vb3x*vb1x+vb3y*vb1y+vb3z*vb1z) / sqrt(vb1x*vb1x+vb1y*vb1y+vb1z*vb1z); projhfg += (vb3x*vb2x+vb3y*vb2y+vb3z*vb2z) / sqrt(vb2x*vb2x+vb2y*vb2y+vb2z*vb2z); if (projhfg > 0.0) { s *= -1.0; cotphi *= -1.0; } // force and energy // if w0 = 0: E = k * (1 - cos w) // if w0 != 0: E = 0.5 * C (cos w - cos w0)^2, C = k/(sin(w0)^2 if (w0[type] == 0.0) { if (eflag) eimproper = kw[type] * (1.0-s); a = -kw[type]; } else { domega = s - cos(w0[type]); a = 0.5 * C[type] * domega; if (eflag) eimproper = a * domega; a *= 2.0; } // dhax = diffrence between H and A in X direction, etc a = a*cotphi; dhax = hrx-c*arx; dhay = hry-c*ary; dhaz = hrz-c*arz; dahx = arx-c*hrx; dahy = ary-c*hry; dahz = arz-c*hrz; f2[0] = (dhay*vb1z - dhaz*vb1y)*rar; f2[1] = (dhaz*vb1x - dhax*vb1z)*rar; f2[2] = (dhax*vb1y - dhay*vb1x)*rar; f3[0] = (-dhay*vb2z + dhaz*vb2y)*rar; f3[1] = (-dhaz*vb2x + dhax*vb2z)*rar; f3[2] = (-dhax*vb2y + dhay*vb2x)*rar; f4[0] = dahx*rhr; f4[1] = dahy*rhr; f4[2] = dahz*rhr; f1[0] = -(f2[0] + f3[0] + f4[0]); f1[1] = -(f2[1] + f3[1] + f4[1]); f1[2] = -(f2[2] + f3[2] + f4[2]); // apply force to each of 4 atoms if (newton_bond || i1 < nlocal) { f[i1][0] += f1[0]*a; f[i1][1] += f1[1]*a; f[i1][2] += f1[2]*a; } if (newton_bond || i2 < nlocal) { f[i2][0] += f3[0]*a; f[i2][1] += f3[1]*a; f[i2][2] += f3[2]*a; } if (newton_bond || i3 < nlocal) { f[i3][0] += f2[0]*a; f[i3][1] += f2[1]*a; f[i3][2] += f2[2]*a; } if (newton_bond || i4 < nlocal) { f[i4][0] += f4[0]*a; f[i4][1] += f4[1]*a; f[i4][2] += f4[2]*a; } if (evflag) ev_tally(i1,i2,i3,i4,nlocal,newton_bond,eimproper,f1,f3,f4, vb1x,vb1y,vb1z,vb2x,vb2y,vb2z,vb3x,vb3y,vb3z); } } /* ---------------------------------------------------------------------- */ void ImproperUmbrella::allocate() { allocated = 1; int n = atom->nimpropertypes; kw = (double *) memory->smalloc((n+1)*sizeof(double),"improper:kw"); w0 = (double *) memory->smalloc((n+1)*sizeof(double),"improper:w0"); C = (double *) memory->smalloc((n+1)*sizeof(double),"improper:C"); setflag = (int *) memory->smalloc((n+1)*sizeof(int),"improper:setflag"); for (int i = 1; i <= n; i++) setflag[i] = 0; } /* ---------------------------------------------------------------------- set coeffs for one type ------------------------------------------------------------------------- */ void ImproperUmbrella::coeff(int narg, char **arg) { if (narg != 3) error->all("Incorrect args for improper coefficients"); if (!allocated) allocate(); int ilo,ihi; force->bounds(arg[0],atom->nimpropertypes,ilo,ihi); double k_one = atof(arg[1]); double w_one = atof(arg[2]); // convert w0 from degrees to radians int count = 0; for (int i = ilo; i <= ihi; i++) { kw[i] = k_one; w0[i] = w_one/180.0 * PI; if (w_one == 0) C[i] = 1.0; else C[i] = kw[i]/(pow(sin(w0[i]),2)); setflag[i] = 1; count++; } if (count == 0) error->all("Incorrect args for improper coefficients"); } /* ---------------------------------------------------------------------- proc 0 writes out coeffs to restart file ------------------------------------------------------------------------- */ void ImproperUmbrella::write_restart(FILE *fp) { fwrite(&kw[1],sizeof(double),atom->nimpropertypes,fp); fwrite(&w0[1],sizeof(double),atom->nimpropertypes,fp); fwrite(&C[1],sizeof(double),atom->nimpropertypes,fp); } /* ---------------------------------------------------------------------- proc 0 reads coeffs from restart file, bcasts them ------------------------------------------------------------------------- */ void ImproperUmbrella::read_restart(FILE *fp) { allocate(); if (comm->me == 0) { fread(&kw[1],sizeof(double),atom->nimpropertypes,fp); fread(&w0[1],sizeof(double),atom->nimpropertypes,fp); fread(&C[1],sizeof(double),atom->nimpropertypes,fp); } MPI_Bcast(&kw[1],atom->nimpropertypes,MPI_DOUBLE,0,world); MPI_Bcast(&w0[1],atom->nimpropertypes,MPI_DOUBLE,0,world); MPI_Bcast(&C[1],atom->nimpropertypes,MPI_DOUBLE,0,world); for (int i = 1; i <= atom->nimpropertypes; i++) setflag[i] = 1; } diff --git a/src/PERI/atom_vec_peri.cpp b/src/PERI/atom_vec_peri.cpp index 4e43d7a6b..d20809e6b 100644 --- a/src/PERI/atom_vec_peri.cpp +++ b/src/PERI/atom_vec_peri.cpp @@ -1,774 +1,777 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- Contributing author: Mike Parks (SNL) ------------------------------------------------------------------------- */ #include "float.h" #include "stdlib.h" #include "atom_vec_peri.h" +#include "lmptype.h" #include "atom.h" #include "domain.h" #include "modify.h" #include "fix.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; #define DELTA 10000 /* ---------------------------------------------------------------------- */ AtomVecPeri::AtomVecPeri(LAMMPS *lmp, int narg, char **arg) : AtomVec(lmp, narg, arg) { molecular = 0; comm_x_only = 0; comm_f_only = 1; size_forward = 4; size_reverse = 3; size_border = 11; size_velocity = 3; size_data_atom = 7; size_data_vel = 4; xcol_data = 5; atom->vfrac_flag = atom->density_flag = atom->rmass_flag = 1; } /* ---------------------------------------------------------------------- grow atom arrays n = 0 grows arrays by DELTA n > 0 allocates arrays to size n ------------------------------------------------------------------------- */ void AtomVecPeri::grow(int n) { if (n == 0) nmax += DELTA; else nmax = n; atom->nmax = nmax; - + if (nmax < 0 || nmax > MAXSMALLINT) + error->one("Per-processor system is too big"); + tag = atom->tag = (int *) memory->srealloc(atom->tag,nmax*sizeof(int),"atom:tag"); type = atom->type = (int *) memory->srealloc(atom->type,nmax*sizeof(int),"atom:type"); mask = atom->mask = (int *) memory->srealloc(atom->mask,nmax*sizeof(int),"atom:mask"); image = atom->image = (int *) memory->srealloc(atom->image,nmax*sizeof(int),"atom:image"); x = atom->x = memory->grow_2d_double_array(atom->x,nmax,3,"atom:x"); v = atom->v = memory->grow_2d_double_array(atom->v,nmax,3,"atom:v"); f = atom->f = memory->grow_2d_double_array(atom->f,nmax,3,"atom:f"); vfrac = atom->vfrac = (double *) memory->srealloc(atom->vfrac,nmax*sizeof(double),"atom:vfrac"); density = atom->density = (double *) memory->srealloc(atom->density,nmax*sizeof(double),"atom:density"); rmass = atom->rmass = (double *) memory->srealloc(atom->rmass,nmax*sizeof(double),"atom:rmass"); s0 = atom->s0 = (double *) memory->srealloc(atom->s0,nmax*sizeof(double),"atom:s0"); x0 = atom->x0 = memory->grow_2d_double_array(atom->x0,nmax,3,"atom:x0"); if (atom->nextra_grow) for (int iextra = 0; iextra < atom->nextra_grow; iextra++) modify->fix[atom->extra_grow[iextra]]->grow_arrays(nmax); } /* ---------------------------------------------------------------------- reset local array ptrs ------------------------------------------------------------------------- */ void AtomVecPeri::grow_reset() { tag = atom->tag; type = atom->type; mask = atom->mask; image = atom->image; x = atom->x; v = atom->v; f = atom->f; vfrac = atom->vfrac; density = atom->density; rmass = atom->rmass; s0 = atom->s0; x0 = atom->x0; } /* ---------------------------------------------------------------------- */ void AtomVecPeri::copy(int i, int j) { tag[j] = tag[i]; type[j] = type[i]; mask[j] = mask[i]; image[j] = image[i]; x[j][0] = x[i][0]; x[j][1] = x[i][1]; x[j][2] = x[i][2]; v[j][0] = v[i][0]; v[j][1] = v[i][1]; v[j][2] = v[i][2]; vfrac[j] = vfrac[i]; density[j] = density[i]; rmass[j] = rmass[i]; s0[j] = s0[i]; x0[j][0] = x0[i][0]; x0[j][1] = x0[i][1]; x0[j][2] = x0[i][2]; if (atom->nextra_grow) for (int iextra = 0; iextra < atom->nextra_grow; iextra++) modify->fix[atom->extra_grow[iextra]]->copy_arrays(i,j); } /* ---------------------------------------------------------------------- */ int AtomVecPeri::pack_comm(int n, int *list, double *buf, int pbc_flag, int *pbc) { int i,j,m; double dx,dy,dz; m = 0; if (pbc_flag == 0) { for (i = 0; i < n; i++) { j = list[i]; buf[m++] = x[j][0]; buf[m++] = x[j][1]; buf[m++] = x[j][2]; buf[m++] = s0[j]; } } else { if (domain->triclinic == 0) { dx = pbc[0]*domain->xprd; dy = pbc[1]*domain->yprd; dz = pbc[2]*domain->zprd; } else { dx = pbc[0]*domain->xprd + pbc[5]*domain->xy + pbc[4]*domain->xz; dy = pbc[1]*domain->yprd + pbc[3]*domain->yz; dz = pbc[2]*domain->zprd; } for (i = 0; i < n; i++) { j = list[i]; buf[m++] = x[j][0] + dx; buf[m++] = x[j][1] + dy; buf[m++] = x[j][2] + dz; buf[m++] = s0[j]; } } return m; } /* ---------------------------------------------------------------------- */ int AtomVecPeri::pack_comm_vel(int n, int *list, double *buf, int pbc_flag, int *pbc) { int i,j,m; double dx,dy,dz; m = 0; if (pbc_flag == 0) { for (i = 0; i < n; i++) { j = list[i]; buf[m++] = x[j][0]; buf[m++] = x[j][1]; buf[m++] = x[j][2]; buf[m++] = s0[j]; buf[m++] = v[j][0]; buf[m++] = v[j][1]; buf[m++] = v[j][2]; } } else { if (domain->triclinic == 0) { dx = pbc[0]*domain->xprd; dy = pbc[1]*domain->yprd; dz = pbc[2]*domain->zprd; } else { dx = pbc[0]*domain->xprd + pbc[5]*domain->xy + pbc[4]*domain->xz; dy = pbc[1]*domain->yprd + pbc[3]*domain->yz; dz = pbc[2]*domain->zprd; } for (i = 0; i < n; i++) { j = list[i]; buf[m++] = x[j][0] + dx; buf[m++] = x[j][1] + dy; buf[m++] = x[j][2] + dz; buf[m++] = s0[j]; buf[m++] = v[j][0]; buf[m++] = v[j][1]; buf[m++] = v[j][2]; } } return m; } /* ---------------------------------------------------------------------- */ int AtomVecPeri::pack_comm_one(int i, double *buf) { buf[0] = s0[i]; return 1; } /* ---------------------------------------------------------------------- */ void AtomVecPeri::unpack_comm(int n, int first, double *buf) { int i,m,last; m = 0; last = first + n; for (i = first; i < last; i++) { x[i][0] = buf[m++]; x[i][1] = buf[m++]; x[i][2] = buf[m++]; s0[i] = buf[m++]; } } /* ---------------------------------------------------------------------- */ void AtomVecPeri::unpack_comm_vel(int n, int first, double *buf) { int i,m,last; m = 0; last = first + n; for (i = first; i < last; i++) { x[i][0] = buf[m++]; x[i][1] = buf[m++]; x[i][2] = buf[m++]; s0[i] = buf[m++]; v[i][0] = buf[m++]; v[i][1] = buf[m++]; v[i][2] = buf[m++]; } } /* ---------------------------------------------------------------------- */ int AtomVecPeri::unpack_comm_one(int i, double *buf) { s0[i] = buf[0]; return 1; } /* ---------------------------------------------------------------------- */ int AtomVecPeri::pack_reverse(int n, int first, double *buf) { int i,m,last; m = 0; last = first + n; for (i = first; i < last; i++) { buf[m++] = f[i][0]; buf[m++] = f[i][1]; buf[m++] = f[i][2]; } return m; } /* ---------------------------------------------------------------------- */ void AtomVecPeri::unpack_reverse(int n, int *list, double *buf) { int i,j,m; m = 0; for (i = 0; i < n; i++) { j = list[i]; f[j][0] += buf[m++]; f[j][1] += buf[m++]; f[j][2] += buf[m++]; } } /* ---------------------------------------------------------------------- */ int AtomVecPeri::pack_border(int n, int *list, double *buf, int pbc_flag, int *pbc) { int i,j,m; double dx,dy,dz; m = 0; if (pbc_flag == 0) { for (i = 0; i < n; i++) { j = list[i]; buf[m++] = x[j][0]; buf[m++] = x[j][1]; buf[m++] = x[j][2]; buf[m++] = tag[j]; buf[m++] = type[j]; buf[m++] = mask[j]; buf[m++] = vfrac[j]; buf[m++] = s0[j]; buf[m++] = x0[j][0]; buf[m++] = x0[j][1]; buf[m++] = x0[j][2]; } } else { if (domain->triclinic == 0) { dx = pbc[0]*domain->xprd; dy = pbc[1]*domain->yprd; dz = pbc[2]*domain->zprd; } else { dx = pbc[0]; dy = pbc[1]; dz = pbc[2]; } for (i = 0; i < n; i++) { j = list[i]; buf[m++] = x[j][0] + dx; buf[m++] = x[j][1] + dy; buf[m++] = x[j][2] + dz; buf[m++] = tag[j]; buf[m++] = type[j]; buf[m++] = mask[j]; buf[m++] = vfrac[j]; buf[m++] = s0[j]; buf[m++] = x0[j][0]; buf[m++] = x0[j][1]; buf[m++] = x0[j][2]; } } return m; } /* ---------------------------------------------------------------------- */ int AtomVecPeri::pack_border_vel(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++] = vfrac[j]; buf[m++] = s0[j]; buf[m++] = x0[j][0]; buf[m++] = x0[j][1]; buf[m++] = x0[j][2]; buf[m++] = v[j][0]; buf[m++] = v[j][1]; buf[m++] = v[j][2]; } } else { if (domain->triclinic == 0) { dx = pbc[0]*domain->xprd; dy = pbc[1]*domain->yprd; dz = pbc[2]*domain->zprd; } else { dx = pbc[0]; dy = pbc[1]; dz = pbc[2]; } 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++] = vfrac[j]; buf[m++] = s0[j]; buf[m++] = x0[j][0]; buf[m++] = x0[j][1]; buf[m++] = x0[j][2]; buf[m++] = v[j][0]; buf[m++] = v[j][1]; buf[m++] = v[j][2]; } } return m; } /* ---------------------------------------------------------------------- */ int AtomVecPeri::pack_border_one(int i, double *buf) { buf[0] = vfrac[i]; buf[1] = s0[i]; buf[2] = x0[i][0]; buf[3] = x0[i][1]; buf[4] = x0[i][2]; return 5; } /* ---------------------------------------------------------------------- */ void AtomVecPeri::unpack_border(int n, int first, double *buf) { int i,m,last; m = 0; last = first + n; for (i = first; i < last; i++) { if (i == nmax) grow(0); x[i][0] = buf[m++]; x[i][1] = buf[m++]; x[i][2] = buf[m++]; tag[i] = static_cast<int> (buf[m++]); type[i] = static_cast<int> (buf[m++]); mask[i] = static_cast<int> (buf[m++]); vfrac[i] = buf[m++]; s0[i] = buf[m++]; x0[i][0] = buf[m++]; x0[i][1] = buf[m++]; x0[i][2] = buf[m++]; } } /* ---------------------------------------------------------------------- */ void AtomVecPeri::unpack_border_vel(int n, int first, double *buf) { int i,m,last; m = 0; last = first + n; for (i = first; i < last; i++) { if (i == nmax) grow(0); x[i][0] = buf[m++]; x[i][1] = buf[m++]; x[i][2] = buf[m++]; tag[i] = static_cast<int> (buf[m++]); type[i] = static_cast<int> (buf[m++]); mask[i] = static_cast<int> (buf[m++]); vfrac[i] = buf[m++]; s0[i] = buf[m++]; x0[i][0] = buf[m++]; x0[i][1] = buf[m++]; x0[i][2] = buf[m++]; v[i][0] = buf[m++]; v[i][1] = buf[m++]; v[i][2] = buf[m++]; } } /* ---------------------------------------------------------------------- */ int AtomVecPeri::unpack_border_one(int i, double *buf) { vfrac[i] = buf[0]; s0[i] = buf[1]; x0[i][0] = buf[2]; x0[i][1] = buf[3]; x0[i][2] = buf[4]; return 5; } /* ---------------------------------------------------------------------- pack data for atom I for sending to another proc xyz must be 1st 3 values, so comm::exchange() can test on them ------------------------------------------------------------------------- */ int AtomVecPeri::pack_exchange(int i, double *buf) { int m = 1; buf[m++] = x[i][0]; buf[m++] = x[i][1]; buf[m++] = x[i][2]; buf[m++] = v[i][0]; buf[m++] = v[i][1]; buf[m++] = v[i][2]; buf[m++] = tag[i]; buf[m++] = type[i]; buf[m++] = mask[i]; buf[m++] = image[i]; buf[m++] = vfrac[i]; buf[m++] = density[i]; buf[m++] = rmass[i]; buf[m++] = s0[i]; buf[m++] = x0[i][0]; buf[m++] = x0[i][1]; buf[m++] = x0[i][2]; if (atom->nextra_grow) for (int iextra = 0; iextra < atom->nextra_grow; iextra++) m += modify->fix[atom->extra_grow[iextra]]->pack_exchange(i,&buf[m]); buf[0] = m; return m; } /* ---------------------------------------------------------------------- */ int AtomVecPeri::unpack_exchange(double *buf) { int nlocal = atom->nlocal; if (nlocal == nmax) grow(0); int m = 1; x[nlocal][0] = buf[m++]; x[nlocal][1] = buf[m++]; x[nlocal][2] = buf[m++]; v[nlocal][0] = buf[m++]; v[nlocal][1] = buf[m++]; v[nlocal][2] = buf[m++]; tag[nlocal] = static_cast<int> (buf[m++]); type[nlocal] = static_cast<int> (buf[m++]); mask[nlocal] = static_cast<int> (buf[m++]); image[nlocal] = static_cast<int> (buf[m++]); vfrac[nlocal] = buf[m++]; density[nlocal] = buf[m++]; rmass[nlocal] = buf[m++]; s0[nlocal] = buf[m++]; x0[nlocal][0] = buf[m++]; x0[nlocal][1] = buf[m++]; x0[nlocal][2] = buf[m++]; if (atom->nextra_grow) for (int iextra = 0; iextra < atom->nextra_grow; iextra++) m += modify->fix[atom->extra_grow[iextra]]-> unpack_exchange(nlocal,&buf[m]); atom->nlocal++; return m; } /* ---------------------------------------------------------------------- size of restart data for all atoms owned by this proc include extra data stored by fixes ------------------------------------------------------------------------- */ int AtomVecPeri::size_restart() { int i; int nlocal = atom->nlocal; int n = 18 * nlocal; if (atom->nextra_restart) for (int iextra = 0; iextra < atom->nextra_restart; iextra++) for (i = 0; i < nlocal; i++) n += modify->fix[atom->extra_restart[iextra]]->size_restart(i); return n; } /* ---------------------------------------------------------------------- pack atom I's data for restart file including extra quantities xyz must be 1st 3 values, so that read_restart can test on them molecular types may be negative, but write as positive ------------------------------------------------------------------------- */ int AtomVecPeri::pack_restart(int i, double *buf) { int m = 1; buf[m++] = x[i][0]; buf[m++] = x[i][1]; buf[m++] = x[i][2]; buf[m++] = tag[i]; buf[m++] = type[i]; buf[m++] = mask[i]; buf[m++] = image[i]; buf[m++] = v[i][0]; buf[m++] = v[i][1]; buf[m++] = v[i][2]; buf[m++] = vfrac[i]; buf[m++] = density[i]; buf[m++] = rmass[i]; buf[m++] = s0[i]; buf[m++] = x0[i][0]; buf[m++] = x0[i][1]; buf[m++] = x0[i][2]; if (atom->nextra_restart) for (int iextra = 0; iextra < atom->nextra_restart; iextra++) m += modify->fix[atom->extra_restart[iextra]]->pack_restart(i,&buf[m]); buf[0] = m; return m; } /* ---------------------------------------------------------------------- unpack data for one atom from restart file including extra quantities ------------------------------------------------------------------------- */ int AtomVecPeri::unpack_restart(double *buf) { int nlocal = atom->nlocal; if (nlocal == nmax) { grow(0); if (atom->nextra_store) atom->extra = memory->grow_2d_double_array(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] = static_cast<int> (buf[m++]); v[nlocal][0] = buf[m++]; v[nlocal][1] = buf[m++]; v[nlocal][2] = buf[m++]; vfrac[nlocal] = buf[m++]; density[nlocal] = buf[m++]; rmass[nlocal] = buf[m++]; s0[nlocal] = buf[m++]; x0[nlocal][0] = buf[m++]; x0[nlocal][1] = buf[m++]; x0[nlocal][2] = buf[m++]; double **extra = atom->extra; if (atom->nextra_store) { int size = static_cast<int> (buf[0]) - m; for (int i = 0; i < size; i++) extra[nlocal][i] = buf[m++]; } atom->nlocal++; return m; } /* ---------------------------------------------------------------------- create one atom of itype at coord set other values to defaults ------------------------------------------------------------------------- */ void AtomVecPeri::create_atom(int itype, double *coord) { int nlocal = atom->nlocal; if (nlocal == nmax) grow(0); tag[nlocal] = 0; type[nlocal] = itype; x[nlocal][0] = coord[0]; x[nlocal][1] = coord[1]; x[nlocal][2] = coord[2]; mask[nlocal] = 1; image[nlocal] = (512 << 20) | (512 << 10) | 512; v[nlocal][0] = 0.0; v[nlocal][1] = 0.0; v[nlocal][2] = 0.0; vfrac[nlocal] = 1.0; density[nlocal] = 1.0; rmass[nlocal] = density[nlocal]; s0[nlocal] = DBL_MAX; x0[nlocal][0] = coord[0]; x0[nlocal][1] = coord[1]; x0[nlocal][2] = coord[2]; atom->nlocal++; } /* ---------------------------------------------------------------------- unpack one line from Atoms section of data file initialize other atom quantities ------------------------------------------------------------------------- */ void AtomVecPeri::data_atom(double *coord, int imagetmp, char **values) { int nlocal = atom->nlocal; if (nlocal == nmax) grow(0); tag[nlocal] = atoi(values[0]); if (tag[nlocal] <= 0) error->one("Invalid atom ID in Atoms section of data file"); type[nlocal] = atoi(values[1]); if (type[nlocal] <= 0 || type[nlocal] > atom->ntypes) error->one("Invalid atom type in Atoms section of data file"); vfrac[nlocal] = atof(values[2]); density[nlocal] = atof(values[3]); rmass[nlocal] = density[nlocal]; if (rmass[nlocal] <= 0.0) error->one("Invalid mass value"); x[nlocal][0] = coord[0]; x[nlocal][1] = coord[1]; x[nlocal][2] = coord[2]; image[nlocal] = imagetmp; mask[nlocal] = 1; v[nlocal][0] = 0.0; v[nlocal][1] = 0.0; v[nlocal][2] = 0.0; s0[nlocal] = DBL_MAX; x0[nlocal][0] = coord[0]; x0[nlocal][1] = coord[1]; x0[nlocal][2] = coord[2]; atom->nlocal++; } /* ---------------------------------------------------------------------- unpack hybrid quantities from one line in Atoms section of data file initialize other atom quantities for this sub-style ------------------------------------------------------------------------- */ int AtomVecPeri::data_atom_hybrid(int nlocal, char **values) { vfrac[nlocal] = atof(values[0]); density[nlocal] = atof(values[1]); rmass[nlocal] = density[nlocal]; if (rmass[nlocal] <= 0.0) error->one("Invalid mass value"); s0[nlocal] = DBL_MAX; x0[nlocal][0] = x[nlocal][0]; x0[nlocal][1] = x[nlocal][1]; x0[nlocal][2] = x[nlocal][2]; return 2; } /* ---------------------------------------------------------------------- return # of bytes of allocated memory ------------------------------------------------------------------------- */ double AtomVecPeri::memory_usage() { double bytes = 0.0; if (atom->memcheck("tag")) bytes += nmax * sizeof(int); if (atom->memcheck("type")) bytes += nmax * sizeof(int); if (atom->memcheck("mask")) bytes += nmax * sizeof(int); if (atom->memcheck("image")) bytes += nmax * sizeof(int); if (atom->memcheck("x")) bytes += nmax*3 * sizeof(double); if (atom->memcheck("v")) bytes += nmax*3 * sizeof(double); if (atom->memcheck("f")) bytes += nmax*3 * sizeof(double); if (atom->memcheck("vfrac")) bytes += nmax * sizeof(double); if (atom->memcheck("density")) bytes += nmax * sizeof(double); if (atom->memcheck("rmass")) bytes += nmax * sizeof(double); if (atom->memcheck("s0")) bytes += nmax * sizeof(double); if (atom->memcheck("x0")) bytes += nmax*3 * sizeof(double); return bytes; } diff --git a/src/PERI/fix_peri_neigh.cpp b/src/PERI/fix_peri_neigh.cpp index 14dbf8cbb..d56946caa 100644 --- a/src/PERI/fix_peri_neigh.cpp +++ b/src/PERI/fix_peri_neigh.cpp @@ -1,518 +1,518 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- Contributing author: Mike Parks (SNL) ------------------------------------------------------------------------- */ #include "math.h" #include "fix_peri_neigh.h" #include "pair_peri_pmb.h" #include "pair_peri_lps.h" #include "atom.h" #include "domain.h" #include "force.h" #include "comm.h" #include "update.h" #include "neighbor.h" #include "neigh_list.h" #include "neigh_request.h" #include "pair.h" #include "lattice.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; #define MIN(A,B) ((A) < (B)) ? (A) : (B) #define MAX(A,B) ((A) > (B)) ? (A) : (B) /* ---------------------------------------------------------------------- */ FixPeriNeigh::FixPeriNeigh(LAMMPS *lmp,int narg, char **arg) : Fix(lmp, narg, arg) { restart_global = 1; restart_peratom = 1; first = 1; // perform initial allocation of atom-based arrays // register with atom class // set maxpartner = 1 as placeholder maxpartner = 1; npartner = NULL; partner = NULL; r0 = NULL; vinter = NULL; wvolume = NULL; grow_arrays(atom->nmax); atom->add_callback(0); atom->add_callback(1); // initialize npartner to 0 so atom migration is OK the 1st time int nlocal = atom->nlocal; for (int i = 0; i < nlocal; i++) npartner[i] = 0; // set comm sizes needed by this fix comm_forward = 1; } /* ---------------------------------------------------------------------- */ FixPeriNeigh::~FixPeriNeigh() { // unregister this fix so atom class doesn't invoke it any more atom->delete_callback(id,0); atom->delete_callback(id,1); // delete locally stored arrays memory->sfree(npartner); memory->destroy_2d_int_array(partner); memory->destroy_2d_double_array(r0); memory->sfree(vinter); memory->sfree(wvolume); } /* ---------------------------------------------------------------------- */ int FixPeriNeigh::setmask() { int mask = 0; return mask; } /* ---------------------------------------------------------------------- */ void FixPeriNeigh::init() { if (!first) return; // need a full neighbor list once int irequest = neighbor->request((void *) this); neighbor->requests[irequest]->pair = 0; neighbor->requests[irequest]->fix = 1; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->full = 1; neighbor->requests[irequest]->occasional = 1; } /* ---------------------------------------------------------------------- */ void FixPeriNeigh::init_list(int id, NeighList *ptr) { list = ptr; } /* ---------------------------------------------------------------------- create initial list of neighbor partners via call to neighbor->build() must be done in setup (not init) since fix init comes before neigh init ------------------------------------------------------------------------- */ void FixPeriNeigh::setup(int vflag) { int i,j,ii,jj,itype,jtype,inum,jnum; double xtmp,ytmp,ztmp,delx,dely,delz,rsq; int *ilist,*jlist,*numneigh; int **firstneigh; double **x = atom->x; double *vfrac = atom->vfrac; int *type = atom->type; int *tag = atom->tag; int nlocal = atom->nlocal; // only build list of bonds on very first run if (!first) return; first = 0; // invoke full neighbor list (will copy or build if necessary) neighbor->build_one(list->index); inum = list->inum; ilist = list->ilist; numneigh = list->numneigh; firstneigh = list->firstneigh; // scan neighbor list to set maxpartner Pair *anypair = force->pair_match("peri",0); double **cutsq = anypair->cutsq; for (ii = 0; ii < inum; ii++) { i = ilist[ii]; xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; itype = type[i]; jlist = firstneigh[i]; jnum = numneigh[i]; for (jj = 0; jj < jnum; jj++) { j = jlist[jj]; delx = xtmp - x[j][0]; dely = ytmp - x[j][1]; delz = ztmp - x[j][2]; rsq = delx*delx + dely*dely + delz*delz; jtype = type[j]; if (rsq <= cutsq[itype][jtype]) npartner[i]++; } } maxpartner = 0; for (i = 0; i < nlocal; i++) maxpartner = MAX(maxpartner,npartner[i]); int maxall; MPI_Allreduce(&maxpartner,&maxall,1,MPI_INT,MPI_MAX,world); maxpartner = maxall; // realloc arrays with correct value for maxpartner memory->destroy_2d_int_array(partner); memory->destroy_2d_double_array(r0); memory->sfree(npartner); npartner = NULL; partner = NULL; r0 = NULL; grow_arrays(atom->nmax); // create partner list and r0 values from neighbor list // compute vinter for each atom for (i = 0; i < nlocal; i++) { npartner[i] = 0; vinter[i] = 0.0; wvolume[i] = 0.0; } for (ii = 0; ii < inum; ii++) { i = ilist[ii]; xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; itype = type[i]; jlist = firstneigh[i]; jnum = numneigh[i]; for (jj = 0; jj < jnum; jj++) { j = jlist[jj]; delx = xtmp - x[j][0]; dely = ytmp - x[j][1]; delz = ztmp - x[j][2]; rsq = delx*delx + dely*dely + delz*delz; jtype = type[j]; if (rsq <= cutsq[itype][jtype]) { partner[i][npartner[i]] = tag[j]; r0[i][npartner[i]] = sqrt(rsq); npartner[i]++; vinter[i] += vfrac[j]; } } } // compute wvolume for each atom double **x0 = atom->x0; double half_lc = 0.5*(domain->lattice->xlattice); double vfrac_scale; PairPeriLPS *pairlps = dynamic_cast<PairPeriLPS*>(anypair); PairPeriPMB *pairpmb = dynamic_cast<PairPeriPMB*>(anypair); for (i = 0; i < nlocal; i++) { double xtmp0 = x0[i][0]; double ytmp0 = x0[i][1]; double ztmp0 = x0[i][2]; jnum = npartner[i]; itype = type[i]; // loop over partners of particle i for (jj = 0; jj < jnum; jj++) { // if bond already broken, skip this partner if (partner[i][jj] == 0) continue; // lookup local index of partner particle j = atom->map(partner[i][jj]); // skip if particle is "lost" if (j < 0) continue; double delx0 = xtmp0 - x0[j][0]; double dely0 = ytmp0 - x0[j][1]; double delz0 = ztmp0 - x0[j][2]; double rsq0 = delx0*delx0 + dely0*dely0 + delz0*delz0; jtype = type[j]; double delta = sqrt(cutsq[itype][jtype]); // scale vfrac[j] if particle j near the horizon if ((fabs(r0[i][jj] - delta)) <= half_lc) vfrac_scale = (-1.0/(2*half_lc))*(r0[i][jj]) + (1.0 + ((delta - half_lc)/(2*half_lc) ) ); else vfrac_scale = 1.0; if (pairpmb != NULL) // define influence function to be 1.0 wvolume[i] += 1.0 * rsq0 * vfrac[j] * vfrac_scale; else if (pairlps != NULL) // call the PairPeriLPS influence function wvolume[i] += pairlps->influence_function(delx0,dely0,delz0) * rsq0 * vfrac[j] * vfrac_scale; } } // communicate wvolume to ghosts comm->forward_comm_fix(this); // bond statistics int n = 0; for (i = 0; i < nlocal; i++) n += npartner[i]; int nall; MPI_Allreduce(&n,&nall,1,MPI_INT,MPI_SUM,world); if (comm->me == 0) { if (screen) { fprintf(screen,"Peridynamic bonds:\n"); fprintf(screen," total # of bonds = %d\n",nall); - fprintf(screen," bonds/atom = %g\n",nall/atom->natoms); + fprintf(screen," bonds/atom = %g\n",(double)nall/atom->natoms); } if (logfile) { fprintf(logfile,"Peridynamic bonds:\n"); fprintf(logfile," total # of bonds = %d\n",nall); - fprintf(logfile," bonds/atom = %g\n",nall/atom->natoms); + fprintf(logfile," bonds/atom = %g\n",(double)nall/atom->natoms); } } } /* ---------------------------------------------------------------------- memory usage of local atom-based arrays ------------------------------------------------------------------------- */ double FixPeriNeigh::memory_usage() { int nmax = atom->nmax; int bytes = nmax * sizeof(int); bytes += nmax*maxpartner * sizeof(int); bytes += nmax*maxpartner * sizeof(double); bytes += nmax * sizeof(double); bytes += nmax * sizeof(double); return bytes; } /* ---------------------------------------------------------------------- allocate local atom-based arrays ------------------------------------------------------------------------- */ void FixPeriNeigh::grow_arrays(int nmax) { npartner = (int *) memory->srealloc(npartner,nmax*sizeof(int), "peri_neigh:npartner"); partner = memory->grow_2d_int_array(partner,nmax,maxpartner, "peri_neigh:partner"); r0 = memory->grow_2d_double_array(r0,nmax,maxpartner,"peri_neigh:r0"); vinter = (double *) memory->srealloc(vinter,nmax*sizeof(double), "peri_neigh:vinter"); wvolume = (double *) memory->srealloc(wvolume,nmax*sizeof(double), "peri_neigh:wvolume"); } /* ---------------------------------------------------------------------- copy values within local atom-based arrays ------------------------------------------------------------------------- */ void FixPeriNeigh::copy_arrays(int i, int j) { npartner[j] = npartner[i]; for (int m = 0; m < npartner[j]; m++) { partner[j][m] = partner[i][m]; r0[j][m] = r0[i][m]; } vinter[j] = vinter[i]; wvolume[j] = wvolume[i]; } /* ---------------------------------------------------------------------- pack values in local atom-based arrays for exchange with another proc ------------------------------------------------------------------------- */ int FixPeriNeigh::pack_exchange(int i, double *buf) { // compact list by eliminating partner = 0 entries // set buf[0] after compaction int m = 1; for (int n = 0; n < npartner[i]; n++) { if (partner[i][n] == 0) continue; buf[m++] = partner[i][n]; buf[m++] = r0[i][n]; } buf[0] = m/2; buf[m++] = vinter[i]; buf[m++] = wvolume[i]; return m; } /* ---------------------------------------------------------------------- unpack values in local atom-based arrays from exchange with another proc ------------------------------------------------------------------------- */ int FixPeriNeigh::unpack_exchange(int nlocal, double *buf) { int m = 0; npartner[nlocal] = static_cast<int> (buf[m++]); for (int n = 0; n < npartner[nlocal]; n++) { partner[nlocal][n] = static_cast<int> (buf[m++]); r0[nlocal][n] = buf[m++]; } vinter[nlocal] = buf[m++]; wvolume[nlocal] = buf[m++]; return m; } /* ---------------------------------------------------------------------- */ int FixPeriNeigh::pack_comm(int n, int *list, double *buf, int pbc_flag, int *pbc) { int i,j,m; m = 0; for (i = 0; i < n; i++) { j = list[i]; buf[m++] = wvolume[j]; } return 1; } /* ---------------------------------------------------------------------- */ void FixPeriNeigh::unpack_comm(int n, int first, double *buf) { int i,m,last; m = 0; last = first + n; for (i = first; i < last; i++) wvolume[i] = buf[m++]; } /* ---------------------------------------------------------------------- pack entire state of Fix into one write ------------------------------------------------------------------------- */ void FixPeriNeigh::write_restart(FILE *fp) { int n = 0; double list[2]; list[n++] = first; list[n++] = maxpartner; if (comm->me == 0) { int size = n * sizeof(double); fwrite(&size,sizeof(int),1,fp); fwrite(list,sizeof(double),n,fp); } } /* ---------------------------------------------------------------------- use state info from restart file to restart the Fix ------------------------------------------------------------------------- */ void FixPeriNeigh::restart(char *buf) { int n = 0; double *list = (double *) buf; first = static_cast<int> (list[n++]); maxpartner = static_cast<int> (list[n++]); // grow 2D arrays now, cannot change size of 2nd array index later grow_arrays(atom->nmax); } /* ---------------------------------------------------------------------- pack values in local atom-based arrays for restart file ------------------------------------------------------------------------- */ int FixPeriNeigh::pack_restart(int i, double *buf) { int m = 0; buf[m++] = 2*npartner[i] + 4; buf[m++] = npartner[i]; for (int n = 0; n < npartner[i]; n++) { buf[m++] = partner[i][n]; buf[m++] = r0[i][n]; } buf[m++] = vinter[i]; buf[m++] = wvolume[i]; return m; } /* ---------------------------------------------------------------------- unpack values from atom->extra array to restart the fix ------------------------------------------------------------------------- */ void FixPeriNeigh::unpack_restart(int nlocal, int nth) { double **extra = atom->extra; // skip to Nth set of extra values int m = 0; for (int i = 0; i < nth; i++) m += static_cast<int> (extra[nlocal][m]); m++; npartner[nlocal] = static_cast<int> (extra[nlocal][m++]); for (int n = 0; n < npartner[nlocal]; n++) { partner[nlocal][n] = static_cast<int> (extra[nlocal][m++]); r0[nlocal][n] = extra[nlocal][m++]; } vinter[nlocal] = extra[nlocal][m++]; wvolume[nlocal] = extra[nlocal][m++]; } /* ---------------------------------------------------------------------- maxsize of any atom's restart data ------------------------------------------------------------------------- */ int FixPeriNeigh::maxsize_restart() { return 2*maxpartner + 4; } /* ---------------------------------------------------------------------- size of atom nlocal's restart data ------------------------------------------------------------------------- */ int FixPeriNeigh::size_restart(int nlocal) { return 2*npartner[nlocal] + 4; } diff --git a/src/REAX/fix_reax_bonds.cpp b/src/REAX/fix_reax_bonds.cpp index 5961b8ed0..1798ffc32 100644 --- a/src/REAX/fix_reax_bonds.cpp +++ b/src/REAX/fix_reax_bonds.cpp @@ -1,237 +1,240 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- Contributing author: Aidan Thompson (Sandia) ------------------------------------------------------------------------- */ #include "stdlib.h" #include "string.h" #include "fix_reax_bonds.h" +#include "lmptype.h" #include "pair_reax_fortran.h" #include "atom.h" #include "update.h" #include "force.h" #include "modify.h" #include "compute.h" #include "input.h" #include "variable.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; /* ---------------------------------------------------------------------- */ FixReaxBonds::FixReaxBonds(LAMMPS *lmp, int narg, char **arg) : Fix(lmp, narg, arg) { if (narg < 5) error->all("Illegal fix reax/bonds command"); MPI_Comm_rank(world,&me); nevery = atoi(arg[3]); if (nevery < 1) error->all("Illegal fix reax/bonds command"); if (me == 0) { fp = fopen(arg[4],"w"); if (fp == NULL) { char str[128]; sprintf(str,"Cannot open fix reax/bonds file %s",arg[4]); error->one(str); } } } /* ---------------------------------------------------------------------- */ FixReaxBonds::~FixReaxBonds() { if (me == 0) fclose(fp); } /* ---------------------------------------------------------------------- */ int FixReaxBonds::setmask() { int mask = 0; mask |= END_OF_STEP; return mask; } /* ---------------------------------------------------------------------- perform initial write ------------------------------------------------------------------------- */ void FixReaxBonds::setup(int vflag) { end_of_step(); } /* ---------------------------------------------------------------------- */ void FixReaxBonds::init() { // insure ReaxFF is defined if (force->pair_match("reax",1) == NULL) error->all("Cannot use fix reax/bonds without pair_style reax"); } /* ---------------------------------------------------------------------- */ void FixReaxBonds::end_of_step() { OutputReaxBonds(update->ntimestep,fp); if (me == 0) fflush(fp); } /* ---------------------------------------------------------------------- */ -void FixReaxBonds::OutputReaxBonds(int timestep, FILE *fp) +void FixReaxBonds::OutputReaxBonds(bigint ntimestep, FILE *fp) { int nparticles,nparticles_tot,nbuf,nbuf_local,most,j; int ii,jn,mbond,numbonds,nsbmax,nsbmax_most; int nprocs,nlocal_tmp,itmp; double cutof3; double *buf; MPI_Request irequest; MPI_Status istatus; MPI_Comm_size(world,&nprocs); nparticles = atom->nlocal; nparticles_tot = static_cast<int> (atom->natoms); mbond = ReaxParams::mbond; FORTRAN(getnsbmax,GETNSBMAX)(&nsbmax); FORTRAN(getcutof3,GETCUTOF3)(&cutof3); MPI_Allreduce(&nparticles,&most,1,MPI_INT,MPI_MAX,world); MPI_Allreduce(&nsbmax,&nsbmax_most,1,MPI_INT,MPI_MAX,world); if (me == 0) { - fprintf(fp,"# Timestep %d \n",timestep); + char fstr[32]; + sprintf(fstr,"# Timestep %d \n",BIGINT_FORMAT); + fprintf(fp,fstr,ntimestep); fprintf(fp,"# \n"); fprintf(fp,"# Number of particles %d \n",nparticles_tot); fprintf(fp,"# \n"); fprintf(fp,"# Max.number of bonds per atom %d with " "coarse bond order cutoff %5.3f \n", nsbmax_most,cutof3); fprintf(fp,"# Particle connection table and bond orders \n"); fprintf(fp,"# id type nb id_1...id_nb mol bo_1...bo_nb abo nlp q \n"); } // allocate a temporary buffer for the snapshot info // big enough for largest number of atoms on any one proc // nbuf_local = size of local buffer for table of atom bonds nbuf = 1+(2*nsbmax_most+7)*most; buf = (double *) memory->smalloc(nbuf*sizeof(double),"reax/bonds:buf"); j = 2; jn = ReaxParams::nat; buf[0] = nparticles; for (int iparticle=0;iparticle<nparticles;iparticle++) { buf[j-1] = atom->tag[iparticle]; //atom tag buf[j+0] = FORTRAN(cbkia,CBKIA).iag[iparticle]; //atom type buf[j+1] = FORTRAN(cbkia,CBKIA).iag[iparticle+jn]; //no.bonds int k; numbonds = nint(buf[j+1]); // connection table based on coarse bond order cutoff (> cutof3) for (k=2;k<2+numbonds;k++) { ii = FORTRAN(cbkia,CBKIA).iag[iparticle+jn*k]; buf[j+k] = FORTRAN(cbkc,CBKC).itag[ii-1]; } buf[j+k]=FORTRAN(cbkia,CBKIA).iag[iparticle+jn*(mbond+2)]; //molec.id j+=(3+numbonds); // bond orders (> cutof3) for (k=0;k<numbonds;k++) { ii = FORTRAN(cbknubon2,CBKNUBON2).nubon1[iparticle+jn*k]; buf[j+k] = FORTRAN(cbkbo,CBKBO).bo[ii-1]; } // sum of bond orders (abo), no. of lone pairs (vlp), charge (ch) buf[j+k] = FORTRAN(cbkabo,CBKABO).abo[iparticle]; buf[j+k+1] = FORTRAN(cbklonpar,CBKLONPAR).vlp[iparticle]; // buf[j+k+2] = FORTRAN(cbkch,CBKCH).ch[iparticle]; buf[j+k+2] = atom->q[iparticle]; j+=(4+numbonds); } nbuf_local = j-1; // node 0 pings each node, receives their buffer, writes to file // all other nodes wait for ping, send buffer to node 0 if (me == 0) { for (int inode = 0; inode<nprocs; inode++) { if (inode == 0) { nlocal_tmp = nparticles; } else { MPI_Irecv(&buf[0],nbuf,MPI_DOUBLE,inode,0,world,&irequest); MPI_Send(&itmp,0,MPI_INT,inode,0,world); MPI_Wait(&irequest,&istatus); nlocal_tmp = nint(buf[0]); } j = 2; for (int iparticle=0;iparticle<nlocal_tmp;iparticle++) { // print atom tag, atom type, no.bonds fprintf(fp," %d %d %d",nint(buf[j-1]),nint(buf[j+0]),nint(buf[j+1])); int k; numbonds = nint(buf[j+1]); if (numbonds > nsbmax_most) { char str[128]; sprintf(str,"Fix reax/bonds numbonds > nsbmax_most"); error->one(str); } // print connection table for (k=2;k<2+numbonds;k++) fprintf(fp," %d",nint(buf[j+k])); fprintf(fp," %d",nint(buf[j+k])); j+=(3+numbonds); // print bond orders for (k=0;k<numbonds;k++) fprintf(fp,"%14.3f",buf[j+k]); // print sum of bond orders, no. of lone pairs, charge fprintf(fp,"%14.3f%14.3f%14.3f\n",buf[j+k],buf[j+k+1],buf[j+k+2]); j+=(4+numbonds); } } } else { MPI_Recv(&itmp,0,MPI_INT,0,0,world,&istatus); MPI_Rsend(&buf[0],nbuf_local,MPI_DOUBLE,0,0,world); } if (me == 0) fprintf(fp,"# \n"); memory->sfree(buf); } /* ---------------------------------------------------------------------- */ int FixReaxBonds::nint(const double &r) { int i = 0; if (r>0.0) i = static_cast<int>(r+0.5); else if (r<0.0) i = static_cast<int>(r-0.5); return i; } diff --git a/src/REAX/pair_reax.cpp b/src/REAX/pair_reax.cpp index 218c4e427..a51737589 100644 --- a/src/REAX/pair_reax.cpp +++ b/src/REAX/pair_reax.cpp @@ -1,1069 +1,1069 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain 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: Aidan Thompson (Sandia, athomps@sandia.gov) Hansohl Cho (MIT, hansohl@mit.edu) LAMMPS implementation of the Reactive Force Field (ReaxFF) is based on Aidan Thompson's GRASP code (General Reactive Atomistic Simulation Program) and Ardi Van Duin's original ReaxFF code ------------------------------------------------------------------------- */ #include "mpi.h" #include "math.h" #include "stdio.h" #include "stdlib.h" #include "string.h" #include "pair_reax.h" #include "pair_reax_fortran.h" #include "atom.h" #include "update.h" #include "force.h" #include "comm.h" #include "neighbor.h" #include "neigh_list.h" #include "neigh_request.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; #define MIN(a,b) ((a) < (b) ? (a) : (b)) #define MAX(a,b) ((a) > (b) ? (a) : (b)) #define SMALL 0.0001 /* ---------------------------------------------------------------------- */ PairREAX::PairREAX(LAMMPS *lmp) : Pair(lmp) { single_enable = 0; one_coeff = 1; no_virial_compute = 1; nextra = 14; pvector = new double[nextra]; cutmax = 0.0; hbcut = 6.0; ihbnew = 1; itripstaball = 1; iprune = 4; ihb = 1; chpot = 0; nmax = 0; arow_ptr = NULL; ch = NULL; elcvec = NULL; rcg = NULL; wcg = NULL; pcg = NULL; poldcg = NULL; qcg = NULL; matmax = 0; aval = NULL; acol_ind = NULL; comm_forward = 1; comm_reverse = 1; precision = 1.0e-6; } /* ---------------------------------------------------------------------- free all arrays check if allocated, since class can be destructed when incomplete ------------------------------------------------------------------------- */ PairREAX::~PairREAX() { delete [] pvector; if (allocated) { memory->destroy_2d_int_array(setflag); memory->destroy_2d_double_array(cutsq); for (int i = 1; i <= atom->ntypes; i++) delete [] param_list[i].params; delete [] param_list; delete [] map; } memory->sfree(arow_ptr); memory->sfree(ch); memory->sfree(elcvec); memory->sfree(rcg); memory->sfree(wcg); memory->sfree(pcg); memory->sfree(poldcg); memory->sfree(qcg); memory->sfree(aval); memory->sfree(acol_ind); } /* ---------------------------------------------------------------------- */ void PairREAX::compute(int eflag, int vflag) { int i,j; double evdwl,ecoul; double energy_charge_equilibration; evdwl = ecoul = 0.0; if (eflag || vflag) ev_setup(eflag,vflag); else evflag = vflag_fdotr = eflag_global = vflag_global = 0; if (vflag_global) FORTRAN(cbkvirial, CBKVIRIAL).Lvirial = 1; else FORTRAN(cbkvirial, CBKVIRIAL).Lvirial = 0; if (vflag_atom) FORTRAN(cbkvirial, CBKVIRIAL).Latomvirial = 1; else FORTRAN(cbkvirial, CBKVIRIAL).Latomvirial = 0; // reallocate charge equilibration and CG arrays if necessary if (atom->nmax > nmax) { memory->sfree(rcg); memory->sfree(wcg); memory->sfree(pcg); memory->sfree(poldcg); memory->sfree(qcg); nmax = atom->nmax; int n = nmax+1; arow_ptr = (int *) memory->smalloc(n*sizeof(int),"reax:arow_ptr"); ch = (double *) memory->smalloc(n*sizeof(double),"reax:ch"); elcvec = (double *) memory->smalloc(n*sizeof(double),"reax:elcvec"); rcg = (double *) memory->smalloc(n*sizeof(double),"reax:rcg"); wcg = (double *) memory->smalloc(n*sizeof(double),"reax:wcg"); pcg = (double *) memory->smalloc(n*sizeof(double),"reax:pcg"); poldcg = (double *) memory->smalloc(n*sizeof(double),"reax:poldcg"); qcg = (double *) memory->smalloc(n*sizeof(double),"reax:qcg"); } // calculate the atomic charge distribution compute_charge(energy_charge_equilibration); // transfer LAMMPS positions and neighbor lists to REAX write_reax_positions(); write_reax_vlist(); // determine whether this bond is owned by the processor or not FORTRAN(srtbon1, SRTBON1)(&iprune, &ihb, &hbcut, &ihbnew, &itripstaball); // communicate with other processors for the atomic bond order calculations FORTRAN(cbkabo, CBKABO).abo; // communicate local atomic bond order to ghost atomic bond order packflag = 0; comm->forward_comm_pair(this); FORTRAN(molec, MOLEC)(); FORTRAN(encalc, ENCALC)(); FORTRAN(mdsav, MDSAV)(&comm->me); // read forces from ReaxFF Fortran read_reax_forces(); // extract global and per-atom energy from ReaxFF Fortran // compute_charge already contributed to eatom if (eflag_global) { evdwl += FORTRAN(cbkenergies, CBKENERGIES).eb; evdwl += FORTRAN(cbkenergies, CBKENERGIES).ea; evdwl += FORTRAN(cbkenergies, CBKENERGIES).elp; evdwl += FORTRAN(cbkenergies, CBKENERGIES).emol; evdwl += FORTRAN(cbkenergies, CBKENERGIES).ev; evdwl += FORTRAN(cbkenergies, CBKENERGIES).epen; evdwl += FORTRAN(cbkenergies, CBKENERGIES).ecoa; evdwl += FORTRAN(cbkenergies, CBKENERGIES).ehb; evdwl += FORTRAN(cbkenergies, CBKENERGIES).et; evdwl += FORTRAN(cbkenergies, CBKENERGIES).eco; evdwl += FORTRAN(cbkenergies, CBKENERGIES).ew; evdwl += FORTRAN(cbkenergies, CBKENERGIES).efi; ecoul += FORTRAN(cbkenergies, CBKENERGIES).ep; ecoul += energy_charge_equilibration; eng_vdwl += evdwl; eng_coul += ecoul; // Store the different parts of the energy // in a list for output by compute pair command pvector[0] = FORTRAN(cbkenergies, CBKENERGIES).eb; pvector[1] = FORTRAN(cbkenergies, CBKENERGIES).ea; pvector[2] = FORTRAN(cbkenergies, CBKENERGIES).elp; pvector[3] = FORTRAN(cbkenergies, CBKENERGIES).emol; pvector[4] = FORTRAN(cbkenergies, CBKENERGIES).ev; pvector[5] = FORTRAN(cbkenergies, CBKENERGIES).epen; pvector[6] = FORTRAN(cbkenergies, CBKENERGIES).ecoa; pvector[7] = FORTRAN(cbkenergies, CBKENERGIES).ehb; pvector[8] = FORTRAN(cbkenergies, CBKENERGIES).et; pvector[9] = FORTRAN(cbkenergies, CBKENERGIES).eco; pvector[10] = FORTRAN(cbkenergies, CBKENERGIES).ew; pvector[11] = FORTRAN(cbkenergies, CBKENERGIES).ep; pvector[12] = FORTRAN(cbkenergies, CBKENERGIES).efi; pvector[13] = energy_charge_equilibration; } if (eflag_atom) { int ntotal = atom->nlocal + atom->nghost; for (i = 0; i < ntotal; i++) eatom[i] += FORTRAN(cbkd,CBKD).estrain[i]; } // extract global and per-atom virial from ReaxFF Fortran if (vflag_global) { virial[0] = -FORTRAN(cbkvirial, CBKVIRIAL).virial[0]; virial[1] = -FORTRAN(cbkvirial, CBKVIRIAL).virial[1]; virial[2] = -FORTRAN(cbkvirial, CBKVIRIAL).virial[2]; virial[3] = -FORTRAN(cbkvirial, CBKVIRIAL).virial[3]; virial[4] = -FORTRAN(cbkvirial, CBKVIRIAL).virial[4]; virial[5] = -FORTRAN(cbkvirial, CBKVIRIAL).virial[5]; } if (vflag_atom) { int ntotal = atom->nlocal + atom->nghost; j = 0; for (i = 0; i < ntotal; i++) { vatom[i][0] = -FORTRAN(cbkvirial, CBKVIRIAL).atomvirial[j+0]; vatom[i][1] = -FORTRAN(cbkvirial, CBKVIRIAL).atomvirial[j+1]; vatom[i][2] = -FORTRAN(cbkvirial, CBKVIRIAL).atomvirial[j+2]; vatom[i][3] = -FORTRAN(cbkvirial, CBKVIRIAL).atomvirial[j+3]; vatom[i][4] = -FORTRAN(cbkvirial, CBKVIRIAL).atomvirial[j+4]; vatom[i][5] = -FORTRAN(cbkvirial, CBKVIRIAL).atomvirial[j+5]; j += 6; } } } /* ---------------------------------------------------------------------- */ void PairREAX::write_reax_positions() { double xtmp, ytmp, ztmp; int j, jx, jy, jz, jia; double **x = atom->x; double *q = atom->q; int *type = atom->type; int *tag = atom->tag; int nlocal = atom->nlocal; int nghost = atom->nghost; FORTRAN(rsmall, RSMALL).na = nlocal+nghost; FORTRAN(rsmall, RSMALL).na_local = nlocal; if (nlocal+nghost > ReaxParams::nat) error->one("Reax_defs.h setting for NATDEF is too small"); jx = 0; jy = ReaxParams::nat; jz = 2*ReaxParams::nat; jia = 0; j = 0; for (int i = 0; i < nlocal+nghost; i++, j++) { FORTRAN(cbkc, CBKC).c[j+jx] = x[i][0]; FORTRAN(cbkc, CBKC).c[j+jy] = x[i][1]; FORTRAN(cbkc, CBKC).c[j+jz] = x[i][2]; FORTRAN(cbkch, CBKCH).ch[j] = q[i]; FORTRAN(cbkia, CBKIA).ia[j+jia] = map[type[i]]; FORTRAN(cbkia, CBKIA).iag[j+jia] = map[type[i]]; FORTRAN(cbkc, CBKC).itag[j] = tag[i]; } } /* ---------------------------------------------------------------------- */ void PairREAX::write_reax_vlist() { int ii, jj, i, j, iii, jjj; double xitmp, yitmp, zitmp; double xjtmp, yjtmp, zjtmp; int itag,jtag; int nvpair, nvlself, nvpairmax; int nbond; int inum,jnum; int *ilist; int *jlist; int *numneigh,**firstneigh; double delr2; double delx, dely, delz; double rtmp[3]; double **x = atom->x; int *tag = atom->tag; int nlocal = atom->nlocal; int nghost = atom->nghost; nvpairmax = ReaxParams::nneighmax * ReaxParams::nat; nvpair = 0; nvlself =0; nbond = 0; inum = list->inum; ilist = list->ilist; numneigh = list->numneigh; firstneigh = list->firstneigh; for (ii = 0; ii < inum; ii++) { i = ilist[ii]; xitmp = x[i][0]; yitmp = x[i][1]; zitmp = x[i][2]; itag = tag[i]; jlist = firstneigh[i]; jnum = numneigh[i]; for (jj = 0; jj < jnum; jj++) { j = jlist[jj]; xjtmp = x[j][0]; yjtmp = x[j][1]; zjtmp = x[j][2]; jtag = tag[j]; delx = xitmp - xjtmp; dely = yitmp - yjtmp; delz = zitmp - zjtmp; delr2 = delx*delx+dely*dely+delz*delz; if (delr2 <= rcutvsq) { if (i < j) { iii = i+1; jjj = j+1; } else { iii = j+1; jjj = i+1; } if (nvpair >= nvpairmax) error->one("Reax_defs.h setting for NNEIGHMAXDEF is too small"); FORTRAN(cbkpairs, CBKPAIRS).nvl1[nvpair] = iii; FORTRAN(cbkpairs, CBKPAIRS).nvl2[nvpair] = jjj; FORTRAN(cbknvlbo, CBKNVLBO).nvlbo[nvpair] = 0; if (delr2 <= rcutbsq) { FORTRAN(cbknvlbo, CBKNVLBO).nvlbo[nvpair] = 1; nbond++; } FORTRAN(cbknvlown, CBKNVLOWN).nvlown[nvpair] = 0; if (j < nlocal) FORTRAN(cbknvlown, CBKNVLOWN).nvlown[nvpair] = 1; else if (itag < jtag) FORTRAN(cbknvlown, CBKNVLOWN).nvlown[nvpair] = 1; else if (itag == jtag) { if (delz > SMALL) FORTRAN(cbknvlown, CBKNVLOWN).nvlown[nvpair] = 1; else if (fabs(delz) < SMALL) { if (dely > SMALL) FORTRAN(cbknvlown, CBKNVLOWN).nvlown[nvpair] = 1; else if (fabs(dely) < SMALL && delx > SMALL) FORTRAN(cbknvlown, CBKNVLOWN).nvlown[nvpair] = 1; } } nvpair++; } } } int ntotal = nlocal + nghost; for (int i = nlocal; i < ntotal; i++) { xitmp = x[i][0]; yitmp = x[i][1]; zitmp = x[i][2]; itag = tag[i]; for (int j = i+1; j < ntotal; j++) { xjtmp = x[j][0]; yjtmp = x[j][1]; zjtmp = x[j][2]; jtag = tag[j]; delx = xitmp - xjtmp; dely = yitmp - yjtmp; delz = zitmp - zjtmp; delr2 = delx*delx+dely*dely+delz*delz; // don't need to check the double count since i < j in the ghost region if (delr2 <= rcutvsq) { iii = i+1; jjj = j+1; if (nvpair >= nvpairmax) error->one("Reax_defs.h setting for NNEIGHMAXDEF is too small"); FORTRAN(cbkpairs, CBKPAIRS).nvl1[nvpair] = iii; FORTRAN(cbkpairs, CBKPAIRS).nvl2[nvpair] = jjj; FORTRAN(cbknvlbo, CBKNVLBO).nvlbo[nvpair] = 0; if (delr2 <= rcutbsq) { FORTRAN(cbknvlbo, CBKNVLBO).nvlbo[nvpair] = 1; nbond++; } FORTRAN(cbknvlown, CBKNVLOWN).nvlown[nvpair] = 0; nvpair++; } } } FORTRAN(cbkpairs, CBKPAIRS).nvpair = nvpair; FORTRAN(cbkpairs, CBKPAIRS).nvlself = nvlself; } /* ---------------------------------------------------------------------- */ void PairREAX::read_reax_forces() { double ftmp[3]; double **f = atom->f; int ntotal = atom->nlocal + atom->nghost; int j = 0; for (int i = 0; i < ntotal; i++) { ftmp[0] = -FORTRAN(cbkd, CBKD).d[j]; ftmp[1] = -FORTRAN(cbkd, CBKD).d[j+1]; ftmp[2] = -FORTRAN(cbkd, CBKD).d[j+2]; f[i][0] = ftmp[0]; f[i][1] = ftmp[1]; f[i][2] = ftmp[2]; j += 3; } } /* ---------------------------------------------------------------------- */ void PairREAX::allocate() { allocated = 1; int n = atom->ntypes; setflag = memory->create_2d_int_array(n+1,n+1,"pair:setflag"); cutsq = memory->create_2d_double_array(n+1,n+1,"pair:cutsq"); param_list = new ff_params[n+1]; for (int i = 1; i <= n; i++) param_list[i].params = new double[5]; map = new int[n+1]; } /* ---------------------------------------------------------------------- global settings ------------------------------------------------------------------------- */ void PairREAX::settings(int narg, char **arg) { if (narg != 0 && narg !=4) error->all("Illegal pair_style command"); if (narg == 4) { hbcut = force->numeric(arg[0]); - ihbnew = force->numeric(arg[1]); - itripstaball = force->numeric(arg[2]); + ihbnew = static_cast<int> (force->numeric(arg[1])); + itripstaball = static_cast<int> (force->numeric(arg[2])); precision = force->numeric(arg[3]); if (hbcut <= 0.0 || (ihbnew != 0 && ihbnew != 1) || (itripstaball != 0 && itripstaball != 1) || precision <= 0.0) error->all("Illegal pair_style command"); } } /* ---------------------------------------------------------------------- set coeffs for one or more type pairs ------------------------------------------------------------------------- */ void PairREAX::coeff(int narg, char **arg) { if (!allocated) allocate(); if (narg != 3 + atom->ntypes) error->all("Incorrect args for pair coefficients"); // insure I,J args are * * if (strcmp(arg[0],"*") != 0 || strcmp(arg[1],"*") != 0) error->all("Incorrect args for pair coefficients"); // insure filename is ffield.reax if (strcmp(arg[2],"ffield.reax") != 0) error->all("Incorrect args for pair coefficients"); // read args that map atom types to elements in potential file // map[i] = which element the Ith atom type is, -1 if NULL for (int i = 3; i < narg; i++) { if (strcmp(arg[i],"NULL") == 0) { map[i-2] = -1; continue; } map[i-2] = force->inumeric(arg[i]); } int n = atom->ntypes; int count = 0; for (int i = 1; i <= n; i++) for (int j = i; j <= n; j++) { setflag[i][j] = 1; count++; } if (count == 0) error->all("Incorrect args for pair coefficients"); } /* ---------------------------------------------------------------------- init specific to this pair style ------------------------------------------------------------------------- */ void PairREAX::init_style() { if (atom->tag_enable == 0) error->all("Pair style reax requires atom IDs"); if (force->newton_pair == 0) error->all("Pair style reax requires newton pair on"); if (strcmp(update->unit_style,"real") != 0 && comm->me == 0) error->warning("Not using real units with pair reax"); int irequest = neighbor->request(this); neighbor->requests[irequest]->newton = 2; FORTRAN(readc, READC)(); FORTRAN(reaxinit, REAXINIT)(); FORTRAN(ffinpt, FFINPT)(); FORTRAN(tap7th, TAP7TH)(); // turn off read_in by fort.3 in REAX Fortran int ngeofor_tmp = -1; FORTRAN(setngeofor, SETNGEOFOR)(&ngeofor_tmp); if (comm->me == 0) FORTRAN(readgeo, READGEO)(); // initial setup for cutoff radius of VLIST and BLIST in ReaxFF double vlbora; FORTRAN(getswb, GETSWB)(&swb); cutmax=MAX(swb, hbcut); rcutvsq=cutmax*cutmax; FORTRAN(getvlbora, GETVLBORA)(&vlbora); rcutbsq=vlbora*vlbora; // parameters for charge equilibration from ReaxFF input, fort.4 // verify that no LAMMPS type to REAX type mapping was invalid int nelements; FORTRAN(getnso, GETNSO)(&nelements); FORTRAN(getswa, GETSWA)(&swa); double chi, eta, gamma; for (int itype = 1; itype <= atom->ntypes; itype++) { if (map[itype] < 1 || map[itype] > nelements) error->all("Invalid REAX atom type"); chi = FORTRAN(cbkchb, CBKCHB).chi[map[itype]-1]; eta = FORTRAN(cbkchb, CBKCHB).eta[map[itype]-1]; gamma = FORTRAN(cbkchb, CBKCHB).gam[map[itype]-1]; param_list[itype].np = 5; param_list[itype].rcutsq = cutmax; param_list[itype].params[0] = chi; param_list[itype].params[1] = eta; param_list[itype].params[2] = gamma; param_list[itype].params[3] = swa; param_list[itype].params[4] = swb; } taper_setup(); } /* ---------------------------------------------------------------------- init for one type pair i,j and corresponding j,i ------------------------------------------------------------------------- */ double PairREAX::init_one(int i, int j) { return cutmax; } /* ---------------------------------------------------------------------- */ int PairREAX::pack_comm(int n, int *list, double *buf, int pbc_flag, int *pbc) { int i,j,m; m = 0; if (packflag == 0) { for (i = 0; i < n; i++) { j = list[i]; buf[m++] = FORTRAN(cbkabo, CBKABO).abo[j]; } } else { for (i = 0; i < n; i++) { j = list[i]; buf[m++] = wcg[j]; } } return 1; } /* ---------------------------------------------------------------------- */ void PairREAX::unpack_comm(int n, int first, double *buf) { int i,m,last; m = 0; last = first + n; if (packflag == 0) { for (i = first; i < last; i++) FORTRAN(cbkabo, CBKABO).abo[i] = buf[m++]; } else { for (i = first; i < last; i++) wcg[i] = buf[m++]; } } /* ---------------------------------------------------------------------- */ int PairREAX::pack_reverse_comm(int n, int first, double *buf) { int i,k,m,last,size; m = 0; last = first + n; for (i = first; i < last; i++) buf[m++] = wcg[i]; return 1; } /* ---------------------------------------------------------------------- */ void PairREAX::unpack_reverse_comm(int n, int *list, double *buf) { int i,j,k,m; m = 0; for (i = 0; i < n; i++) { j = list[i]; wcg[j] += buf[m++]; } } /* ---------------------------------------------------------------------- charge equilibration routines ------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */ void PairREAX::taper_setup() { double swb2,swa2,swb3,swa3,d1,d7; d1=swb-swa; d7=pow(d1,7); swa2=swa*swa; swa3=swa2*swa; swb2=swb*swb; swb3=swb2*swb; swc7= 20.0e0/d7; swc6= -70.0e0*(swa+swb)/d7; swc5= 84.0e0*(swa2+3.0e0*swa*swb+swb2)/d7; swc4= -35.0e0*(swa3+9.0e0*swa2*swb+9.0e0*swa*swb2+swb3)/d7; swc3= 140.0e0*(swa3*swb+3.0e0*swa2*swb2+swa*swb3)/d7; swc2=-210.0e0*(swa3*swb2+swa2*swb3)/d7; swc1= 140.0e0*swa3*swb3/d7; swc0=(-35.0e0*swa3*swb2*swb2+21.0e0*swa2*swb3*swb2+ 7.0e0*swa*swb3*swb3+swb3*swb3*swb)/d7; } /* ---------------------------------------------------------------------- */ double PairREAX::taper_E(const double &r, const double &r2) { double r3=r2*r; return swc7*r3*r3*r+swc6*r3*r3+swc5*r3*r2+swc4*r2*r2+swc3*r3+swc2*r2+ swc1*r+swc0; } /* ---------------------------------------------------------------------- */ double PairREAX::taper_F(const double &r, const double &r2) { double r3=r2*r; return 7.0e0*swc7*r3*r3+6.0e0*swc6*r3*r2+5.0e0*swc5*r2*r2+ 4.0e0*swc4*r3+3.0e0*swc3*r2+2.0e0*swc2*r+swc1; } /* ---------------------------------------------------------------------- compute current charge distributions based on the charge equilibration ------------------------------------------------------------------------- */ void PairREAX::compute_charge(double &energy_charge_equilibration) { double xitmp, yitmp, zitmp; double xjtmp, yjtmp, zjtmp; int itype, jtype, itag, jtag; int ii, jj, i, j; double delr2, delr_norm, gamt, hulp1, hulp2; double delx, dely, delz; double qsum,qi; int nmatentries; double sw; double rtmp[3]; int inum,jnum; int *ilist; int *jlist; int *numneigh,**firstneigh; double **x = atom->x; double *q = atom->q; int *type = atom->type; int *tag = atom->tag; int nlocal = atom->nlocal; int nghost = atom->nghost; inum = list->inum; ilist = list->ilist; numneigh = list->numneigh; firstneigh = list->firstneigh; // realloc neighbor based arrays if necessary int numneigh_total = 0; for (ii = 0; ii < inum; ii++) numneigh_total += numneigh[ilist[ii]]; if (numneigh_total + 2*nlocal > matmax) { memory->sfree(aval); memory->sfree(acol_ind); matmax = numneigh_total + 2*nlocal; aval = (double *) memory->smalloc(matmax*sizeof(double),"reax:aval"); acol_ind = (int *) memory->smalloc(matmax*sizeof(int),"reax:acol_ind"); } // build linear system nmatentries = 0; for (ii = 0; ii < inum; ii++) { i = ilist[ii]; xitmp = x[i][0]; yitmp = x[i][1]; zitmp = x[i][2]; itype = type[i]; itag = tag[i]; jlist = firstneigh[i]; jnum = numneigh[i]; arow_ptr[i] = nmatentries; aval[nmatentries] = 2.0*param_list[itype].params[1]; acol_ind[nmatentries] = i; nmatentries++; aval[nmatentries] = 1.0; acol_ind[nmatentries] = nlocal + nghost; nmatentries++; for (jj = 0; jj < jnum; jj++) { j = jlist[jj]; xjtmp = x[j][0]; yjtmp = x[j][1]; zjtmp = x[j][2]; jtype = type[j]; jtag = tag[j]; delx = xitmp - xjtmp; dely = yitmp - yjtmp; delz = zitmp - zjtmp; delr2 = delx*delx+dely*dely+delz*delz; // avoid counting local-ghost pair twice since // ReaxFF uses half neigh list with newton off if (j >= nlocal) { if (itag > jtag) { if ((itag+jtag) % 2 == 0) continue; } else if (itag < jtag) { if ((itag+jtag) % 2 == 1) continue; } else { if (zjtmp < zitmp) continue; if (zjtmp == zitmp && yjtmp < yitmp) continue; if (zjtmp == zitmp && yjtmp == yitmp && xjtmp < xitmp) continue; } } // rcutvsq = cutmax*cutmax, in ReaxFF if (delr2 <= rcutvsq) { gamt = sqrt(param_list[itype].params[2]*param_list[jtype].params[2]); delr_norm = sqrt(delr2); sw = taper_E(delr_norm, delr2); hulp1=(delr_norm*delr2+(1.0/(gamt*gamt*gamt))); hulp2=sw*14.40/cbrt(hulp1); aval[nmatentries] = hulp2; acol_ind[nmatentries] = j; nmatentries++; } } } // in this case, we don't use Midpoint method // so, we don't need to consider ghost-ghost interactions // but, need to fill the arow_ptr[] arrays for the ghost atoms for (i = nlocal; i < nlocal+nghost; i++) arow_ptr[i] = nmatentries; arow_ptr[nlocal+nghost] = nmatentries; // add rhs matentries to linear system for (ii =0; ii<inum; ii++) { i = ilist[ii]; itype = type[i]; elcvec[i] = -param_list[itype].params[0]; } for (i = nlocal; i < nlocal+nghost; i++) elcvec[i] = 0.0; // assign current charges to charge vector qsum = 0.0; for (ii = 0; ii < inum; ii++) { i = ilist[ii]; qi = q[i]; ch[i] = qi; if (i < nlocal) qsum += qi; } for (i = nlocal; i < nlocal+nghost; i++) { qi = q[i]; ch[i] = qi; } double qtot; MPI_Allreduce(&qsum,&qtot,1,MPI_DOUBLE,MPI_SUM,world); elcvec[nlocal+nghost] = 0.0; ch[nlocal+nghost] = chpot; // solve the linear system using CG sover charge_reax(nlocal,nghost,ch,aval,acol_ind,arow_ptr,elcvec); // calculate the charge equilibration energy energy_charge_equilibration = 0; // have already updated charge distributions for the current structure for (ii = 0; ii < inum; ii++) { i = ilist[ii]; itype = type[i]; // 23.02 is the ReaxFF conversion from eV to kcal/mol // should really use constants.evfactor ~23.06 // but that would break consistency with serial ReaxFF code // NOTE: this hard-wired real units // if want other units would have to change params[] in file qi = 23.02 * (param_list[itype].params[0]*ch[i]+ param_list[itype].params[1]*ch[i]*ch[i]); energy_charge_equilibration += qi; if (eflag_atom) eatom[i] += qi; } // copy charge vector back to particles from the calculated values for (i = 0; i < nlocal+nghost; i++) q[i] = ch[i]; chpot = ch[nlocal+nghost]; } /* ---------------------------------------------------------------------- */ void PairREAX::charge_reax(const int & nlocal, const int & nghost, double ch[], double aval[], int acol_ind[], int arow_ptr[], double elcvec[]) { double chpottmp, suma; double sumtmp; cg_solve(nlocal,nghost,aval,acol_ind,arow_ptr,ch,elcvec); } /* ---------------------------------------------------------------------- CG solver for linear systems ------------------------------------------------------------------------- */ void PairREAX::cg_solve(const int & nlocal, const int & nghost, double aval[], int acol_ind[], int arow_ptr[], double x[], double b[]) { double one, zero, rho, rho_old, alpha, beta, gamma; int iter, maxiter; int n; double sumtmp; // parallel CG method by A. P. Thompson // distributed (partial) vectors: b, r, q, A // accumulated (full) vectors: x, w, p // r = b-A.x // w = r (ReverseComm + Comm) double *r = rcg; double *w = wcg; double *p = pcg; double *p_old = poldcg; double *q = qcg; n = nlocal+nghost+1; one = 1.0; zero = 0.0; maxiter = 100; for (int i = 0; i < n; i++) w[i] = 0; // construct r = b-Ax sparse_product(n, nlocal, nghost, aval, acol_ind, arow_ptr, x, r); // not using BLAS library for (int i=0; i<n; i++) { r[i] = b[i] - r[i]; w[i] = r[i]; } packflag = 1; comm->reverse_comm_pair(this); comm->forward_comm_pair(this); MPI_Allreduce(&w[n-1], &sumtmp, 1, MPI_DOUBLE, MPI_SUM, world); w[n-1] = sumtmp; rho_old = one; for (iter = 1; iter < maxiter; iter++) { rho = 0.0; for (int i=0; i<nlocal; i++) rho += w[i]*w[i]; MPI_Allreduce(&rho, &sumtmp, 1, MPI_DOUBLE, MPI_SUM, world); rho = sumtmp + w[n-1]*w[n-1]; if (rho < precision) break; for (int i = 0; i<n; i++) p[i] = w[i]; if (iter > 1) { beta = rho/rho_old; for (int i = 0; i<n; i++) p[i] += beta*p_old[i]; } sparse_product(n, nlocal, nghost, aval, acol_ind, arow_ptr, p, q); gamma = 0.0; for (int i=0; i<n; i++) gamma += p[i]*q[i]; MPI_Allreduce(&gamma, &sumtmp, 1, MPI_DOUBLE, MPI_SUM, world); gamma = sumtmp; alpha = rho/gamma; for (int i=0; i<n; i++) { x[i] += alpha*p[i]; r[i] -= alpha*q[i]; w[i] = r[i]; } comm->reverse_comm_pair(this); comm->forward_comm_pair(this); MPI_Allreduce(&w[n-1], &sumtmp, 1, MPI_DOUBLE, MPI_SUM, world); w[n-1] = sumtmp; for (int i=0; i<n; i++) p_old[i] = p[i]; rho_old = rho; } } /* ---------------------------------------------------------------------- sparse maxtrix operations ------------------------------------------------------------------------- */ void PairREAX::sparse_product(const int &n, const int &nlocal, const int &nghost, double aval[], int acol_ind[], int arow_ptr[], double *x, double *r) { int i,j,jj; for (i=0; i<n; i++) r[i] = 0.0; for (i=0; i<nlocal; i++) { r[i] += aval[arow_ptr[i]]*x[i]; for (j=arow_ptr[i]+1; j<arow_ptr[i+1]; j++) { jj = acol_ind[j]; r[i] += aval[j]*x[jj]; r[jj] += aval[j]*x[i]; } } for (i=nlocal; i<nlocal+nghost; i++) for (j=arow_ptr[i]; j<arow_ptr[i+1]; j++) { jj = acol_ind[j]; r[i] += aval[j]*x[jj]; r[jj] += aval[j]*x[i]; } } /* ---------------------------------------------------------------------- memory usage of local atom-based arrays ------------------------------------------------------------------------- */ double PairREAX::memory_usage() { double bytes = nmax * sizeof(int); bytes += 7 * nmax * sizeof(double); bytes += matmax * sizeof(int); bytes += matmax * sizeof(double); return bytes; } diff --git a/src/REAX/pair_reax_fortran.h b/src/REAX/pair_reax_fortran.h index d672c45c5..1900613c6 100644 --- a/src/REAX/pair_reax_fortran.h +++ b/src/REAX/pair_reax_fortran.h @@ -1,209 +1,209 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ // machine-specific C++ -> Fortran calling syntax // It defines the FORTRAN macro for converting variable and function // names from FORTRAN to C. Different compilers do this in different // ways. The default is add an underscore to the lower case string. // Other definitions of the macro can be invoked by defining the // corresponding macro at compile time using -D e.g. -D_IBM // CONS(a,b) should return ab, the concatenation of its arguments. // If compiler is using strict ISO C standards, the ## works. // Otherwise try the old /**/ trick and test. // If that fails, you will need to figure out // a definition for the FORTRAN macro that works on your machine. #if __STDC__ #define CONS(a,b) a##b #else #define CONS(a,b) a/**/b #warning "The following declaration is a test of the CONS macro." #warning "If it fails with an error, pair_reax_fortran.h must be modified by hand." static int my_apples_my_oranges = 1; static int my_applesoroanges = CONS(my_apples,_my_oranges); #endif #ifdef _IBM #define FORTRAN(lcname,ucname) lcname #endif #ifdef _F2C_LINUX #define FORTRAN(lcname,ucname) CONS(lcname,__) #endif #ifndef FORTRAN #define FORTRAN(lcname,ucname) CONS(lcname,_) #endif // hard-wired array sizes set in Fortran library // accesses include file from Fortran library #include "reax_defs.h" class ReaxParams { public: enum {nneighmax=NNEIGHMAXDEF, nat=NATDEF, nattot=NATTOTDEF, nsort=NSORTDEF, mbond=MBONDDEF, nbomax=NBOMAXDEF, }; }; // data structures corresponding to values in Fortran library -extern struct { +extern "C" struct { double abo[ReaxParams::nat]; } FORTRAN(cbkabo,CBKABO); -extern struct { +extern "C" struct { double bo[ReaxParams::nbomax]; } FORTRAN(cbkbo,CBKBO); -extern struct { +extern "C" struct { double c[3*ReaxParams::nat]; double cglobal[3*ReaxParams::nattot]; int itag[ReaxParams::nat]; } FORTRAN(cbkc,CBKC); -extern struct { +extern "C" struct { double ch[ReaxParams::nat]; } FORTRAN(cbkch,CBKCH); -extern struct { +extern "C" struct { double chi[ReaxParams::nsort]; double eta[ReaxParams::nsort]; double gam[ReaxParams::nsort]; } FORTRAN(cbkchb,CBKCHB); -extern struct { +extern "C" struct { double d[3*ReaxParams::nat]; double estrain[ReaxParams::nat]; } FORTRAN(cbkd,CBKD); -extern struct { +extern "C" struct { double atomvirial[6*ReaxParams::nat]; double virial[6]; int Lvirial; int Latomvirial; } FORTRAN(cbkvirial,CBKVIRIAL); -extern struct { +extern "C" struct { int ia[ReaxParams::nat*(ReaxParams::mbond+3)]; int iag[ReaxParams::nat*(ReaxParams::mbond+3)]; } FORTRAN(cbkia,CBKIA); -extern struct { +extern "C" struct { double vlp[ReaxParams::nat]; double dvlpdsbo[ReaxParams::nat]; } FORTRAN(cbklonpar,CBKLONPAR); -extern struct { +extern "C" struct { int nubon1[ReaxParams::nat*(ReaxParams::mbond)]; int nubon2[ReaxParams::nat*(ReaxParams::mbond)]; } FORTRAN(cbknubon2,CBKNUBON2); -extern struct { +extern "C" struct { int nvl1[ReaxParams::nneighmax * ReaxParams::nat]; int nvl2[ReaxParams::nneighmax * ReaxParams::nat]; int nvpair; int nvlself; } FORTRAN(cbkpairs,CBKPAIRS); -extern struct { +extern "C" struct { int nvlbo[ReaxParams::nneighmax * ReaxParams::nat]; } FORTRAN(cbknvlbo,CBKNVLBO); -extern struct { +extern "C" struct { int nvlown[ReaxParams::nneighmax * ReaxParams::nat]; } FORTRAN(cbknvlown,CBKNVLOWN); -extern struct { +extern "C" struct { char qa[20*ReaxParams::nattot+10]; } FORTRAN(cbkqa,CBKQA); -extern struct { +extern "C" struct { double eb; double eoop; double epen; double estrc; double deda[3]; double pressu; double efi; double elp; double emol; double ea; double eres; double et; double eradbo; double ev; double eco; double ecoa; double ehb; double sw; double ew; double ep; double ekin; } FORTRAN(cbkenergies,CBKENERGIES); -extern struct { +extern "C" struct { double tset; double dseed; double tempmd; double ts2; double ts22; int nmolo; int nmolo5; int nbon; int na; int namov; int na_local; } FORTRAN(rsmall,RSMALL); // external routines provided by Fortran library extern "C" void FORTRAN(readc,READC)(); extern "C" void FORTRAN(reaxinit,REAXINIT)(); extern "C" void FORTRAN(ffinpt,FFINPT)(); extern "C" void FORTRAN(tap7th,TAP7TH)(); extern "C" void FORTRAN(taper,TAPER)(double*,double*); extern "C" void FORTRAN(readgeo,READGEO)(); extern "C" void FORTRAN(srtatom,SRTATOM)(); extern "C" void FORTRAN(vlist,VLIST) (); extern "C" void FORTRAN(srtbon1,SRTBON1)(int*,int*,double*,int*,int*); extern "C" void FORTRAN(molec,MOLEC)(); extern "C" void FORTRAN(encalc,ENCALC)(); extern "C" void FORTRAN(getswb,GETSWB)(double*); extern "C" void FORTRAN(getswa,GETSWA)(double*); extern "C" void FORTRAN(getvrange,GET_VRANGE)(double*); extern "C" void FORTRAN(getnvlist,GET_NVLIST)(int*); extern "C" void FORTRAN(getvlbora,GETVLBORA)(double*); extern "C" void FORTRAN(cgsolve,CGSOLVE) (int*,double*,int*,double*,double*,int*); extern "C" void FORTRAN(getnval,GETNVAL)(int*); extern "C" void FORTRAN(getntor,GETNTOR)(int*); extern "C" void FORTRAN(getnhb,GETNHB)(int*); extern "C" void FORTRAN(getnbonall,GETNBONALL)(int*); extern "C" void FORTRAN(getnneighmax,GETNNEIGHMAX)(int*); extern "C" void FORTRAN(getnat,GETNAT)(int*); extern "C" void FORTRAN(getnattot,GETNATTOT)(int*); extern "C" void FORTRAN(getnsort,GETNSORT)(int*); extern "C" void FORTRAN(getmbond,GETMBOND)(int*); extern "C" void FORTRAN(getnso,GETNSO)(int*); extern "C" void FORTRAN(setngeofor,SETNGEOFOR)(int*); extern "C" void FORTRAN(mdsav,MDSAV)(int*); extern "C" void FORTRAN(getnsbmax,GETNSBMAX)(int*); extern "C" void FORTRAN(getnsbma2,GETNSBMA2)(int*); extern "C" void FORTRAN(getcutof3,GETCUTOF3)(double*); diff --git a/src/REPLICA/fix_event.h b/src/REPLICA/fix_event.h index 73df5d157..41ce7f261 100644 --- a/src/REPLICA/fix_event.h +++ b/src/REPLICA/fix_event.h @@ -1,52 +1,51 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ #ifndef LMP_FIX_EVENT_H #define LMP_FIX_EVENT_H #include "fix.h" namespace LAMMPS_NS { class FixEvent : public Fix { public: - FixEvent(class LAMMPS *, int, char **); virtual ~FixEvent()=0; // Use destructor to make base class virtual int setmask(); double memory_usage(); void grow_arrays(int); void copy_arrays(int, int); int pack_exchange(int, double *); int unpack_exchange(int, double *); virtual void write_restart(FILE *); virtual void restart(char *); // methods specific to FixEvent void store_event(); // store quenched atoms void restore_event(); // restore quenched atoms void store_state(); // store hot atoms void restore_state(); // restore hot atoms private: double **xevent; // atom coords at last event double **xold; // atom coords for reset/restore double **vold; // atom vels for reset/restore int *imageold; // image flags for reset/restore }; } #endif diff --git a/src/REPLICA/fix_event_prd.cpp b/src/REPLICA/fix_event_prd.cpp index ad606d9ab..3fba4da90 100644 --- a/src/REPLICA/fix_event_prd.cpp +++ b/src/REPLICA/fix_event_prd.cpp @@ -1,100 +1,101 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- Contributing author: Mike Brown (SNL) ------------------------------------------------------------------------- */ #include "stdlib.h" #include "string.h" #include "fix_event_prd.h" +#include "lmptype.h" #include "atom.h" #include "update.h" #include "domain.h" #include "neighbor.h" #include "comm.h" #include "universe.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; /* ---------------------------------------------------------------------- */ FixEventPRD::FixEventPRD(LAMMPS *lmp, int narg, char **arg) : FixEvent(lmp, narg, arg) { if (narg != 3) error->all("Illegal fix event command"); restart_global = 1; event_number = 0; event_timestep = update->ntimestep; clock = 0; } /* ---------------------------------------------------------------------- save current atom coords as an event (via call to base class) called when an event occurs in some replica set event_timestep = when event occurred in a particular replica update clock = elapsed time since last event, across all replicas ------------------------------------------------------------------------- */ -void FixEventPRD::store_event_prd(int timestep, int delta_clock) +void FixEventPRD::store_event_prd(bigint ntimestep, int delta_clock) { store_event(); - event_timestep = timestep; + event_timestep = ntimestep; clock += delta_clock; event_number++; } /* ---------------------------------------------------------------------- pack entire state of Fix into one write ------------------------------------------------------------------------- */ void FixEventPRD::write_restart(FILE *fp) { int n = 0; double list[6]; list[n++] = event_number; list[n++] = event_timestep; list[n++] = clock; list[n++] = replica_number; list[n++] = correlated_event; list[n++] = ncoincident; if (comm->me == 0) { int size = n * sizeof(double); fwrite(&size,sizeof(int),1,fp); fwrite(list,sizeof(double),n,fp); } } /* ---------------------------------------------------------------------- use state info from restart file to restart the Fix ------------------------------------------------------------------------- */ void FixEventPRD::restart(char *buf) { int n = 0; double *list = (double *) buf; event_number = static_cast<int> (list[n++]); event_timestep = static_cast<int> (list[n++]); clock = static_cast<int> (list[n++]); replica_number = static_cast<int> (list[n++]); correlated_event = static_cast<int> (list[n++]); ncoincident = static_cast<int> (list[n++]); } diff --git a/src/REPLICA/fix_event_prd.h b/src/REPLICA/fix_event_prd.h index fa97ead78..18f77b324 100644 --- a/src/REPLICA/fix_event_prd.h +++ b/src/REPLICA/fix_event_prd.h @@ -1,53 +1,54 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain 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(EVENT/PRD,FixEventPRD) #else #ifndef LMP_FIX_EVENT_PRD_H #define LMP_FIX_EVENT_PRD_H #include "fix_event.h" +#include "lmptype.h" namespace LAMMPS_NS { class FixEventPRD : public FixEvent { public: int event_number; // event counter - int event_timestep; // timestep of last event on any replica + bigint event_timestep; // timestep of last event on any replica int clock; // total elapsed timesteps across all replicas int replica_number; // replica where last event occured int correlated_event; // 1 if last event was correlated, 0 otherwise int ncoincident; // # of simultaneous events on different replicas FixEventPRD(class LAMMPS *, int, char **); ~FixEventPRD() {} void write_restart(FILE *); void restart(char *); // methods specific to FixEventPRD, invoked by PRD - void store_event_prd(int, int); + void store_event_prd(bigint, int); private: }; } #endif #endif diff --git a/src/REPLICA/fix_event_tad.cpp b/src/REPLICA/fix_event_tad.cpp index 5f0dcd069..108668b63 100644 --- a/src/REPLICA/fix_event_tad.cpp +++ b/src/REPLICA/fix_event_tad.cpp @@ -1,94 +1,95 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- Contributing author: Mike Brown (SNL) ------------------------------------------------------------------------- */ #include "stdlib.h" #include "string.h" #include "fix_event_tad.h" +#include "lmptype.h" #include "atom.h" #include "update.h" #include "domain.h" #include "neighbor.h" #include "comm.h" #include "universe.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; /* ---------------------------------------------------------------------- */ FixEventTAD::FixEventTAD(LAMMPS *lmp, int narg, char **arg) : FixEvent(lmp, narg, arg) { if (narg != 3) error->all("Illegal fix event command"); restart_global = 1; event_number = 0; event_timestep = update->ntimestep; tlo = 0.0; ebarrier = 0.0; } /* ---------------------------------------------------------------------- save current atom coords as an event (via call to base class) called when an event occurs in some replica set event_timestep = when event occurred ------------------------------------------------------------------------- */ -void FixEventTAD::store_event_tad(int timestep) +void FixEventTAD::store_event_tad(bigint ntimestep) { store_event(); - event_timestep = timestep; + event_timestep = ntimestep; } /* ---------------------------------------------------------------------- pack entire state of Fix into one write ------------------------------------------------------------------------- */ void FixEventTAD::write_restart(FILE *fp) { int n = 0; double list[4]; list[n++] = event_number; list[n++] = event_timestep; list[n++] = tlo; list[n++] = ebarrier; if (comm->me == 0) { int size = n * sizeof(double); fwrite(&size,sizeof(int),1,fp); fwrite(list,sizeof(double),n,fp); } } /* ---------------------------------------------------------------------- use state info from restart file to restart the Fix ------------------------------------------------------------------------- */ void FixEventTAD::restart(char *buf) { int n = 0; double *list = (double *) buf; event_number = static_cast<int> (list[n++]); event_timestep = static_cast<int> (list[n++]); tlo = static_cast<double> (list[n++]); ebarrier = list[n++]; } diff --git a/src/REPLICA/fix_event_tad.h b/src/REPLICA/fix_event_tad.h index 5bf937e22..2b6067e9e 100644 --- a/src/REPLICA/fix_event_tad.h +++ b/src/REPLICA/fix_event_tad.h @@ -1,51 +1,52 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain 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(EVENT/TAD,FixEventTAD) #else #ifndef LMP_FIX_EVENT_TAD_H #define LMP_FIX_EVENT_TAD_H #include "fix_event.h" +#include "lmptype.h" namespace LAMMPS_NS { class FixEventTAD : public FixEvent { public: int event_number; // event counter - int event_timestep; // timestep of last event + bigint event_timestep; // timestep of last event double tlo; // event time at low temperature double ebarrier; // energy barrier for this event FixEventTAD(class LAMMPS *, int, char **); ~FixEventTAD() {} void write_restart(FILE *); void restart(char *); // methods specific to FixEventTAD, invoked by TAD - void store_event_tad(int); + void store_event_tad(bigint); private: }; } #endif #endif diff --git a/src/REPLICA/neb.cpp b/src/REPLICA/neb.cpp index e44c95f7f..f021a1f7f 100644 --- a/src/REPLICA/neb.cpp +++ b/src/REPLICA/neb.cpp @@ -1,507 +1,510 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ #include "mpi.h" #include "math.h" #include "stdlib.h" #include "string.h" #include "neb.h" +#include "lmptype.h" #include "universe.h" #include "atom.h" #include "update.h" #include "domain.h" #include "min.h" #include "modify.h" #include "fix.h" #include "fix_neb.h" #include "output.h" #include "thermo.h" #include "finish.h" #include "timer.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; #define CHUNK 1000 #define MAXLINE 256 /* ---------------------------------------------------------------------- */ NEB::NEB(LAMMPS *lmp) : Pointers(lmp) {} /* ---------------------------------------------------------------------- internal NEB constructor ------------------------------------------------------------------------- */ NEB::NEB(LAMMPS *lmp, double etol_in, double ftol_in, int n1steps_in, int n2steps_in, int nevery_in, double *buf_init, double *buf_final) : Pointers(lmp) { double delx,dely,delz; etol = etol_in; ftol = ftol_in; n1steps = n1steps_in; n2steps = n2steps_in; nevery = nevery_in; // replica info nreplica = universe->nworlds; ireplica = universe->iworld; me_universe = universe->me; uworld = universe->uworld; MPI_Comm_rank(world,&me); // generate linear interpolate replica double fraction = ireplica/(nreplica-1.0); double **x = atom->x; int nlocal = atom->nlocal; int ii = 0; for (int i = 0; i < nlocal; i++) { delx = buf_final[ii] - buf_init[ii]; dely = buf_final[ii+1] - buf_init[ii+1]; delz = buf_final[ii+2] - buf_init[ii+2]; domain->minimum_image(delx,dely,delz); x[i][0] = buf_init[ii] + fraction*delx; x[i][1] = buf_init[ii+1] + fraction*dely; x[i][2] = buf_init[ii+2] + fraction*delz; ii += 3; } } /* ---------------------------------------------------------------------- */ NEB::~NEB() { MPI_Comm_free(&roots); memory->destroy_2d_double_array(all); delete [] rdist; } /* ---------------------------------------------------------------------- perform NEB on multiple replicas ------------------------------------------------------------------------- */ void NEB::command(int narg, char **arg) { if (domain->box_exist == 0) error->all("NEB command before simulation box is defined"); if (narg != 6) error->universe_all("Illegal NEB command"); etol = atof(arg[0]); ftol = atof(arg[1]); n1steps = atoi(arg[2]); n2steps = atoi(arg[3]); nevery = atoi(arg[4]); infile = arg[5]; // error checks if (etol < 0.0) error->all("Illegal NEB command"); if (ftol < 0.0) error->all("Illegal NEB command"); if (nevery == 0) error->universe_all("Illegal NEB command"); if (n1steps % nevery || n2steps % nevery) error->universe_all("Illegal NEB command"); // replica info nreplica = universe->nworlds; ireplica = universe->iworld; me_universe = universe->me; uworld = universe->uworld; MPI_Comm_rank(world,&me); // read in file of final state atom coords and reset my coords readfile(infile); // run the NEB calculation run(); } /* ---------------------------------------------------------------------- run NEB on multiple replicas ------------------------------------------------------------------------- */ void NEB::run() { // create MPI communicator for root proc from each world int color; if (me == 0) color = 0; else color = 1; MPI_Comm_split(uworld,color,0,&roots); // error checks if (nreplica == 1) error->all("Cannot use NEB with a single replica"); if (nreplica != universe->nprocs) error->all("Can only use NEB with 1-processor replicas"); if (atom->sortfreq > 0) error->all("Cannot use NEB with atom_modify sort enabled"); if (atom->map_style == 0) error->all("Cannot use NEB unless atom map exists"); int ineb,idamp; for (ineb = 0; ineb < modify->nfix; ineb++) if (strcmp(modify->fix[ineb]->style,"neb") == 0) break; if (ineb == modify->nfix) error->all("NEB requires use of fix neb"); fneb = (FixNEB *) modify->fix[ineb]; nall = 4; all = memory->create_2d_double_array(nreplica,nall,"neb:all"); rdist = new double[nreplica]; // initialize LAMMPS update->whichflag = 2; update->etol = etol; update->ftol = ftol; update->multireplica = 1; lmp->init(); if (update->minimize->searchflag) error->all("NEB requires damped dynamics minimizer"); // setup regular NEB minimization if (me_universe == 0 && universe->uscreen) fprintf(universe->uscreen,"Setting up regular NEB ...\n"); update->beginstep = update->firststep = update->ntimestep; update->endstep = update->laststep = update->firststep + n1steps; update->nsteps = n1steps; update->max_eval = n1steps; update->minimize->setup(); if (me_universe == 0) { if (universe->uscreen) fprintf(universe->uscreen,"Step MaxReplicaForce MaxAtomForce " "GradV0 GradV1 GradVc " "EBF EBR RDT " "RD1 PE1 RD2 PE2 ... RDN PEN\n"); if (universe->ulogfile) fprintf(universe->ulogfile,"Step MaxReplicaForce MaxAtomForce " "GradV0 GradV1 GradVc " "EBF EBR RDT " "RD1 PE1 RD2 PE2 ... RDN PEN\n"); } print_status(); // perform regular NEB for n1steps or until replicas converge // retrieve PE values from fix NEB and print every nevery iterations // break induced if converged // damped dynamic min styles insure all replicas converge together int flag,flagall; timer->barrier_start(TIME_LOOP); while (update->minimize->niter < n1steps) { update->minimize->run(nevery); print_status(); if (update->minimize->stop_condition) break; } timer->barrier_stop(TIME_LOOP); update->minimize->cleanup(); Finish finish(lmp); finish.end(1); // switch fix NEB to climbing mode // top = replica that becomes hill climber double vmax = all[0][0]; int top = 0; for (int m = 1; m < nreplica; m++) if (vmax < all[m][0]) { vmax = all[m][0]; top = m; } // setup climbing NEB minimization // must reinitialize minimizer so it re-creates its fix MINIMIZE if (me_universe == 0 && universe->uscreen) fprintf(universe->uscreen,"Setting up climbing ...\n"); if (me_universe == 0) { if (universe->uscreen) fprintf(universe->uscreen,"Climbing replica = %d\n",top+1); if (universe->ulogfile) fprintf(universe->ulogfile,"Climbing replica = %d\n",top+1); } update->beginstep = update->firststep = update->ntimestep; update->endstep = update->laststep = update->firststep + n2steps; update->nsteps = n2steps; update->max_eval = n2steps; update->minimize->init(); fneb->rclimber = top; update->minimize->setup(); if (me_universe == 0) { if (universe->uscreen) fprintf(universe->uscreen,"Step MaxReplicaForce MaxAtomForce " "GradV0 GradV1 GradVc " "EBF EBR RDT " "RD1 PE1 RD2 PE2 ... RDN PEN\n"); if (universe->ulogfile) fprintf(universe->ulogfile,"Step MaxReplicaForce MaxAtomForce " "GradV0 GradV1 GradVc " "EBF EBR RDT " "RD1 PE1 RD2 PE2 ... RDN PEN\n"); } print_status(); // perform climbing NEB for n2steps or until replicas converge // retrieve PE values from fix NEB and print every nevery iterations // break induced if converged // damped dynamic min styles insure all replicas converge together timer->barrier_start(TIME_LOOP); while (update->minimize->niter < n2steps) { update->minimize->run(nevery); print_status(); if (update->minimize->stop_condition) break; } timer->barrier_stop(TIME_LOOP); update->minimize->cleanup(); finish.end(1); update->whichflag = 0; update->multireplica = 0; update->firststep = update->laststep = 0; update->beginstep = update->endstep = 0; } /* ---------------------------------------------------------------------- read target coordinates from file, store with appropriate atom adjust coords of each atom based on ireplica new coord = replica fraction between current and final state ------------------------------------------------------------------------- */ void NEB::readfile(char *file) { if (me_universe == 0) { if (screen) fprintf(screen,"Reading NEB coordinate file %s ...\n",file); open(file); } double fraction = ireplica/(nreplica-1.0); double **x = atom->x; int *image = atom->image; int nlocal = atom->nlocal; char *buffer = new char[CHUNK*MAXLINE]; char *ptr,*next,*bufptr; int i,m,nlines,tag; double xx,yy,zz,delx,dely,delz; int firstline = 1; int ncount = 0; int eof = 0; while (!eof) { if (me_universe == 0) { m = 0; for (nlines = 0; nlines < CHUNK; nlines++) { ptr = fgets(&buffer[m],MAXLINE,fp); if (ptr == NULL) break; m += strlen(&buffer[m]); } if (ptr == NULL) eof = 1; buffer[m++] = '\n'; } MPI_Bcast(&eof,1,MPI_INT,0,uworld); MPI_Bcast(&nlines,1,MPI_INT,0,uworld); MPI_Bcast(&m,1,MPI_INT,0,uworld); MPI_Bcast(buffer,m,MPI_CHAR,0,uworld); bufptr = buffer; for (i = 0; i < nlines; i++) { next = strchr(bufptr,'\n'); *next = '\0'; if (firstline) { if (atom->count_words(bufptr) == 4) firstline = 0; else error->all("Incorrect format in NEB coordinate file"); } sscanf(bufptr,"%d %lg %lg %lg",&tag,&xx,&yy,&zz); // adjust atom coord based on replica fraction // ignore image flags of final x // new x is displacement from old x // if final x is across periodic boundary: // new x may be outside box // will be remapped back into box when simulation starts // its image flags will be adjusted appropriately m = atom->map(tag); if (m >= 0 && m < nlocal) { delx = xx - x[m][0]; dely = yy - x[m][1]; delz = zz - x[m][2]; domain->minimum_image(delx,dely,delz); x[m][0] += fraction*delx; x[m][1] += fraction*dely; x[m][2] += fraction*delz; ncount++; } bufptr = next + 1; } } // clean up delete [] buffer; if (me_universe == 0) { if (compressed) pclose(fp); else fclose(fp); } } /* ---------------------------------------------------------------------- universe proc 0 opens NEB data file test if gzipped ------------------------------------------------------------------------- */ void NEB::open(char *file) { compressed = 0; char *suffix = file + strlen(file) - 3; if (suffix > file && strcmp(suffix,".gz") == 0) compressed = 1; if (!compressed) fp = fopen(file,"r"); else { #ifdef LAMMPS_GZIP char gunzip[128]; sprintf(gunzip,"gunzip -c %s",file); fp = popen(gunzip,"r"); #else error->one("Cannot open gzipped file"); #endif } if (fp == NULL) { char str[128]; sprintf(str,"Cannot open file %s",file); error->one(str); } } /* ---------------------------------------------------------------------- query fix NEB for PE of each replica proc 0 prints current NEB status ------------------------------------------------------------------------- */ void NEB::print_status() { double fnorm2 = sqrt(update->minimize->fnorm_sqr()); double fmaxreplica; MPI_Allreduce(&fnorm2,&fmaxreplica,1,MPI_DOUBLE,MPI_MAX,roots); double fnorminf = update->minimize->fnorm_inf(); double fmaxatom; MPI_Allreduce(&fnorminf,&fmaxatom,1,MPI_DOUBLE,MPI_MAX,roots); double one[4]; one[0] = fneb->veng; one[1] = fneb->plen; one[2] = fneb->nlen; one[nall-1] = fneb->gradvnorm; if (output->thermo->normflag) one[0] /= atom->natoms; if (me == 0) MPI_Allgather(one,nall,MPI_DOUBLE,&all[0][0],nall,MPI_DOUBLE,roots); rdist[0] = 0.0; for (int i = 1; i < nreplica; i++) rdist[i] = rdist[i-1] + all[i][1]; double endpt = rdist[nreplica-1] = rdist[nreplica-2] + all[nreplica-2][2]; for (int i = 1; i < nreplica; i++) rdist[i] /= endpt; // look up GradV for the initial, final, and climbing replicas // these are identical to fnorm2, but to be safe we // take them straight from fix_neb double gradvnorm0, gradvnorm1, gradvnormc; int irep; irep = 0; gradvnorm0 = all[irep][3]; irep = nreplica-1; gradvnorm1 = all[irep][3]; irep = fneb->rclimber; if (irep > -1) { gradvnormc = all[irep][3]; ebf = all[irep][0]-all[0][0]; ebr = all[irep][0]-all[nreplica-1][0]; } else { double vmax = all[0][0]; int top = 0; for (int m = 1; m < nreplica; m++) if (vmax < all[m][0]) { vmax = all[m][0]; top = m; } irep = top; gradvnormc = all[irep][3]; ebf = all[irep][0]-all[0][0]; ebr = all[irep][0]-all[nreplica-1][0]; } if (me_universe == 0) { + char fstr[32]; + sprintf(fstr,"%s %%g %%g ",BIGINT_FORMAT); if (universe->uscreen) { - fprintf(universe->uscreen,"%d %g %g ",update->ntimestep, + fprintf(universe->uscreen,fstr,update->ntimestep, fmaxreplica,fmaxatom); fprintf(universe->uscreen,"%g %g %g ", gradvnorm0,gradvnorm1,gradvnormc); fprintf(universe->uscreen,"%g %g %g ",ebf,ebr,endpt); for (int i = 0; i < nreplica; i++) fprintf(universe->uscreen,"%g %g ",rdist[i],all[i][0]); fprintf(universe->uscreen,"\n"); } if (universe->ulogfile) { - fprintf(universe->ulogfile,"%d %g %g ",update->ntimestep, + fprintf(universe->ulogfile,fstr,update->ntimestep, fmaxreplica,fmaxatom); fprintf(universe->ulogfile,"%g %g %g ", gradvnorm0,gradvnorm1,gradvnormc); fprintf(universe->ulogfile,"%g %g %g ",ebf,ebr,endpt); for (int i = 0; i < nreplica; i++) fprintf(universe->ulogfile,"%g %g ",rdist[i],all[i][0]); fprintf(universe->ulogfile,"\n"); fflush(universe->ulogfile); } } } diff --git a/src/REPLICA/prd.cpp b/src/REPLICA/prd.cpp index e11dae149..07ca60580 100644 --- a/src/REPLICA/prd.cpp +++ b/src/REPLICA/prd.cpp @@ -1,809 +1,812 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- Contributing author: Mike Brown (SNL) ------------------------------------------------------------------------- */ #include "mpi.h" #include "math.h" #include "stdlib.h" #include "string.h" #include "prd.h" #include "lmptype.h" #include "universe.h" #include "update.h" #include "atom.h" #include "domain.h" #include "region.h" #include "comm.h" #include "velocity.h" #include "integrate.h" #include "min.h" #include "neighbor.h" #include "modify.h" #include "compute.h" #include "fix.h" #include "fix_event_prd.h" #include "force.h" #include "pair.h" #include "random_park.h" #include "random_mars.h" #include "output.h" #include "dump.h" #include "finish.h" #include "timer.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; /* ---------------------------------------------------------------------- */ PRD::PRD(LAMMPS *lmp) : Pointers(lmp) {} /* ---------------------------------------------------------------------- perform PRD simulation on one or more replicas ------------------------------------------------------------------------- */ void PRD::command(int narg, char **arg) { int flag,ireplica; // error checks if (domain->box_exist == 0) error->all("PRD command before simulation box is defined"); if (universe->nworlds != universe->nprocs && atom->map_style == 0) error->all("Cannot use PRD with multi-processor replicas " "unless atom map exists"); if (universe->nworlds == 1 && comm->me == 0) error->warning("Running PRD with only one replica"); if (narg < 7) error->universe_all("Illegal prd command"); nsteps = atoi(arg[0]); t_event = atoi(arg[1]); n_dephase = atoi(arg[2]); t_dephase = atoi(arg[3]); t_corr = atoi(arg[4]); char id_compute[strlen(arg[5])+1]; strcpy(id_compute,arg[5]); int seed = atoi(arg[6]); options(narg-7,&arg[7]); // total # of timesteps must be multiple of t_event if (t_event <= 0) error->universe_all("Invalid t_event in prd command"); if (nsteps % t_event) error->universe_all("PRD nsteps must be multiple of t_event"); if (t_corr % t_event) error->universe_all("PRD t_corr must be multiple of t_event"); // local storage int me_universe = universe->me; int nprocs_universe = universe->nprocs; int nreplica = universe->nworlds; int iworld = universe->iworld; MPI_Comm_rank(world,&me); MPI_Comm_size(world,&nprocs); // comm_replica = communicator between same proc across replicas // not used if replicas have unequal number of procs // equal_size_replicas = 1 if all replicas have same # of procs int color = me; MPI_Comm_split(universe->uworld,color,0,&comm_replica); flag = 0; if (nreplica*nprocs == nprocs_universe) flag = 1; MPI_Allreduce(&flag,&equal_size_replicas,1,MPI_INT,MPI_MIN,universe->uworld); // workspace for inter-replica communication via gathers natoms = atom->natoms; displacements = NULL; tagall = NULL; xall = NULL; imageall = NULL; if (nreplica != nprocs_universe) { displacements = new int[nprocs]; tagall = (int *) memory->smalloc(natoms*sizeof(int),"prd:tagall"); xall = memory->create_2d_double_array(natoms,3,"prd:xall"); imageall = (int *) memory->smalloc(natoms*sizeof(int),"prd:imageall"); } // random_select = same RNG for each replica for multiple event selection // random_dephase = unique RNG for each replica for dephasing random_select = new RanPark(lmp,seed); random_dephase = new RanMars(lmp,seed+iworld); // create ComputeTemp class to monitor temperature char **args = new char*[3]; args[0] = (char *) "prd_temp"; args[1] = (char *) "all"; args[2] = (char *) "temp"; modify->add_compute(3,args); temperature = modify->compute[modify->ncompute-1]; // create Velocity class for velocity creation in dephasing // pass it temperature compute, loop_setting, dist_setting settings atom->check_mass(); velocity = new Velocity(lmp); velocity->init_external("all"); args[0] = (char *) "temp"; args[1] = (char *) "prd_temp"; velocity->options(2,args); args[0] = (char *) "loop"; args[1] = (char *) loop_setting; if (loop_setting) velocity->options(2,args); args[0] = (char *) "dist"; args[1] = (char *) dist_setting; if (dist_setting) velocity->options(2,args); // create FixEventPRD class to store event and pre-quench states args[0] = (char *) "prd_event"; args[1] = (char *) "all"; args[2] = (char *) "EVENT/PRD"; modify->add_fix(3,args); fix_event = (FixEventPRD *) modify->fix[modify->nfix-1]; // create Finish for timing output finish = new Finish(lmp); // string clean-up delete [] args; delete [] loop_setting; delete [] dist_setting; // assign FixEventPRD to event-detection compute // necessary so it will know atom coords at last event int icompute = modify->find_compute(id_compute); if (icompute < 0) error->all("Could not find compute ID for PRD"); compute_event = modify->compute[icompute]; compute_event->reset_extra_compute_fix("prd_event"); // reset reneighboring criteria since will perform minimizations neigh_every = neighbor->every; neigh_delay = neighbor->delay; neigh_dist_check = neighbor->dist_check; if (neigh_every != 1 || neigh_delay != 0 || neigh_dist_check != 1) { if (me == 0) error->warning("Resetting reneighboring criteria during PRD"); } neighbor->every = 1; neighbor->delay = 0; neighbor->dist_check = 1; // initialize PRD as if one long dynamics run update->whichflag = 1; update->nsteps = nsteps; update->beginstep = update->firststep = update->ntimestep; update->endstep = update->laststep = update->firststep + nsteps; update->restrict_output = 1; lmp->init(); // init minimizer settings and minimizer itself update->etol = etol; update->ftol = ftol; update->max_eval = maxeval; update->minimize->init(); // cannot use PRD with time-dependent fixes or regions or atom sorting for (int i = 0; i < modify->nfix; i++) if (modify->fix[i]->time_depend) error->all("Cannot use PRD with a time-dependent fix defined"); for (int i = 0; i < domain->nregion; i++) if (domain->regions[i]->dynamic_check()) error->all("Cannot use PRD with a time-dependent region defined"); if (atom->sortfreq > 0) error->all("Cannot use PRD with atom_modify sort enabled"); // perform PRD simulation if (me_universe == 0 && universe->uscreen) fprintf(universe->uscreen,"Setting up PRD ...\n"); if (me_universe == 0) { if (universe->uscreen) fprintf(universe->uscreen,"Step CPU Clock Event " "Correlated Coincident Replica\n"); if (universe->ulogfile) fprintf(universe->ulogfile,"Step CPU Clock Event " "Correlated Coincident Replica\n"); } // store hot state and quenched event for replica 0 // use share_event() to copy that info to all replicas // this insures all start from same place // need this line if quench() does only setup_minimal() // update->minimize->setup(); fix_event->store_state(); quench(); ncoincident = 0; share_event(0,0); timer->barrier_start(TIME_LOOP); time_start = timer->array[TIME_LOOP]; log_event(); // do full init/setup since are starting all replicas after event // replica 0 bcasts temp to all replicas if temp_dephase is not set update->whichflag = 1; lmp->init(); update->integrate->setup(); if (temp_flag == 0) { if (universe->iworld == 0) temp_dephase = temperature->compute_scalar(); MPI_Bcast(&temp_dephase,1,MPI_DOUBLE,universe->root_proc[0], universe->uworld); } // main loop: look for events until out of time // (1) dephase independently on each proc after event // (2) loop: dynamics, store state, quench, check event, restore state // (3) share and record event nbuild = ndanger = 0; time_dephase = time_dynamics = time_quench = time_comm = time_output = 0.0; timer->barrier_start(TIME_LOOP); time_start = timer->array[TIME_LOOP]; while (update->ntimestep < update->endstep) { dephase(); ireplica = -1; while (update->ntimestep < update->endstep) { dynamics(); fix_event->store_state(); quench(); ireplica = check_event(); if (ireplica >= 0) break; fix_event->restore_state(); } if (ireplica < 0) break; // potentially more efficient for correlated events if don't // share until correlated check has completed // this will complicate the dump (always on replica 0) share_event(ireplica,1); log_event(); int restart_flag = 0; if (output->restart_every && universe->iworld == 0) if (fix_event->event_number % output->restart_every == 0) restart_flag = 1; // correlated event loop // other procs could be dephasing during this time int corr_endstep = update->ntimestep + t_corr; while (update->ntimestep < corr_endstep) { if (update->ntimestep == update->endstep) { restart_flag = 0; break; } dynamics(); fix_event->store_state(); quench(); int corr_event_check = check_event(ireplica); if (corr_event_check >= 0) { share_event(ireplica,2); log_event(); corr_endstep = update->ntimestep + t_corr; } else fix_event->restore_state(); } // full init/setup since are starting all replicas after event // event replica bcasts temp to all replicas if temp_dephase is not set update->whichflag = 1; lmp->init(); update->integrate->setup(); timer->barrier_start(TIME_LOOP); if (t_corr > 0) replicate(ireplica); if (temp_flag == 0) { if (ireplica == universe->iworld) temp_dephase = temperature->compute_scalar(); MPI_Bcast(&temp_dephase,1,MPI_DOUBLE,universe->root_proc[ireplica], universe->uworld); } timer->barrier_stop(TIME_LOOP); time_comm += timer->array[TIME_LOOP]; // write restart file of hot coords if (restart_flag) { timer->barrier_start(TIME_LOOP); output->write_restart(update->ntimestep); timer->barrier_stop(TIME_LOOP); time_output += timer->array[TIME_LOOP]; } } // set total timers and counters so Finish() will process them timer->array[TIME_LOOP] = time_start; timer->barrier_stop(TIME_LOOP); timer->array[TIME_PAIR] = time_dephase; timer->array[TIME_BOND] = time_dynamics; timer->array[TIME_KSPACE] = time_quench; timer->array[TIME_COMM] = time_comm; timer->array[TIME_OUTPUT] = time_output; neighbor->ncalls = nbuild; neighbor->ndanger = ndanger; if (me_universe == 0) { + char str[128]; + sprintf(str,"Loop time of %%g on %%d procs for %%d steps with %s atoms\n", + BIGINT_FORMAT); if (universe->uscreen) - fprintf(universe->uscreen, - "Loop time of %g on %d procs for %d steps with %lu atoms\n", + fprintf(universe->uscreen,str, timer->array[TIME_LOOP],nprocs_universe,nsteps,atom->natoms); if (universe->ulogfile) - fprintf(universe->ulogfile, - "Loop time of %g on %d procs for %d steps with %lu atoms\n", + fprintf(universe->ulogfile,str, timer->array[TIME_LOOP],nprocs_universe,nsteps,atom->natoms); } finish->end(2); update->whichflag = 0; update->firststep = update->laststep = 0; update->beginstep = update->endstep = 0; update->restrict_output = 0; // reset reneighboring criteria neighbor->every = neigh_every; neighbor->delay = neigh_delay; neighbor->dist_check = neigh_dist_check; // clean up delete [] displacements; memory->sfree(tagall); memory->destroy_2d_double_array(xall); memory->sfree(imageall); MPI_Comm_free(&comm_replica); delete random_select; delete random_dephase; delete velocity; delete finish; modify->delete_compute("prd_temp"); modify->delete_fix("prd_event"); compute_event->reset_extra_compute_fix(NULL); } /* ---------------------------------------------------------------------- dephasing = one or more short runs with new random velocities ------------------------------------------------------------------------- */ void PRD::dephase() { - int ntimestep_hold = update->ntimestep; + bigint ntimestep_hold = update->ntimestep; update->whichflag = 1; update->nsteps = n_dephase*t_dephase; timer->barrier_start(TIME_LOOP); for (int i = 0; i < n_dephase; i++) { - int seed = static_cast<int> (random_dephase->uniform() * MAXINT32); + int seed = static_cast<int> (random_dephase->uniform() * MAXSMALLINT); if (seed == 0) seed = 1; velocity->create(temp_dephase,seed); update->integrate->run(t_dephase); if (temp_flag == 0) temp_dephase = temperature->compute_scalar(); } timer->barrier_stop(TIME_LOOP); time_dephase += timer->array[TIME_LOOP]; update->integrate->cleanup(); finish->end(0); // reset timestep as if dephase did not occur // clear timestep storage from computes, since now invalid update->ntimestep = ntimestep_hold; for (int i = 0; i < modify->ncompute; i++) if (modify->compute[i]->timeflag) modify->compute[i]->clearstep(); } /* ---------------------------------------------------------------------- single short dynamics run ------------------------------------------------------------------------- */ void PRD::dynamics() { update->whichflag = 1; update->nsteps = t_event; lmp->init(); update->integrate->setup(); // this may be needed if don't do full init //modify->addstep_compute_all(update->ntimestep); int ncalls = neighbor->ncalls; timer->barrier_start(TIME_LOOP); update->integrate->run(t_event); timer->barrier_stop(TIME_LOOP); time_dynamics += timer->array[TIME_LOOP]; nbuild += neighbor->ncalls - ncalls; ndanger += neighbor->ndanger; update->integrate->cleanup(); finish->end(0); } /* ---------------------------------------------------------------------- quench minimization ------------------------------------------------------------------------- */ void PRD::quench() { - int ntimestep_hold = update->ntimestep; - int endstep_hold = update->endstep; + bigint ntimestep_hold = update->ntimestep; + bigint endstep_hold = update->endstep; // need to change whichflag so that minimize->setup() calling // modify->setup() will call fix->min_setup() update->whichflag = 2; update->nsteps = maxiter; update->endstep = update->laststep = update->firststep + maxiter; // full init works lmp->init(); update->minimize->setup(); // partial init does not work //modify->addstep_compute_all(update->ntimestep); //update->minimize->setup_minimal(1); int ncalls = neighbor->ncalls; timer->barrier_start(TIME_LOOP); update->minimize->run(maxiter); timer->barrier_stop(TIME_LOOP); time_quench += timer->array[TIME_LOOP]; if (neighbor->ncalls == ncalls) quench_reneighbor = 0; else quench_reneighbor = 1; update->minimize->cleanup(); finish->end(0); // reset timestep as if dephase did not occur // clear timestep storage from computes, since now invalid update->ntimestep = ntimestep_hold; update->endstep = update->laststep = endstep_hold; for (int i = 0; i < modify->ncompute; i++) if (modify->compute[i]->timeflag) modify->compute[i]->clearstep(); } /* ---------------------------------------------------------------------- check for an event in any replica if replica_num is non-negative only check for event on replica_num if multiple events, choose one at random return -1 if no event else return ireplica = world in which event occured ------------------------------------------------------------------------- */ int PRD::check_event(int replica_num) { int worldflag,universeflag,scanflag,replicaflag,ireplica; worldflag = 0; if (compute_event->compute_scalar() > 0.0) worldflag = 1; if (replica_num >= 0 && replica_num != universe->iworld) worldflag = 0; timer->barrier_start(TIME_LOOP); if (me == 0) MPI_Allreduce(&worldflag,&universeflag,1, MPI_INT,MPI_SUM,comm_replica); MPI_Bcast(&universeflag,1,MPI_INT,0,world); ncoincident = universeflag; if (!universeflag) ireplica = -1; else { if (universeflag > 1) { int iwhich = static_cast<int> (universeflag*random_select->uniform()) + 1; if (me == 0) MPI_Scan(&worldflag,&scanflag,1, MPI_INT,MPI_SUM,comm_replica); MPI_Bcast(&scanflag,1,MPI_INT,0,world); if (scanflag != iwhich) worldflag = 0; } if (worldflag) replicaflag = universe->iworld; else replicaflag = 0; if (me == 0) MPI_Allreduce(&replicaflag,&ireplica,1, MPI_INT,MPI_SUM,comm_replica); MPI_Bcast(&ireplica,1,MPI_INT,0,world); } timer->barrier_stop(TIME_LOOP); time_comm += timer->array[TIME_LOOP]; return ireplica; } /* ---------------------------------------------------------------------- share quenched and hot coords owned by ireplica with all replicas all replicas store event in fix_event replica 0 dumps event snapshot flag = 0 = called before PRD run flag = 1 = called during PRD run = not correlated event flag = 2 = called during PRD run = correlated event ------------------------------------------------------------------------- */ void PRD::share_event(int ireplica, int flag) { timer->barrier_start(TIME_LOOP); // communicate quenched coords to all replicas and store as event // decrement event counter if flag = 0 since not really an event replicate(ireplica); timer->barrier_stop(TIME_LOOP); time_comm += timer->array[TIME_LOOP]; // adjust time for last correlated event check (not on first event) int corr_adjust = t_corr; if (fix_event->event_number < 1 || flag == 2) corr_adjust = 0; // delta = time since last correlated event check int delta = update->ntimestep - fix_event->event_timestep - corr_adjust; // if this is a correlated event, time elapsed only on one partition if (flag != 2) delta *= universe->nworlds; delta += corr_adjust; // don't change the clock or timestep if this is a restart if (flag == 0 && fix_event->event_number != 0) fix_event->store_event_prd(fix_event->event_timestep,0); else { fix_event->store_event_prd(update->ntimestep,delta); fix_event->replica_number = ireplica; fix_event->correlated_event = 0; if (flag == 2) fix_event->correlated_event = 1; fix_event->ncoincident = ncoincident; } if (flag == 0) fix_event->event_number--; // dump snapshot of quenched coords // must reneighbor and compute forces before dumping // since replica 0 possibly has new state from another replica // addstep_compute_all insures eng/virial are calculated if needed if (output->ndump && universe->iworld == 0) { timer->barrier_start(TIME_LOOP); modify->addstep_compute_all(update->ntimestep); update->integrate->setup_minimal(1); output->write_dump(update->ntimestep); timer->barrier_stop(TIME_LOOP); time_output += timer->array[TIME_LOOP]; } // restore and communicate hot coords to all replicas fix_event->restore_state(); timer->barrier_start(TIME_LOOP); replicate(ireplica); timer->barrier_stop(TIME_LOOP); time_comm += timer->array[TIME_LOOP]; } /* ---------------------------------------------------------------------- universe proc 0 prints event info ------------------------------------------------------------------------- */ void PRD::log_event() { timer->array[TIME_LOOP] = time_start; if (universe->me == 0) { + char fstr[32]; + sprintf(fstr,"%s %%.3f %%d %%d %%d %%d %%d\n",BIGINT_FORMAT); if (universe->uscreen) - fprintf(universe->uscreen,"%d %.3f %d %d %d %d %d\n", + fprintf(universe->uscreen,fstr, fix_event->event_timestep, timer->elapsed(TIME_LOOP), fix_event->clock, fix_event->event_number,fix_event->correlated_event, fix_event->ncoincident, fix_event->replica_number); if (universe->ulogfile) - fprintf(universe->ulogfile,"%d %.3f %d %d %d %d %d\n", + fprintf(universe->ulogfile,fstr, fix_event->event_timestep, timer->elapsed(TIME_LOOP), fix_event->clock, fix_event->event_number,fix_event->correlated_event, fix_event->ncoincident, fix_event->replica_number); } } /* ---------------------------------------------------------------------- communicate atom coords and image flags in ireplica to all other replicas one proc per replica: direct overwrite via bcast equal procs per replica and no replica reneighbored: direct overwrite via bcast unequal procs per replica or reneighboring occurred: collect to root proc of event replica bcast to roots of other replicas bcast within each replica each proc extracts info for atoms it owns using atom IDs ------------------------------------------------------------------------- */ void PRD::replicate(int ireplica) { int nreplica = universe->nworlds; int nprocs_universe = universe->nprocs; int i,m,flag,commflag; int counts[nprocs]; if (nreplica == nprocs_universe) commflag = 0; else if (equal_size_replicas) { flag = 0; if (quench_reneighbor) flag = 1; MPI_Allreduce(&flag,&commflag,1,MPI_INT,MPI_MAX,universe->uworld); } else commflag = 1; if (commflag == 0) { MPI_Bcast(atom->image,atom->nlocal,MPI_INT,ireplica,comm_replica); MPI_Bcast(atom->x[0],3*atom->nlocal,MPI_DOUBLE,ireplica,comm_replica); } else { if (universe->iworld == ireplica) { MPI_Gather(&atom->nlocal,1,MPI_INT,counts,1,MPI_INT,0,world); displacements[0] = 0; for (i = 0; i < nprocs-1; i++) displacements[i+1] = displacements[i] + counts[i]; MPI_Gatherv(atom->tag,atom->nlocal,MPI_INT, tagall,counts,displacements,MPI_INT,0,world); MPI_Gatherv(atom->image,atom->nlocal,MPI_INT, imageall,counts,displacements,MPI_INT,0,world); for (i = 0; i < nprocs; i++) counts[i] *= 3; for (i = 0; i < nprocs-1; i++) displacements[i+1] = displacements[i] + counts[i]; MPI_Gatherv(atom->x[0],3*atom->nlocal,MPI_DOUBLE, xall[0],counts,displacements,MPI_DOUBLE,0,world); } if (me == 0) { MPI_Bcast(tagall,natoms,MPI_INT,ireplica,comm_replica); MPI_Bcast(imageall,natoms,MPI_INT,ireplica,comm_replica); MPI_Bcast(xall[0],3*natoms,MPI_DOUBLE,ireplica,comm_replica); } MPI_Bcast(tagall,natoms,MPI_INT,0,world); MPI_Bcast(imageall,natoms,MPI_INT,0,world); MPI_Bcast(xall[0],3*natoms,MPI_DOUBLE,0,world); double **x = atom->x; int nlocal = atom->nlocal; for (i = 0; i < natoms; i++) { m = atom->map(tagall[i]); if (m >= 0 && m < nlocal) { x[m][0] = xall[i][0]; x[m][1] = xall[i][1]; x[m][2] = xall[i][2]; atom->image[m] = imageall[i]; } } } } /* ---------------------------------------------------------------------- parse optional parameters at end of PRD input line ------------------------------------------------------------------------- */ void PRD::options(int narg, char **arg) { if (narg < 0) error->all("Illegal prd command"); // set defaults etol = 0.1; ftol = 0.1; maxiter = 40; maxeval = 50; temp_flag = 0; char *str = "geom"; int n = strlen(str) + 1; loop_setting = new char[n]; strcpy(loop_setting,str); str = "gaussian"; n = strlen(str) + 1; dist_setting = new char[n]; strcpy(dist_setting,str); int iarg = 0; while (iarg < narg) { if (strcmp(arg[iarg],"min") == 0) { if (iarg+5 > narg) error->all("Illegal prd command"); etol = atof(arg[iarg+1]); ftol = atof(arg[iarg+2]); maxiter = atoi(arg[iarg+3]); maxeval = atoi(arg[iarg+4]); if (maxiter < 0) error->all("Illegal prd command"); iarg += 5; } else if (strcmp(arg[iarg],"temp") == 0) { if (iarg+2 > narg) error->all("Illegal prd command"); temp_flag = 1; temp_dephase = atof(arg[iarg+1]); if (temp_dephase <= 0.0) error->all("Illegal prd command"); iarg += 2; } else if (strcmp(arg[iarg],"vel") == 0) { if (iarg+3 > narg) error->all("Illegal prd command"); delete [] loop_setting; delete [] dist_setting; if (strcmp(arg[iarg+1],"all") == 0) loop_setting = NULL; else if (strcmp(arg[iarg+1],"local") == 0) loop_setting = NULL; else if (strcmp(arg[iarg+1],"geom") == 0) loop_setting = NULL; else error->all("Illegal prd command"); int n = strlen(arg[iarg+1]) + 1; loop_setting = new char[n]; strcpy(loop_setting,arg[iarg+1]); if (strcmp(arg[iarg+2],"uniform") == 0) dist_setting = NULL; else if (strcmp(arg[iarg+2],"gaussian") == 0) dist_setting = NULL; else error->all("Illegal prd command"); n = strlen(arg[iarg+2]) + 1; dist_setting = new char[n]; strcpy(dist_setting,arg[iarg+2]); iarg += 3; } else error->all("Illegal prd command"); } } diff --git a/src/REPLICA/tad.cpp b/src/REPLICA/tad.cpp index c1d487ed1..0cbb93707 100644 --- a/src/REPLICA/tad.cpp +++ b/src/REPLICA/tad.cpp @@ -1,987 +1,985 @@ -// To do: -// Mysterious problem with // if (universe->iworld == 0) - /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- Contributing author: Aidan Thompson (SNL) ------------------------------------------------------------------------- */ #include "mpi.h" #include "math.h" #include "stdlib.h" #include "string.h" #include "tad.h" #include "universe.h" #include "update.h" #include "atom.h" #include "domain.h" #include "region.h" #include "comm.h" #include "velocity.h" #include "integrate.h" #include "min.h" #include "neighbor.h" #include "modify.h" #include "neb.h" #include "compute.h" #include "fix.h" #include "fix_event_tad.h" #include "fix_store_state.h" #include "force.h" #include "pair.h" #include "random_park.h" #include "random_mars.h" #include "output.h" #include "dump.h" #include "finish.h" #include "timer.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; /* ---------------------------------------------------------------------- */ TAD::TAD(LAMMPS *lmp) : Pointers(lmp) {} /* ---------------------------------------------------------------------- */ TAD::~TAD() { memory->sfree(fix_event_list); if (neb_logfilename != NULL) delete [] neb_logfilename; delete [] min_style; delete [] min_style_neb; } /* ---------------------------------------------------------------------- perform TAD simulation on root proc other procs only used for NEB calcs ------------------------------------------------------------------------- */ void TAD::command(int narg, char **arg) { fix_event_list = NULL; n_event_list = 0; nmax_event_list = 0; nmin_event_list = 10; // error checks if (domain->box_exist == 0) error->all("tad command before simulation box is defined"); - if (universe->nworlds == 1) error->all("Cannot use TAD with a single replica for NEB"); + if (universe->nworlds == 1) + error->all("Cannot use TAD with a single replica for NEB"); if (universe->nworlds != universe->nprocs) error->all("Can only use TAD with 1-processor replicas for NEB"); if (atom->sortfreq > 0) error->all("Cannot use TAD with atom_modify sort enabled for NEB"); if (atom->map_style == 0) error->all("Cannot use TAD unless atom map exists for NEB"); if (narg < 7) error->universe_all("Illegal tad command"); nsteps = atoi(arg[0]); t_event = atoi(arg[1]); templo = atof(arg[2]); temphi = atof(arg[3]); delta_conf = atof(arg[4]); tmax = atof(arg[5]); char id_compute[strlen(arg[6])+1]; strcpy(id_compute,arg[6]); options(narg-7,&arg[7]); // total # of timesteps must be multiple of t_event if (t_event <= 0) error->universe_all("Invalid t_event in tad command"); if (nsteps % t_event) error->universe_all("TAD nsteps must be multiple of t_event"); if (delta_conf <= 0.0 || delta_conf >= 1.0) error->universe_all("Invalid delta_conf in tad command"); if (tmax <= 0.0) error->universe_all("Invalid tmax in tad command"); // deltconf = (ln(1/delta))/freq_min (timestep units) deltconf = -log(delta_conf)*tmax/update->dt; // local storage int me_universe = universe->me; int nprocs_universe = universe->nprocs; MPI_Comm_rank(world,&me); MPI_Comm_size(world,&nprocs); delta_beta = (1.0/templo - 1.0/temphi) / force->boltz; ratio_beta = templo/temphi; // create FixEventTAD object to store last event int narg2 = 3; char **args = new char*[narg2]; args[0] = (char *) "tad_event"; args[1] = (char *) "all"; args[2] = (char *) "EVENT/TAD"; modify->add_fix(narg2,args); fix_event = (FixEventTAD *) modify->fix[modify->nfix-1]; delete [] args; // create FixStoreState object to store revert state narg2 = 13; args = new char*[narg2]; args[0] = (char *) "tad_revert"; args[1] = (char *) "all"; args[2] = (char *) "store/state"; args[3] = (char *) "0"; args[4] = (char *) "x"; args[5] = (char *) "y"; args[6] = (char *) "z"; args[7] = (char *) "ix"; args[8] = (char *) "iy"; args[9] = (char *) "iz"; args[10] = (char *) "vx"; args[11] = (char *) "vy"; args[12] = (char *) "vz"; modify->add_fix(narg2,args); fix_revert = (FixStoreState *) modify->fix[modify->nfix-1]; delete [] args; // create Finish for timing output finish = new Finish(lmp); // assign FixEventTAD to event-detection compute // necessary so it will know atom coords at last event int icompute = modify->find_compute(id_compute); if (icompute < 0) error->all("Could not find compute ID for TAD"); compute_event = modify->compute[icompute]; compute_event->reset_extra_compute_fix("tad_event"); // reset reneighboring criteria since will perform minimizations neigh_every = neighbor->every; neigh_delay = neighbor->delay; neigh_dist_check = neighbor->dist_check; if (neigh_every != 1 || neigh_delay != 0 || neigh_dist_check != 1) { if (me_universe == 0) error->warning("Resetting reneighboring criteria during TAD"); } neighbor->every = 1; neighbor->delay = 0; neighbor->dist_check = 1; // initialize TAD as if one long dynamics run update->whichflag = 1; update->nsteps = nsteps; update->beginstep = update->firststep = update->ntimestep; update->endstep = update->laststep = update->firststep + nsteps; update->restrict_output = 1; lmp->init(); // set minimize style for quench narg2 = 1; args = new char*[narg2]; args[0] = min_style; update->create_minimize(narg2,args); delete [] args; // init minimizer settings and minimizer itself update->etol = etol; update->ftol = ftol; update->max_eval = maxeval; update->minimize->init(); // perform TAD simulation if (me_universe == 0 && universe->uscreen) fprintf(universe->uscreen,"Setting up TAD ...\n"); if (me_universe == 0) { if (universe->uscreen) - fprintf(universe->uscreen,"Step CPU Clock Event " - "\n"); + fprintf(universe->uscreen,"Step CPU Clock Event\n"); if (universe->ulogfile) - fprintf(universe->ulogfile,"Step CPU Clock Event " - "\n"); + fprintf(universe->ulogfile,"Step CPU Clock Event\n"); } ulogfile_lammps = universe->ulogfile; uscreen_lammps = universe->uscreen; ulogfile_neb = NULL; uscreen_neb = NULL; if (me_universe == 0 && neb_logfilename) ulogfile_neb = fopen(neb_logfilename,"w"); // store hot state and quenched event, only on replica 0 // need this line if quench() does only setup_minimal() // update->minimize->setup(); // This should work with if uncommented, but does not // if (universe->iworld == 0) { fix_event->store_state(); quench(); timer->barrier_start(TIME_LOOP); time_start = timer->array[TIME_LOOP]; fix_event->store_event_tad(update->ntimestep); log_event(); fix_event->restore_state(); // do full init/setup update->whichflag = 1; lmp->init(); update->integrate->setup(); // } // main loop: look for events until out of time // (1) dynamics, store state, quench, check event, restore state // (2) if event, perform NEB, record in fix_event_list // (3) if confident, pick earliest event nbuild = ndanger = 0; time_neb = time_dynamics = time_quench = time_comm = time_output = 0.0; timer->barrier_start(TIME_LOOP); time_start = timer->array[TIME_LOOP]; int confident_flag, event_flag; if (universe->iworld == 0) { while (update->ntimestep < update->endstep) { // initialize list of possible events initialize_event_list(); confident_flag = 0; while (update->ntimestep < update->endstep) { event_flag = 0; while (update->ntimestep < update->endstep) { dynamics(); fix_event->store_state(); quench(); event_flag = check_event(); MPI_Bcast(&event_flag,1,MPI_INT,0,universe->uworld); if (event_flag) break; // restore hot state fix_event->restore_state(); // store hot state in revert fix_revert->end_of_step(); } if (!event_flag) break; add_event(); perform_neb(n_event_list-1); compute_tlo(n_event_list-1); confident_flag = check_confidence(); MPI_Bcast(&confident_flag,1,MPI_INT,0,universe->uworld); if (confident_flag) break; if (universe->iworld == 0) revert(); } if (!confident_flag) break; perform_event(event_first); // need to sync timestep with TAD MPI_Bcast(&(update->ntimestep),1,MPI_INT,0,universe->uworld); int restart_flag = 0; if (output->restart_every && universe->iworld == 0) if (fix_event->event_number % output->restart_every == 0) restart_flag = 1; // full init/setup since are starting after event update->whichflag = 1; lmp->init(); update->integrate->setup(); // write restart file of hot coords if (restart_flag) { timer->barrier_start(TIME_LOOP); output->write_restart(update->ntimestep); timer->barrier_stop(TIME_LOOP); time_output += timer->array[TIME_LOOP]; } } } else { while (update->ntimestep < update->endstep) { confident_flag = 0; while (update->ntimestep < update->endstep) { event_flag = 0; while (update->ntimestep < update->endstep) { update->ntimestep += t_event; MPI_Bcast(&event_flag,1,MPI_INT,0,universe->uworld); if (event_flag) break; } if (!event_flag) break; perform_neb(-1); MPI_Bcast(&confident_flag,1,MPI_INT,0,universe->uworld); if (confident_flag) break; } if (!confident_flag) break; // need to sync timestep with TAD MPI_Bcast(&(update->ntimestep),1,MPI_INT,0,universe->uworld); } } // set total timers and counters so Finish() will process them timer->array[TIME_LOOP] = time_start; timer->barrier_stop(TIME_LOOP); timer->array[TIME_PAIR] = time_neb; timer->array[TIME_BOND] = time_dynamics; timer->array[TIME_KSPACE] = time_quench; timer->array[TIME_COMM] = time_comm; timer->array[TIME_OUTPUT] = time_output; neighbor->ncalls = nbuild; neighbor->ndanger = ndanger; if (me_universe == 0) { + char str[128]; + sprintf(str,"Loop time of %%g on %%d procs for %%d steps with %s atoms\n", + BIGINT_FORMAT); if (universe->uscreen) - fprintf(universe->uscreen, - "Loop time of %g on %d procs for %d steps with %lu atoms\n", + fprintf(universe->uscreen,str, timer->array[TIME_LOOP],nprocs_universe,nsteps,atom->natoms); if (universe->ulogfile) - fprintf(universe->ulogfile, - "Loop time of %g on %d procs for %d steps with %lu atoms\n", + fprintf(universe->ulogfile,str, timer->array[TIME_LOOP],nprocs_universe,nsteps,atom->natoms); } if (me_universe == 0) fclose(ulogfile_neb); finish->end(3); update->whichflag = 0; update->firststep = update->laststep = 0; update->beginstep = update->endstep = 0; update->restrict_output = 0; // reset reneighboring criteria neighbor->every = neigh_every; neighbor->delay = neigh_delay; neighbor->dist_check = neigh_dist_check; delete finish; modify->delete_fix("tad_event"); modify->delete_fix("tad_revert"); delete_event_list(); compute_event->reset_extra_compute_fix(NULL); } /* ---------------------------------------------------------------------- single short dynamics run ------------------------------------------------------------------------- */ void TAD::dynamics() { update->whichflag = 1; update->nsteps = t_event; lmp->init(); update->integrate->setup(); // this may be needed if don't do full init //modify->addstep_compute_all(update->ntimestep); int ncalls = neighbor->ncalls; timer->barrier_start(TIME_LOOP); update->integrate->run(t_event); timer->barrier_stop(TIME_LOOP); time_dynamics += timer->array[TIME_LOOP]; nbuild += neighbor->ncalls - ncalls; ndanger += neighbor->ndanger; update->integrate->cleanup(); finish->end(0); } /* ---------------------------------------------------------------------- quench minimization ------------------------------------------------------------------------- */ void TAD::quench() { - int ntimestep_hold = update->ntimestep; - int endstep_hold = update->endstep; + bigint ntimestep_hold = update->ntimestep; + bigint endstep_hold = update->endstep; // need to change whichflag so that minimize->setup() calling // modify->setup() will call fix->min_setup() update->whichflag = 2; update->nsteps = maxiter; update->endstep = update->laststep = update->firststep + maxiter; // full init works lmp->init(); update->minimize->setup(); // partial init does not work //modify->addstep_compute_all(update->ntimestep); //update->minimize->setup_minimal(1); int ncalls = neighbor->ncalls; timer->barrier_start(TIME_LOOP); update->minimize->run(maxiter); timer->barrier_stop(TIME_LOOP); time_quench += timer->array[TIME_LOOP]; if (neighbor->ncalls == ncalls) quench_reneighbor = 0; else quench_reneighbor = 1; update->minimize->cleanup(); finish->end(1); // reset timestep as if quench did not occur // clear timestep storage from computes, since now invalid update->ntimestep = ntimestep_hold; update->endstep = update->laststep = endstep_hold; for (int i = 0; i < modify->ncompute; i++) if (modify->compute[i]->timeflag) modify->compute[i]->clearstep(); } /* ---------------------------------------------------------------------- check for an event return 0 if no event return 1 if event ------------------------------------------------------------------------- */ int TAD::check_event() { int flag; flag = 0; if (compute_event->compute_scalar() > 0.0) flag = 1; return flag; } /* ---------------------------------------------------------------------- universe proc 0 prints event info ------------------------------------------------------------------------- */ void TAD::log_event() { timer->array[TIME_LOOP] = time_start; if (universe->me == 0) { + char fstr[32]; + sprintf(fstr,"%s %%.3f %%.3f %%d\n",BIGINT_FORMAT); if (universe->uscreen) - fprintf(universe->uscreen,"%d %.3f %.3f %d\n", + fprintf(universe->uscreen,fstr, fix_event->event_timestep, timer->elapsed(TIME_LOOP), fix_event->tlo, fix_event->event_number); if (universe->ulogfile) - fprintf(universe->ulogfile,"%d %.3f %.3f %d\n", + fprintf(universe->ulogfile,fstr, fix_event->event_timestep, timer->elapsed(TIME_LOOP), fix_event->tlo, fix_event->event_number); } // dump snapshot of quenched coords // must reneighbor and compute forces before dumping // addstep_compute_all insures eng/virial are calculated if needed if (output->ndump && universe->iworld == 0) { timer->barrier_start(TIME_LOOP); modify->addstep_compute_all(update->ntimestep); update->integrate->setup_minimal(1); output->write_dump(update->ntimestep); timer->barrier_stop(TIME_LOOP); time_output += timer->array[TIME_LOOP]; } } /* ---------------------------------------------------------------------- parse optional parameters at end of TAD input line ------------------------------------------------------------------------- */ void TAD::options(int narg, char **arg) { if (narg < 0) error->all("Illegal tad command"); // set defaults etol = 0.1; ftol = 0.1; maxiter = 40; maxeval = 50; etol_neb = 0.01; ftol_neb = 0.01; n1steps_neb = 100; n2steps_neb = 100; nevery_neb = 10; min_style = new char[3]; strcpy(min_style,"cg"); min_style_neb = new char[9]; strcpy(min_style_neb,"quickmin"); neb_logfilename = NULL; int iarg = 0; while (iarg < narg) { if (strcmp(arg[iarg],"min") == 0) { if (iarg+5 > narg) error->all("Illegal tad command"); etol = atof(arg[iarg+1]); ftol = atof(arg[iarg+2]); maxiter = atoi(arg[iarg+3]); maxeval = atoi(arg[iarg+4]); if (maxiter < 0 || maxeval < 0 || etol < 0.0 || ftol < 0.0 ) error->all("Illegal tad command"); iarg += 5; } else if (strcmp(arg[iarg],"neb") == 0) { if (iarg+6 > narg) error->all("Illegal tad command"); etol_neb = atof(arg[iarg+1]); ftol_neb = atof(arg[iarg+2]); n1steps_neb = atoi(arg[iarg+3]); n2steps_neb = atoi(arg[iarg+4]); nevery_neb = atoi(arg[iarg+5]); if (etol_neb < 0.0 || ftol_neb < 0.0 || n1steps_neb < 0 || n2steps_neb < 0 || nevery_neb < 0) error->all("Illegal tad command"); iarg += 6; } else if (strcmp(arg[iarg],"min_style") == 0) { if (iarg+2 > narg) error->all("Illegal tad command"); int n = strlen(arg[iarg+1]) + 1; delete [] min_style; min_style = new char[n]; strcpy(min_style,arg[iarg+1]); iarg += 2; } else if (strcmp(arg[iarg],"neb_style") == 0) { if (iarg+2 > narg) error->all("Illegal tad command"); int n = strlen(arg[iarg+1]) + 1; delete [] min_style_neb; min_style_neb = new char[n]; strcpy(min_style_neb,arg[iarg+1]); iarg += 2; } else if (strcmp(arg[iarg],"neb_log") == 0) { delete [] neb_logfilename; if (iarg+2 > narg) error->all("Illegal tad command"); if (strcmp(arg[iarg+1],"none") == 0) neb_logfilename = NULL; else { int n = strlen(arg[iarg+1]) + 1; neb_logfilename = new char[n]; strcpy(neb_logfilename,arg[iarg+1]); } iarg += 2; } else error->all("Illegal tad command"); } } /* ---------------------------------------------------------------------- perform NEB calculation ------------------------------------------------------------------------- */ void TAD::perform_neb(int ievent) { double **x = atom->x; int nlocal = atom->nlocal; double *buf_final = (double *) memory->smalloc(3*nlocal*sizeof(double),"tad:buffinal"); // set system to quenched state of event ievent if (universe->iworld == 0) { fix_event_list[ievent]->restore_event(); int ii = 0; for (int i = 0; i < nlocal; i++) { buf_final[ii++] = x[i][0]; buf_final[ii++] = x[i][1]; buf_final[ii++] = x[i][2]; } } MPI_Bcast(buf_final,3*nlocal,MPI_DOUBLE,universe->root_proc[0], universe->uworld); double *buf_init = (double *) memory->smalloc(3*nlocal*sizeof(double),"tad:bufinit"); // set system to quenched state of fix_event if (universe->iworld == 0) { fix_event->restore_event(); int ii = 0; for (int i = 0; i < nlocal; i++) { buf_init[ii++] = x[i][0]; buf_init[ii++] = x[i][1]; buf_init[ii++] = x[i][2]; } } MPI_Bcast(buf_init,3*nlocal,MPI_DOUBLE,universe->root_proc[0], universe->uworld); // create FixNEB object to support NEB int narg2 = 4; char **args = new char*[narg2]; args[0] = (char *) "neb"; args[1] = (char *) "all"; args[2] = (char *) "neb"; char str[128]; args[3] = str; double kspring = 1.0; sprintf(args[3],"%f",kspring); modify->add_fix(narg2,args); fix_neb = (Fix *) modify->fix[modify->nfix-1]; delete [] args; // switch minimize style to quickmin for NEB narg2 = 1; args = new char*[narg2]; args[0] = min_style_neb; update->create_minimize(narg2,args); delete [] args; // create NEB object neb = new NEB(lmp,etol_neb,ftol_neb,n1steps_neb, n2steps_neb,nevery_neb,buf_init,buf_final); // free up temporary arrays memory->sfree(buf_init); memory->sfree(buf_final); // Run NEB - double beginstep_hold = update->beginstep; - double endstep_hold = update->endstep; - double ntimestep_hold = update->ntimestep; - double nsteps_hold = update->nsteps; + int beginstep_hold = update->beginstep; + int endstep_hold = update->endstep; + int ntimestep_hold = update->ntimestep; + int nsteps_hold = update->nsteps; if (universe->me == 0) { universe->ulogfile = ulogfile_neb; universe->uscreen = uscreen_neb; } // Had to bypass timer interface // because timer->array is reset // inside neb->run() // timer->barrier_start(TIME_LOOP); // neb->run(); // timer->barrier_stop(TIME_LOOP); // time_neb += timer->array[TIME_LOOP]; MPI_Barrier(world); double time_tmp = MPI_Wtime(); neb->run(); MPI_Barrier(world); time_neb += MPI_Wtime() - time_tmp; if (universe->me == 0) { universe->ulogfile = ulogfile_lammps; universe->uscreen = uscreen_lammps; } // Extract barrier energy from NEB if (universe->iworld == 0) fix_event_list[ievent]->ebarrier = neb->ebf; update->beginstep = update->firststep = beginstep_hold; update->endstep = update->laststep = endstep_hold; update->ntimestep = ntimestep_hold; update->nsteps = nsteps_hold; // switch minimize style back for quench narg2 = 1; args = new char*[narg2]; args[0] = min_style; update->create_minimize(narg2,args); update->etol = etol; update->ftol = ftol; delete [] args; // Clean up modify->delete_fix("neb"); delete neb; } /* ---------------------------------------------------------------------- check if confidence criterion for tstop is satisfied return 0 if not satisfied return 1 if satisfied ------------------------------------------------------------------------- */ int TAD::check_confidence() { int flag; // update stopping time deltstop = deltconf*pow(deltfirst/deltconf, ratio_beta); flag = 0; if (deltstop < update->ntimestep - fix_event->event_timestep) flag = 1; return flag; } /* ---------------------------------------------------------------------- reflect back in to starting state ------------------------------------------------------------------------- */ void TAD::revert() { double **x = atom->x; double **v = atom->v; int *image = atom->image; int nlocal = atom->nlocal; double **array_atom = fix_revert->array_atom; for (int i = 0; i < nlocal; i++) { x[i][0] = array_atom[i][0]; x[i][1] = array_atom[i][1]; x[i][2] = array_atom[i][2]; image[i] = ((int(array_atom[i][5]) + 512 & 1023) << 20) | ((int(array_atom[i][4]) + 512 & 1023) << 10) | (int(array_atom[i][3]) + 512 & 1023); v[i][0] = -array_atom[i][6]; v[i][1] = -array_atom[i][7]; v[i][2] = -array_atom[i][8]; } } /* ---------------------------------------------------------------------- Initialize list of possible events ------------------------------------------------------------------------- */ void TAD::initialize_event_list() { // First delete old events, if any delete_event_list(); // Create new list n_event_list = 0; grow_event_list(nmin_event_list); } /* ---------------------------------------------------------------------- Delete list of possible events ------------------------------------------------------------------------- */ void TAD::delete_event_list() { for (int i = 0; i < n_event_list; i++) { char str[128]; sprintf(str,"tad_event_%d",i); modify->delete_fix(str); } memory->sfree(fix_event_list); fix_event_list = NULL; n_event_list = 0; nmax_event_list = 0; } /* ---------------------------------------------------------------------- add event ------------------------------------------------------------------------- */ void TAD::add_event() { // create FixEventTAD object to store possible event int narg = 3; char **args = new char*[narg]; char str[128]; sprintf(str,"tad_event_%d",n_event_list); args[0] = str; args[1] = (char *) "all"; args[2] = (char *) "EVENT/TAD"; modify->add_fix(narg,args); if (n_event_list == nmax_event_list) grow_event_list(nmax_event_list+nmin_event_list); n_event_list += 1; int ievent = n_event_list-1; fix_event_list[ievent] = (FixEventTAD *) modify->fix[modify->nfix-1]; // store quenched state for new event fix_event_list[ievent]->store_event_tad(update->ntimestep); // store hot state for new event fix_event->restore_state(); fix_event_list[ievent]->store_state(); // string clean-up delete [] args; } /* ---------------------------------------------------------------------- compute cold time for event ievent ------------------------------------------------------------------------- */ void TAD::compute_tlo(int ievent) { double deltlo,delthi,ebarrier; ebarrier = fix_event_list[ievent]->ebarrier; delthi = fix_event_list[ievent]->event_timestep - fix_event->event_timestep; deltlo = delthi*exp(ebarrier*delta_beta); fix_event_list[ievent]->tlo = fix_event->tlo + deltlo; // first-replica output about each event if (universe->me == 0) { - char str[128]; + char str[128],fstr[128]; double tfrac = 0.0; if (ievent > 0) tfrac = delthi/deltstop; // sprintf(str, // "New event: ievent = %d eb = %g t_lo = %g t_hi = %g t_hi/t_stop = %g \n", // ievent,ebarrier,deltlo,delthi,tfrac); // error->warning(str); + sprintf(fstr,"New event: t_hi = %s ievent = %%d eb = %%g " + "dt_lo = %%g dt_hi/t_stop = %%g \n",BIGINT_FORMAT); + if (screen) - fprintf(screen, - "New event: t_hi = %d ievent = %d eb = %g dt_lo = %g dt_hi/t_stop = %g \n", - fix_event_list[ievent]->event_timestep, + fprintf(screen,fstr,fix_event_list[ievent]->event_timestep, ievent,ebarrier,deltlo,tfrac); if (logfile) - fprintf(logfile, - "New event: t_hi = %d ievent = %d eb = %g dt_lo = %g dt_hi/t_stop = %g \n", - fix_event_list[ievent]->event_timestep, + fprintf(logfile,fstr,fix_event_list[ievent]->event_timestep, ievent,ebarrier,deltlo,tfrac); } // update first event if (ievent == 0) { deltfirst = deltlo; event_first = ievent; } else if (deltlo < deltfirst) { deltfirst = deltlo; event_first = ievent; } } /* ---------------------------------------------------------------------- perform event ------------------------------------------------------------------------- */ void TAD::perform_event(int ievent) { // reset timestep to that of event update->ntimestep = fix_event_list[ievent]->event_timestep; // Copy event to current event fix_event->tlo = fix_event_list[ievent]->tlo; fix_event->event_number++; fix_event->event_timestep = update->ntimestep; fix_event_list[ievent]->restore_event(); fix_event->store_event_tad(fix_event_list[ievent]->event_timestep); // output stats and dump for quenched state log_event(); // load and store hot state fix_event_list[ievent]->restore_state(); fix_event->store_state(); } /* ---------------------------------------------------------------------- Allocate list of pointers to events ------------------------------------------------------------------------- */ void TAD::grow_event_list(int nmax) { if (nmax_event_list > nmax) return; fix_event_list = (FixEventTAD **) memory->srealloc(fix_event_list,nmax*sizeof(FixEventTAD *),"tad:eventlist"); nmax_event_list = nmax; } diff --git a/src/REPLICA/temper.cpp b/src/REPLICA/temper.cpp index 592e012f3..17fcc41c7 100644 --- a/src/REPLICA/temper.cpp +++ b/src/REPLICA/temper.cpp @@ -1,357 +1,358 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- Contributing author: Mark Sears (SNL) ------------------------------------------------------------------------- */ #include "math.h" #include "stdlib.h" #include "string.h" #include "temper.h" +#include "lmptype.h" #include "universe.h" #include "domain.h" #include "atom.h" #include "update.h" #include "integrate.h" #include "modify.h" #include "compute.h" #include "force.h" #include "output.h" #include "thermo.h" #include "fix.h" #include "random_park.h" #include "finish.h" #include "timer.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; // #define TEMPER_DEBUG 1 /* ---------------------------------------------------------------------- */ Temper::Temper(LAMMPS *lmp) : Pointers(lmp) {} /* ---------------------------------------------------------------------- */ Temper::~Temper() { MPI_Comm_free(&roots); if (ranswap) delete ranswap; delete ranboltz; delete [] set_temp; delete [] temp2world; delete [] world2temp; delete [] world2root; } /* ---------------------------------------------------------------------- perform tempering with inter-world swaps ------------------------------------------------------------------------- */ void Temper::command(int narg, char **arg) { if (universe->nworlds == 1) error->all("Must have more than one processor partition to temper"); if (domain->box_exist == 0) error->all("Temper command before simulation box is defined"); if (narg != 6 && narg != 7) error->universe_all("Illegal temper command"); int nsteps = atoi(arg[0]); nevery = atoi(arg[1]); double temp = atof(arg[2]); for (whichfix = 0; whichfix < modify->nfix; whichfix++) if (strcmp(arg[3],modify->fix[whichfix]->id) == 0) break; if (whichfix == modify->nfix) error->universe_all("Tempering fix ID is not defined"); seed_swap = atoi(arg[4]); seed_boltz = atoi(arg[5]); my_set_temp = universe->iworld; if (narg == 7) my_set_temp = atoi(arg[6]); // swap frequency must evenly divide total # of timesteps if (nevery == 0) error->universe_all("Invalid frequency in temper command"); nswaps = nsteps/nevery; if (nswaps*nevery != nsteps) error->universe_all("Non integer # of swaps in temper command"); // fix style must be appropriate for temperature control if ((strcmp(modify->fix[whichfix]->style,"nvt") != 0) && (strcmp(modify->fix[whichfix]->style,"langevin") != 0) && (strcmp(modify->fix[whichfix]->style,"temp/berendsen") != 0) && (strcmp(modify->fix[whichfix]->style,"temp/rescale") != 0)) error->universe_all("Tempering temperature fix is not valid"); // setup for long tempering run update->whichflag = 1; update->nsteps = nsteps; update->beginstep = update->firststep = update->ntimestep; update->endstep = update->laststep = update->firststep + nsteps; lmp->init(); // local storage me_universe = universe->me; MPI_Comm_rank(world,&me); nworlds = universe->nworlds; iworld = universe->iworld; boltz = force->boltz; // pe_compute = ptr to thermo_pe compute // notify compute it will be called at first swap int id = modify->find_compute("thermo_pe"); if (id < 0) error->all("Tempering could not find thermo_pe compute"); Compute *pe_compute = modify->compute[id]; pe_compute->addstep(update->ntimestep + nevery); // create MPI communicator for root proc from each world int color; if (me == 0) color = 0; else color = 1; MPI_Comm_split(universe->uworld,color,0,&roots); // RNGs for swaps and Boltzmann test // warm up Boltzmann RNG if (seed_swap) ranswap = new RanPark(lmp,seed_swap); else ranswap = NULL; ranboltz = new RanPark(lmp,seed_boltz + me_universe); for (int i = 0; i < 100; i++) ranboltz->uniform(); // world2root[i] = global proc that is root proc of world i world2root = new int[nworlds]; if (me == 0) MPI_Allgather(&me_universe,1,MPI_INT,world2root,1,MPI_INT,roots); MPI_Bcast(world2root,nworlds,MPI_INT,0,world); // create static list of set temperatures // allgather tempering arg "temp" across root procs // bcast from each root to other procs in world set_temp = new double[nworlds]; if (me == 0) MPI_Allgather(&temp,1,MPI_DOUBLE,set_temp,1,MPI_DOUBLE,roots); MPI_Bcast(set_temp,nworlds,MPI_DOUBLE,0,world); // create world2temp only on root procs from my_set_temp // create temp2world on root procs from world2temp, // then bcast to all procs within world world2temp = new int[nworlds]; temp2world = new int[nworlds]; if (me == 0) { MPI_Allgather(&my_set_temp,1,MPI_INT,world2temp,1,MPI_INT,roots); for (int i = 0; i < nworlds; i++) temp2world[world2temp[i]] = i; } MPI_Bcast(temp2world,nworlds,MPI_INT,0,world); // if restarting tempering, reset temp target of Fix to current my_set_temp if (narg == 7) { double new_temp = set_temp[my_set_temp]; modify->fix[whichfix]->reset_target(new_temp); } // setup tempering runs int i,which,partner,swap,partner_set_temp,partner_world; double pe,pe_partner,boltz_factor,new_temp; MPI_Status status; if (me_universe == 0 && universe->uscreen) fprintf(universe->uscreen,"Setting up tempering ...\n"); update->integrate->setup(); if (me_universe == 0) { if (universe->uscreen) { fprintf(universe->uscreen,"Step"); for (int i = 0; i < nworlds; i++) fprintf(universe->uscreen," T%d",i); fprintf(universe->uscreen,"\n"); } if (universe->ulogfile) { fprintf(universe->ulogfile,"Step"); for (int i = 0; i < nworlds; i++) fprintf(universe->ulogfile," T%d",i); fprintf(universe->ulogfile,"\n"); } print_status(); } timer->barrier_start(TIME_LOOP); for (int iswap = 0; iswap < nswaps; iswap++) { // run for nevery timesteps update->integrate->run(nevery); // compute PE // notify compute it will be called at next swap pe = pe_compute->compute_scalar(); pe_compute->addstep(update->ntimestep + nevery); // which = which of 2 kinds of swaps to do (0,1) if (!ranswap) which = iswap % 2; else if (ranswap->uniform() < 0.5) which = 0; else which = 1; // partner_set_temp = which set temp I am partnering with for this swap if (which == 0) { if (my_set_temp % 2 == 0) partner_set_temp = my_set_temp + 1; else partner_set_temp = my_set_temp - 1; } else { if (my_set_temp % 2 == 1) partner_set_temp = my_set_temp + 1; else partner_set_temp = my_set_temp - 1; } // partner = proc ID to swap with // if partner = -1, then I am not a proc that swaps partner = -1; if (me == 0 && partner_set_temp >= 0 && partner_set_temp < nworlds) { partner_world = temp2world[partner_set_temp]; partner = world2root[partner_world]; } // swap with a partner, only root procs in each world participate // hi proc sends PE to low proc // lo proc make Boltzmann decision on whether to swap // lo proc communicates decision back to hi proc swap = 0; if (partner != -1) { if (me_universe > partner) MPI_Send(&pe,1,MPI_DOUBLE,partner,0,universe->uworld); else MPI_Recv(&pe_partner,1,MPI_DOUBLE,partner,0,universe->uworld,&status); if (me_universe < partner) { boltz_factor = (pe - pe_partner) * (1.0/(boltz*set_temp[my_set_temp]) - 1.0/(boltz*set_temp[partner_set_temp])); if (boltz_factor >= 0.0) swap = 1; else if (ranboltz->uniform() < exp(boltz_factor)) swap = 1; } if (me_universe < partner) MPI_Send(&swap,1,MPI_INT,partner,0,universe->uworld); else MPI_Recv(&swap,1,MPI_INT,partner,0,universe->uworld,&status); #ifdef TEMPER_DEBUG if (me_universe < partner) printf("SWAP %d & %d: yes = %d,Ts = %d %d, PEs = %g %g, Bz = %g %g\n", me_universe,partner,swap,my_set_temp,partner_set_temp, pe,pe_partner,boltz_factor,exp(boltz_factor)); #endif } // bcast swap result to other procs in my world MPI_Bcast(&swap,1,MPI_INT,0,world); // rescale kinetic energy via velocities if move is accepted if (swap) scale_velocities(partner_set_temp,my_set_temp); // if my world swapped, all procs in world reset temp target of Fix if (swap) { new_temp = set_temp[partner_set_temp]; modify->fix[whichfix]->reset_target(new_temp); } // update my_set_temp and temp2world on every proc // root procs update their value if swap took place // allgather across root procs // bcast within my world if (swap) my_set_temp = partner_set_temp; if (me == 0) { MPI_Allgather(&my_set_temp,1,MPI_INT,world2temp,1,MPI_INT,roots); for (i = 0; i < nworlds; i++) temp2world[world2temp[i]] = i; } MPI_Bcast(temp2world,nworlds,MPI_INT,0,world); // print out current swap status if (me_universe == 0) print_status(); } timer->barrier_stop(TIME_LOOP); update->integrate->cleanup(); Finish finish(lmp); finish.end(1); update->whichflag = 0; update->firststep = update->laststep = 0; update->beginstep = update->endstep = 0; } /* ---------------------------------------------------------------------- scale kinetic energy via velocities a la Sugita ------------------------------------------------------------------------- */ void Temper::scale_velocities(int t_partner, int t_me) { double sfactor = sqrt(set_temp[t_partner]/set_temp[t_me]); double **v = atom->v; int nlocal = atom->nlocal; for (int i = 0; i < nlocal; i++) { v[i][0] = v[i][0]*sfactor; v[i][1] = v[i][1]*sfactor; v[i][2] = v[i][2]*sfactor; } } /* ---------------------------------------------------------------------- proc 0 prints current tempering status ------------------------------------------------------------------------- */ void Temper::print_status() { if (universe->uscreen) { - fprintf(universe->uscreen,"%d ",update->ntimestep); + fprintf(universe->uscreen,BIGINT_FORMAT,update->ntimestep); for (int i = 0; i < nworlds; i++) - fprintf(universe->uscreen,"%d ",world2temp[i]); + fprintf(universe->uscreen," %d",world2temp[i]); fprintf(universe->uscreen,"\n"); } if (universe->ulogfile) { - fprintf(universe->ulogfile,"%d ",update->ntimestep); + fprintf(universe->ulogfile,BIGINT_FORMAT,update->ntimestep); for (int i = 0; i < nworlds; i++) - fprintf(universe->ulogfile,"%d ",world2temp[i]); + fprintf(universe->ulogfile," %d",world2temp[i]); fprintf(universe->ulogfile,"\n"); fflush(universe->ulogfile); } } diff --git a/src/SRD/fix_srd.cpp b/src/SRD/fix_srd.cpp index a59d10599..71ce7698e 100644 --- a/src/SRD/fix_srd.cpp +++ b/src/SRD/fix_srd.cpp @@ -1,3534 +1,3528 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- Contributing authors: Jeremy Lechman (SNL), Pieter in 't Veld (BASF) ------------------------------------------------------------------------- */ #include "math.h" #include "string.h" #include "stdlib.h" #include "fix_srd.h" #include "atom.h" #include "atom_vec.h" #include "group.h" #include "update.h" #include "force.h" #include "pair.h" #include "domain.h" #include "neighbor.h" #include "comm.h" #include "modify.h" #include "fix_deform.h" #include "fix_wall_srd.h" #include "random_mars.h" #include "random_park.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; enum{SLIP,NOSLIP}; enum{SPHERE,ELLIPSOID,WALL}; enum{SPHERE_SHAPE,SPHERE_RADIUS}; enum{ANGULAR_OMEGA,ANGULAR_ANGMOM}; enum{INSIDE_ERROR,INSIDE_WARN,INSIDE_IGNORE}; enum{BIG_MOVE,SRD_MOVE,SRD_ROTATE}; enum{CUBIC_ERROR,CUBIC_WARN}; enum{SHIFT_NO,SHIFT_YES,SHIFT_POSSIBLE}; enum{NO_REMAP,X_REMAP,V_REMAP}; // same as fix_deform.cpp #define INERTIA 0.4 #define ATOMPERBIN 10 #define BIG 1.0e20 #define VBINSIZE 5 #define MIN(A,B) ((A) < (B)) ? (A) : (B) #define MAX(A,B) ((A) > (B)) ? (A) : (B) //#define SRD_DEBUG 1 //#define SRD_DEBUG_ATOMID 58 //#define SRD_DEBUG_TIMESTEP 449 /* ---------------------------------------------------------------------- */ FixSRD::FixSRD(LAMMPS *lmp, int narg, char **arg) : Fix(lmp, narg, arg) { if (narg < 8) error->all("Illegal fix srd command"); restart_pbc = 1; vector_flag = 1; size_vector = 12; global_freq = 1; extvector = 0; nevery = atoi(arg[3]); bigexist = 1; if (strcmp(arg[4],"NULL") == 0) bigexist = 0; else biggroup = group->find(arg[4]); temperature_srd = atof(arg[5]); gridsrd = atof(arg[6]); int seed = atoi(arg[7]); // parse options lamdaflag = 0; collidestyle = NOSLIP; overlap = 0; insideflag = INSIDE_ERROR; exactflag = 1; radfactor = 1.0; maxbounceallow = 0; gridsearch = gridsrd; cubicflag = CUBIC_ERROR; cubictol = 0.01; shiftuser = SHIFT_NO; shiftseed = 0; streamflag = 1; int iarg = 8; while (iarg < narg) { if (strcmp(arg[iarg],"lamda") == 0) { if (iarg+2 > narg) error->all("Illegal fix srd command"); lamda = atof(arg[iarg+1]); lamdaflag = 1; iarg += 2; } else if (strcmp(arg[iarg],"collision") == 0) { if (iarg+2 > narg) error->all("Illegal fix srd command"); if (strcmp(arg[iarg+1],"slip") == 0) collidestyle = SLIP; else if (strcmp(arg[iarg+1],"noslip") == 0) collidestyle = NOSLIP; else error->all("Illegal fix srd command"); iarg += 2; } else if (strcmp(arg[iarg],"overlap") == 0) { if (iarg+2 > narg) error->all("Illegal fix srd command"); if (strcmp(arg[iarg+1],"yes") == 0) overlap = 1; else if (strcmp(arg[iarg+1],"no") == 0) overlap = 0; else error->all("Illegal fix srd command"); iarg += 2; } else if (strcmp(arg[iarg],"inside") == 0) { if (iarg+2 > narg) error->all("Illegal fix srd command"); if (strcmp(arg[iarg+1],"error") == 0) insideflag = INSIDE_ERROR; else if (strcmp(arg[iarg+1],"warn") == 0) insideflag = INSIDE_WARN; else if (strcmp(arg[iarg+1],"ignore") == 0) insideflag = INSIDE_IGNORE; else error->all("Illegal fix srd command"); iarg += 2; } else if (strcmp(arg[iarg],"exact") == 0) { if (iarg+2 > narg) error->all("Illegal fix srd command"); if (strcmp(arg[iarg+1],"yes") == 0) exactflag = 1; else if (strcmp(arg[iarg+1],"no") == 0) exactflag = 0; else error->all("Illegal fix srd command"); iarg += 2; } else if (strcmp(arg[iarg],"radius") == 0) { if (iarg+2 > narg) error->all("Illegal fix srd command"); radfactor = atof(arg[iarg+1]); iarg += 2; } else if (strcmp(arg[iarg],"bounce") == 0) { if (iarg+2 > narg) error->all("Illegal fix srd command"); maxbounceallow = atoi(arg[iarg+1]); iarg += 2; } else if (strcmp(arg[iarg],"search") == 0) { if (iarg+2 > narg) error->all("Illegal fix srd command"); gridsearch = atof(arg[iarg+1]); iarg += 2; } else if (strcmp(arg[iarg],"cubic") == 0) { if (iarg+3 > narg) error->all("Illegal fix srd command"); if (strcmp(arg[iarg+1],"error") == 0) cubicflag = CUBIC_ERROR; else if (strcmp(arg[iarg+1],"warn") == 0) cubicflag = CUBIC_WARN; else error->all("Illegal fix srd command"); cubictol = atof(arg[iarg+2]); iarg += 3; } else if (strcmp(arg[iarg],"shift") == 0) { if (iarg+3 > narg) error->all("Illegal fix srd command"); else if (strcmp(arg[iarg+1],"no") == 0) shiftuser = SHIFT_NO; else if (strcmp(arg[iarg+1],"yes") == 0) shiftuser = SHIFT_YES; else if (strcmp(arg[iarg+1],"possible") == 0) shiftuser = SHIFT_POSSIBLE; else error->all("Illegal fix srd command"); shiftseed = atoi(arg[iarg+2]); iarg += 3; } else if (strcmp(arg[iarg],"stream") == 0) { if (iarg+2 > narg) error->all("Illegal fix srd command"); if (strcmp(arg[iarg+1],"yes") == 0) streamflag = 1; else if (strcmp(arg[iarg+1],"no") == 0) streamflag = 0; else error->all("Illegal fix srd command"); iarg += 2; } else error->all("Illegal fix srd command"); } // error check if (nevery <= 0) error->all("Illegal fix srd command"); if (bigexist && biggroup < 0) error->all("Could not find fix srd group ID"); if (gridsrd <= 0.0) error->all("Illegal fix srd command"); if (temperature_srd <= 0.0) error->all("Illegal fix srd command"); if (seed <= 0) error->all("Illegal fix srd command"); if (radfactor <= 0.0) error->all("Illegal fix srd command"); if (maxbounceallow < 0) error->all("Illegal fix srd command"); if (lamdaflag && lamda <= 0.0) error->all("Illegal fix srd command"); if (gridsearch <= 0.0) error->all("Illegal fix srd command"); if (cubictol < 0.0 || cubictol > 1.0) error->all("Illegal fix srd command"); if ((shiftuser == SHIFT_YES || shiftuser == SHIFT_POSSIBLE) && shiftseed <= 0) error->all("Illegal fix srd command"); // initialize Marsaglia RNG with processor-unique seed me = comm->me; nprocs = comm->nprocs; random = new RanMars(lmp,seed + me); // if requested, initialize shift RNG, same on every proc if (shiftuser == SHIFT_YES || shiftuser == SHIFT_POSSIBLE) randomshift = new RanPark(lmp,shiftseed); else randomshift = NULL; // initialize data structs and flags if (bigexist) biggroupbit = group->bitmask[biggroup]; else biggroupbit = 0; nmax = 0; binhead = NULL; maxbin1 = 0; binnext = NULL; maxbuf = 0; sbuf1 = sbuf2 = rbuf1 = rbuf2 = NULL; shifts[0].maxvbin = shifts[1].maxvbin = 0; shifts[0].vbin = shifts[1].vbin = NULL; shifts[0].maxbinsq = shifts[1].maxbinsq = 0; for (int ishift = 0; ishift < 2; ishift++) for (int iswap = 0; iswap < 6; iswap++) shifts[ishift].bcomm[iswap].sendlist = shifts[ishift].bcomm[iswap].recvlist = NULL; maxbin2 = 0; nbinbig = NULL; binbig = NULL; binsrd = NULL; nstencil = maxstencil = 0; stencil = NULL; maxbig = 0; biglist = NULL; stats_flag = 1; for (int i = 0; i < size_vector; i++) stats_all[i] = 0.0; initflag = 0; srd_bin_temp = 0.0; srd_bin_count = 0; // fix parameters if (collidestyle == SLIP) comm_reverse = 3; else comm_reverse = 6; force_reneighbor = 1; } /* ---------------------------------------------------------------------- */ FixSRD::~FixSRD() { delete random; delete randomshift; memory->sfree(binhead); memory->sfree(binnext); memory->sfree(sbuf1); memory->sfree(sbuf2); memory->sfree(rbuf1); memory->sfree(rbuf2); memory->sfree(shifts[0].vbin); memory->sfree(shifts[1].vbin); for (int ishift = 0; ishift < 2; ishift++) for (int iswap = 0; iswap < 6; iswap++) { memory->sfree(shifts[ishift].bcomm[iswap].sendlist); memory->sfree(shifts[ishift].bcomm[iswap].recvlist); } memory->sfree(nbinbig); memory->destroy_2d_int_array(binbig); memory->sfree(binsrd); memory->destroy_2d_int_array(stencil); memory->sfree(biglist); } /* ---------------------------------------------------------------------- */ int FixSRD::setmask() { int mask = 0; mask |= PRE_NEIGHBOR; mask |= POST_FORCE; return mask; } /* ---------------------------------------------------------------------- */ void FixSRD::init() { // error checks if (force->newton_pair == 0) error->all("Fix srd requires newton pair on"); if (bigexist && comm->ghost_velocity == 0) error->all("Fix srd requires ghost atoms store velocity"); if (bigexist && !atom->radius_flag && !atom->avec->shape_type) error->all("Fix SRD requires atom attribute radius or shape"); if (bigexist && !atom->angmom_flag && !atom->omega_flag) error->all("Fix SRD requires atom attribute angmom or omega"); if (bigexist && atom->angmom_flag && atom->omega_flag) error->all("Fix SRD cannot have both atom attributes angmom and omega"); if (bigexist && collidestyle == NOSLIP && !atom->torque_flag) error->all("Fix SRD no-slip requires atom attribute torque"); if (initflag && update->dt != dt_big) error->all("Cannot change timestep once fix srd is setup"); // orthogonal vs triclinic simulation box // could be static or shearing box triclinic = domain->triclinic; // wallexist = 1 if SRD wall(s) are defined wallexist = 0; for (int m = 0; m < modify->nfix; m++) { if (strcmp(modify->fix[m]->style,"wall/srd") == 0) { if (wallexist) error->all("Cannot use fix wall/srd more than once"); wallexist = 1; wallfix = (FixWallSRD *) modify->fix[m]; nwall = wallfix->nwall; wallvarflag = wallfix->varflag; wallwhich = wallfix->wallwhich; xwall = wallfix->xwall; xwallhold = wallfix->xwallhold; vwall = wallfix->vwall; fwall = wallfix->fwall; walltrigger = 0.5 * neighbor->skin; if (wallfix->overlap && overlap == 0 && me == 0) error->warning("Fix SRD walls overlap but fix srd overlap not set"); } } // set change_flags if box size or shape changes change_size = change_shape = 0; if (domain->nonperiodic == 2) change_size = 1; for (int i = 0; i < modify->nfix; i++) if (modify->fix[i]->box_change) { if (modify->fix[i]->box_change_size) change_size = 1; if (modify->fix[i]->box_change_shape) change_shape = 1; if (strcmp(modify->fix[i]->style,"deform") == 0) { FixDeform *deform = (FixDeform *) modify->fix[i]; if (deform->box_change_shape && deform->remapflag != V_REMAP) error->all("Using fix srd with inconsistent " "fix deform remap option"); } } // parameterize based on current box volume dimension = domain->dimension; parameterize(); // limit initial SRD velocities if necessary double **v = atom->v; int *mask = atom->mask; int nlocal = atom->nlocal; double vsq; nrescale = 0; for (int i = 0; i < nlocal; i++) if (mask[i] & groupbit) { vsq = v[i][0]*v[i][0] + v[i][1]*v[i][1] + v[i][2]*v[i][2]; if (vsq > vmaxsq) nrescale++; } int all; MPI_Allreduce(&nrescale,&all,1,MPI_INT,MPI_SUM,world); if (me == 0) { if (screen) fprintf(screen," # of rescaled SRD velocities = %d\n",all); if (logfile) fprintf(logfile," # of rescaled SRD velocities = %d\n",all); } velocity_stats(igroup); if (bigexist) velocity_stats(biggroup); // zero per-run stats bouncemaxnum = 0; bouncemax = 0; reneighcount = 0; initflag = 1; next_reneighbor = -1; } /* ---------------------------------------------------------------------- */ void FixSRD::setup(int vflag) { setup_bounds(); if (dist_srd_reneigh < nevery*dt_big*vmax && me == 0) error->warning("Fix srd SRD moves may trigger frequent reneighboring"); // setup search bins and search stencil based on these distances if (bigexist || wallexist) { setup_search_bins(); setup_search_stencil(); } else nbins2 = 0; // perform first bining of SRD and big particles and walls // set reneighflag to turn off SRD rotation // don't do SRD rotation in setup, only during timestepping reneighflag = BIG_MOVE; pre_neighbor(); } /* ---------------------------------------------------------------------- assign SRD particles to bins assign big particles to all bins they overlap ------------------------------------------------------------------------- */ void FixSRD::pre_neighbor() { int i,j,m,ix,iy,iz,jx,jy,jz,ibin,jbin,lo,hi; double rsq,cutbinsq; double xlamda[3]; // grow SRD per-atom bin arrays if necessary if (atom->nlocal > nmax) { nmax = atom->nmax; memory->sfree(binsrd); memory->sfree(binnext); binsrd = (int *) memory->smalloc(nmax*sizeof(int),"fix/srd:binsrd"); binnext = (int *) memory->smalloc(nmax*sizeof(int),"fix/srd:binnext"); } // setup and grow BIG info list if necessary // set index ptrs to BIG particles and to WALLS // big_static() adds static properties to info list if (bigexist || wallexist) { if (bigexist) { if (biggroup == atom->firstgroup) nbig = atom->nfirst + atom->nghost; else { int *mask = atom->mask; int nlocal = atom->nlocal; nbig = atom->nghost; for (i = 0; i < nlocal; i++) if (mask[i] & biggroupbit) nbig++; } } else nbig = 0; int ninfo = nbig; if (wallexist) ninfo += nwall; if (ninfo > maxbig) { maxbig = ninfo; memory->sfree(biglist); biglist = (Big *) memory->smalloc(maxbig*sizeof(Big),"fix/srd:biglist"); } if (bigexist) { int *mask = atom->mask; int nlocal = atom->nlocal; if (biggroup == atom->firstgroup) nlocal = atom->nfirst; nbig = 0; for (i = 0; i < nlocal; i++) if (mask[i] & biggroupbit) biglist[nbig++].index = i; int nall = atom->nlocal + atom->nghost; for (i = atom->nlocal; i < nall; i++) if (mask[i] & biggroupbit) biglist[nbig++].index = i; big_static(); } if (wallexist) { for (m = 0; m < nwall; m++) { biglist[nbig+m].index = m; biglist[nbig+m].type = WALL; } wallfix->wall_params(1); } } // if simulation box size changes, reset velocity bins // if big particles exist, reset search bins if box size or shape changes, // b/c finite-size particles will overlap different bins as the box tilts if (change_size) setup_bounds(); if (change_size) setup_velocity_bins(); if ((change_size || change_shape) && (bigexist || wallexist)) { setup_search_bins(); setup_search_stencil(); } // map each owned & ghost big particle to search bins it overlaps // zero out bin counters for big particles // if firstgroup is defined, only loop over first and ghost particles // for each big particle: loop over stencil to find overlap bins int *mask = atom->mask; double **x = atom->x; int nlocal = atom->nlocal; int nall = nlocal + atom->nghost; int nfirst = nlocal; if (bigexist && biggroup == atom->firstgroup) nfirst = atom->nfirst; if (bigexist || wallexist) for (i = 0; i < nbins2; i++) nbinbig[i] = 0; if (bigexist) { i = nbig = 0; while (i < nall) { if (mask[i] & biggroupbit) { ix = static_cast<int> ((x[i][0]-xblo2)*bininv2x); iy = static_cast<int> ((x[i][1]-yblo2)*bininv2y); iz = static_cast<int> ((x[i][2]-zblo2)*bininv2z); ibin = iz*nbin2y*nbin2x + iy*nbin2x + ix; if (ix < 0 || ix >= nbin2x || iy < 0 || iy >= nbin2y || iz < 0 || iz >= nbin2z) error->one("Fix SRD: bad search bin assignment"); cutbinsq = biglist[nbig].cutbinsq; for (j = 0; j < nstencil; j++) { jx = ix + stencil[j][0]; jy = iy + stencil[j][1]; jz = iz + stencil[j][2]; if (jx < 0 || jx >= nbin2x || jy < 0 || jy >= nbin2y || jz < 0 || jz >= nbin2z) { printf("Big particle %d %d %g %g %g\n", atom->tag[i],i,x[i][0],x[i][1],x[i][2]); printf("Bin indices: %d %d %d, %d %d %d, %d %d %d\n", ix,iy,iz,jx,jy,jz,nbin2x,nbin2y,nbin2z); error->one("Fix SRD: bad stencil bin for big particle"); } rsq = point_bin_distance(x[i],jx,jy,jz); if (rsq < cutbinsq) { jbin = ibin + stencil[j][3]; if (nbinbig[jbin] == ATOMPERBIN) error->one("Fix SRD: too many big particles in bin"); binbig[jbin][nbinbig[jbin]++] = nbig; } } nbig++; } i++; if (i == nfirst) i = nlocal; } } // map each wall to search bins it covers, up to non-periodic boundary // if wall moves, add walltrigger to its position // this insures it is added to all search bins it may move into // may not overlap any of my search bins if (wallexist) { double delta = 0.0; if (wallvarflag) delta = walltrigger; for (m = 0; m < nwall; m++) { int dim = wallwhich[m] / 2; int side = wallwhich[m] % 2; if (dim == 0) { if (side == 0) { hi = static_cast<int> ((xwall[m]+delta-xblo2)*bininv2x); if (hi < 0) continue; if (hi >= nbin2x) error->all("Fix SRD: bad search bin assignment"); lo = 0; } else { lo = static_cast<int> ((xwall[m]-delta-xblo2)*bininv2x); if (lo >= nbin2x) continue; if (lo < 0) error->all("Fix SRD: bad search bin assignment"); hi = nbin2x-1; } for (ix = lo; ix <= hi; ix++) for (iy = 0; iy < nbin2y; iy++) for (iz = 0; iz < nbin2z; iz++) { ibin = iz*nbin2y*nbin2x + iy*nbin2x + ix; if (nbinbig[ibin] == ATOMPERBIN) error->all("Fix SRD: too many walls in bin"); binbig[ibin][nbinbig[ibin]++] = nbig+m; } } else if (dim == 1) { if (side == 0) { hi = static_cast<int> ((xwall[m]+delta-yblo2)*bininv2y); if (hi < 0) continue; if (hi >= nbin2y) error->all("Fix SRD: bad search bin assignment"); lo = 0; } else { lo = static_cast<int> ((xwall[m]-delta-yblo2)*bininv2y); if (lo >= nbin2y) continue; if (lo < 0) error->all("Fix SRD: bad search bin assignment"); hi = nbin2y-1; } for (iy = lo; iy <= hi; iy++) for (ix = 0; ix < nbin2x; ix++) for (iz = 0; iz < nbin2z; iz++) { ibin = iz*nbin2y*nbin2x + iy*nbin2x + ix; if (nbinbig[ibin] == ATOMPERBIN) error->all("Fix SRD: too many walls in bin"); binbig[ibin][nbinbig[ibin]++] = nbig+m; } } else if (dim == 2) { if (side == 0) { hi = static_cast<int> ((xwall[m]+delta-zblo2)*bininv2z); if (hi < 0) continue; if (hi >= nbin2z) error->all("Fix SRD: bad search bin assignment"); lo = 0; } else { lo = static_cast<int> ((xwall[m]-delta-zblo2)*bininv2z); if (lo >= nbin2z) continue; if (lo < 0) error->all("Fix SRD: bad search bin assignment"); hi = nbin2z-1; } for (iz = lo; iz < hi; iz++) for (ix = 0; ix < nbin2x; ix++) for (iy = 0; iy < nbin2y; iy++) { ibin = iz*nbin2y*nbin2x + iy*nbin2x + ix; if (nbinbig[ibin] == ATOMPERBIN) error->all("Fix SRD: too many walls in bin"); binbig[ibin][nbinbig[ibin]++] = nbig+m; } } } } // rotate SRD velocities on SRD timestep // done now since all SRDs are currently inside my sub-domain if (reneighflag == SRD_ROTATE) reset_velocities(); // log stats if reneighboring occurred b/c SRDs moved too far if (reneighflag == SRD_MOVE) reneighcount++; reneighflag = BIG_MOVE; } /* ---------------------------------------------------------------------- advect SRD particles and detect collisions between SRD and BIG particles when collision occurs, change x,v of SRD, force,torque of BIG particle ------------------------------------------------------------------------- */ void FixSRD::post_force(int vflag) { int i,m,ix,iy,iz; double xlamda[3]; // zero per-timestep stats stats_flag = 0; ncheck = ncollide = nbounce = ninside = nrescale = 0; // zero ghost forces & torques on BIG particles double **f = atom->f; double **torque = atom->torque; int nlocal = atom->nlocal; int nall = nlocal + atom->nghost; if (bigexist == 0) nall = 0; for (i = nlocal; i < nall; i++) f[i][0] = f[i][1] = f[i][2] = 0.0; if (collidestyle == NOSLIP) for (i = nlocal; i < nall; i++) torque[i][0] = torque[i][1] = torque[i][2] = 0.0; // advect SRD particles // assign to search bins if big particles or walls exist int *mask = atom->mask; double **x = atom->x; double **v = atom->v; if (bigexist || wallexist) { for (i = 0; i < nlocal; i++) if (mask[i] & groupbit) { x[i][0] += dt_big*v[i][0]; x[i][1] += dt_big*v[i][1]; x[i][2] += dt_big*v[i][2]; ix = static_cast<int> ((x[i][0]-xblo2)*bininv2x); iy = static_cast<int> ((x[i][1]-yblo2)*bininv2y); iz = static_cast<int> ((x[i][2]-zblo2)*bininv2z); binsrd[i] = iz*nbin2y*nbin2x + iy*nbin2x + ix; if (ix < 0 || ix >= nbin2x || iy < 0 || iy >= nbin2y || iz < 0 || iz >= nbin2z) { - printf("SRD particle %d on step %d\n", - atom->tag[i],update->ntimestep); + char fstr[64]; + sprintf(fstr,"SRD particle %%d on step %s\n",BIGINT_FORMAT); + printf(fstr,atom->tag[i],update->ntimestep); printf("v = %g %g %g\n",v[i][0],v[i][1],v[i][2]); printf("x = %g %g %g\n",x[i][0],x[i][1],x[i][2]); printf("ix,iy,iz nx,ny,nz = %d %d %d %d %d %d\n", ix,iy,iz,nbin2x,nbin2y,nbin2z); error->one("Fix SRD: bad bin assignment for SRD advection"); } } } else { for (i = 0; i < nlocal; i++) if (mask[i] & groupbit) { x[i][0] += dt_big*v[i][0]; x[i][1] += dt_big*v[i][1]; x[i][2] += dt_big*v[i][2]; } } // detect collision of SRDs with BIG particles or walls if (bigexist || wallexist) { if (bigexist && (collidestyle == NOSLIP || any_ellipsoids)) big_dynamic(); if (wallexist) wallfix->wall_params(0); if (overlap) collisions_multi(); else collisions_single(); } // reverse communicate forces & torques on BIG particles if (bigexist) { flocal = f; tlocal = torque; comm->reverse_comm_fix(this); } // if any SRD particle has moved too far, trigger reneigh on next step // for triclinic, perform check in lamda units int flag = 0; if (triclinic) domain->x2lamda(nlocal); for (i = 0; i < nlocal; i++) if (mask[i] & groupbit) { if (x[i][0] < srdlo_reneigh[0] || x[i][0] > srdhi_reneigh[0] || x[i][1] < srdlo_reneigh[1] || x[i][1] > srdhi_reneigh[1] || x[i][2] < srdlo_reneigh[2] || x[i][2] > srdhi_reneigh[2]) flag = 1; } if (triclinic) domain->lamda2x(nlocal); int flagall; MPI_Allreduce(&flag,&flagall,1,MPI_INT,MPI_SUM,world); if (flagall) { next_reneighbor = update->ntimestep + 1; reneighflag = SRD_MOVE; } // if wall has moved too far, trigger reneigh on next step // analagous to neighbor check for big particle moving 1/2 of skin distance if (wallexist) { for (m = 0; m < nwall; m++) if (fabs(xwall[m]-xwallhold[m]) > walltrigger) next_reneighbor = update->ntimestep + 1; } // if next timestep is SRD timestep, trigger reneigh if ((update->ntimestep+1) % nevery == 0) { next_reneighbor = update->ntimestep + 1; reneighflag = SRD_ROTATE; } } /* ---------------------------------------------------------------------- reset SRD velocities may perform random shifting by 1/2 bin in each dimension called at pre-neighbor stage when all SRDs are now inside my sub-domain for triclinic, will set mean velocity to box deformation velocity ------------------------------------------------------------------------- */ void FixSRD::reset_velocities() { int i,j,n,ix,iy,iz,ibin,axis,sign,irandom; double u[3],vave[3]; double vx,vy,vz,vsq; double *vold,*vnew,*xlamda; double vstream[3]; // if requested, perform a dynamic shift if (shiftflag) { double *boxlo; if (triclinic == 0) boxlo = domain->boxlo; else boxlo = domain->boxlo_lamda; shifts[1].corner[0] = boxlo[0] - binsize1x*randomshift->uniform(); shifts[1].corner[1] = boxlo[1] - binsize1y*randomshift->uniform(); if (dimension == 3) shifts[1].corner[2] = boxlo[2] - binsize1z*randomshift->uniform(); else shifts[1].corner[2] = boxlo[2]; setup_velocity_shift(1,1); } double *corner = shifts[shiftflag].corner; int *binlo = shifts[shiftflag].binlo; int *binhi = shifts[shiftflag].binhi; int nbins = shifts[shiftflag].nbins; int nbinx = shifts[shiftflag].nbinx; int nbiny = shifts[shiftflag].nbiny; BinAve *vbin = shifts[shiftflag].vbin; // binhead = 1st SRD particle in each bin // binnext = index of next particle in bin // bin assignment is done in lamda units for triclinic int *mask = atom->mask; double **x = atom->x; double **v = atom->v; int nlocal = atom->nlocal; if (triclinic) domain->x2lamda(nlocal); for (i = 0; i < nbins; i++) binhead[i] = -1; for (i = 0; i < nlocal; i++) if (mask[i] & groupbit) { ix = static_cast<int> ((x[i][0]-corner[0])*bininv1x); ix = MAX(ix,binlo[0]); ix = MIN(ix,binhi[0]); iy = static_cast<int> ((x[i][1]-corner[1])*bininv1y); iy = MAX(iy,binlo[1]); iy = MIN(iy,binhi[1]); iz = static_cast<int> ((x[i][2]-corner[2])*bininv1z); iz = MAX(iz,binlo[2]); iz = MIN(iz,binhi[2]); ibin = (iz-binlo[2])*nbiny*nbinx + (iy-binlo[1])*nbinx + (ix-binlo[0]); binnext[i] = binhead[ibin]; binhead[ibin] = i; } if (triclinic) domain->lamda2x(nlocal); if (triclinic && streamflag) { double *h_rate = domain->h_rate; double *h_ratelo = domain->h_ratelo; for (i = 0; i < nlocal; i++) if (mask[i] & groupbit) { xlamda = x[i]; v[i][0] -= h_rate[0]*xlamda[0] + h_rate[5]*xlamda[1] + h_rate[4]*xlamda[2] + h_ratelo[0]; v[i][1] -= h_rate[1]*xlamda[1] + h_rate[3]*xlamda[2] + h_ratelo[1]; v[i][2] -= h_rate[2]*xlamda[2] + h_ratelo[2]; } } // for each bin I have particles contributing to: // compute ave v and v^2 of particles in that bin // if I own the bin, set its random value, else set to 0.0 for (i = 0; i < nbins; i++) { n = 0; vave[0] = vave[1] = vave[2] = 0.0; for (j = binhead[i]; j >= 0; j = binnext[j]) { vx = v[j][0]; vy = v[j][1]; vz = v[j][2]; vave[0] += vx; vave[1] += vy; vave[2] += vz; n++; } vbin[i].vave[0] = vave[0]; vbin[i].vave[1] = vave[1]; vbin[i].vave[2] = vave[2]; vbin[i].n = n; if (vbin[i].owner) vbin[i].random = random->uniform(); else vbin[i].random = 0.0; } // communicate bin info for bins which more than 1 proc contribute to if (shifts[shiftflag].commflag) vbin_comm(shiftflag); // for each bin I have particles contributing to: // reassign particle velocity by rotation around a random axis // accumulate T_srd for each bin I own // for triclinic, replace mean velocity with stream velocity srd_bin_temp = 0.0; srd_bin_count = 0; if (dimension == 2) axis = 2; for (i = 0; i < nbins; i++) { n = vbin[i].n; if (n == 0) continue; vold = vbin[i].vave; vold[0] /= n; vold[1] /= n; vold[2] /= n; // if (triclinic && streamflag) { // xlamda = vbin[i].xctr; // vstream[0] = h_rate[0]*xlamda[0] + h_rate[5]*xlamda[1] + // h_rate[4]*xlamda[2] + h_ratelo[0]; // vstream[1] = h_rate[1]*xlamda[1] + h_rate[3]*xlamda[2] + h_ratelo[1]; // vstream[2] = h_rate[2]*xlamda[2] + h_ratelo[2]; // vnew = vstream; //} else vnew = vold; vnew = vold; irandom = static_cast<int> (6.0*vbin[i].random); sign = irandom % 2; if (dimension == 3) axis = irandom / 2; vsq = 0.0; for (j = binhead[i]; j >= 0; j = binnext[j]) { if (axis == 0) { u[0] = v[j][0]-vold[0]; u[1] = sign ? v[j][2]-vold[2] : vold[2]-v[j][2]; u[2] = sign ? vold[1]-v[j][1] : v[j][1]-vold[1]; } else if (axis == 1) { u[1] = v[j][1]-vold[1]; u[0] = sign ? v[j][2]-vold[2] : vold[2]-v[j][2]; u[2] = sign ? vold[0]-v[j][0] : v[j][0]-vold[0]; } else { u[2] = v[j][2]-vold[2]; u[1] = sign ? v[j][0]-vold[0] : vold[0]-v[j][0]; u[0] = sign ? vold[1]-v[j][1] : v[j][1]-vold[1]; } vsq += u[0]*u[0] + u[1]*u[1] + u[2]*u[2]; v[j][0] = u[0] + vnew[0]; v[j][1] = u[1] + vnew[1]; v[j][2] = u[2] + vnew[2]; } // sum partial contribution of my particles to T even if I don't own bin // but only count bin if I own it, so that bin is counted exactly once if (n > 1) { srd_bin_temp += vsq / (n-1); if (vbin[i].owner) srd_bin_count++; } } srd_bin_temp *= force->mvv2e * mass_srd / (dimension * force->boltz); if (triclinic && streamflag) { double *h_rate = domain->h_rate; double *h_ratelo = domain->h_ratelo; for (i = 0; i < nlocal; i++) if (mask[i] & groupbit) { xlamda = x[i]; v[i][0] += h_rate[0]*xlamda[0] + h_rate[5]*xlamda[1] + h_rate[4]*xlamda[2] + h_ratelo[0]; v[i][1] += h_rate[1]*xlamda[1] + h_rate[3]*xlamda[2] + h_ratelo[1]; v[i][2] += h_rate[2]*xlamda[2] + h_ratelo[2]; } } // rescale any too-large velocities for (i = 0; i < nlocal; i++) if (mask[i] & groupbit) { vsq = v[i][0]*v[i][0] + v[i][1]*v[i][1] + v[i][2]*v[i][2]; if (vsq > vmaxsq) nrescale++; } } /* ---------------------------------------------------------------------- communicate summed particle info for bins that overlap 1 or more procs ------------------------------------------------------------------------- */ void FixSRD::vbin_comm(int ishift) { BinComm *bcomm1,*bcomm2; MPI_Request request1,request2; MPI_Status status; // send/recv bins in both directions in each dimension // don't send if nsend = 0 // due to static bins aliging with proc boundary // due to dynamic bins across non-periodic global boundary // copy to self if sendproc = me // MPI send to another proc if sendproc != me // don't recv if nrecv = 0 // copy from self if recvproc = me // MPI recv from another proc if recvproc != me BinAve *vbin = shifts[ishift].vbin; int *procgrid = comm->procgrid; int iswap = 0; for (int idim = 0; idim < dimension; idim++) { bcomm1 = &shifts[ishift].bcomm[iswap++]; bcomm2 = &shifts[ishift].bcomm[iswap++]; if (procgrid[idim] == 1) { if (bcomm1->nsend) vbin_pack(vbin,bcomm1->nsend,bcomm1->sendlist,sbuf1); if (bcomm2->nsend) vbin_pack(vbin,bcomm2->nsend,bcomm2->sendlist,sbuf2); if (bcomm1->nrecv) vbin_unpack(sbuf1,vbin,bcomm1->nrecv,bcomm1->recvlist); if (bcomm2->nrecv) vbin_unpack(sbuf2,vbin,bcomm2->nrecv,bcomm2->recvlist); } else { if (bcomm1->nrecv) MPI_Irecv(rbuf1,bcomm1->nrecv*VBINSIZE,MPI_DOUBLE,bcomm1->recvproc,0, world,&request1); if (bcomm2->nrecv) MPI_Irecv(rbuf2,bcomm2->nrecv*VBINSIZE,MPI_DOUBLE,bcomm2->recvproc,0, world,&request2); if (bcomm1->nsend) { vbin_pack(vbin,bcomm1->nsend,bcomm1->sendlist,sbuf1); MPI_Send(sbuf1,bcomm1->nsend*VBINSIZE,MPI_DOUBLE, bcomm1->sendproc,0,world); } if (bcomm2->nsend) { vbin_pack(vbin,bcomm2->nsend,bcomm2->sendlist,sbuf2); MPI_Send(sbuf2,bcomm2->nsend*VBINSIZE,MPI_DOUBLE, bcomm2->sendproc,0,world); } if (bcomm1->nrecv) { MPI_Wait(&request1,&status); vbin_unpack(rbuf1,vbin,bcomm1->nrecv,bcomm1->recvlist); } if (bcomm2->nrecv) { MPI_Wait(&request2,&status); vbin_unpack(rbuf2,vbin,bcomm2->nrecv,bcomm2->recvlist); } } } } /* ---------------------------------------------------------------------- pack velocity bin data into a message buffer for sending ------------------------------------------------------------------------- */ void FixSRD::vbin_pack(BinAve *vbin, int n, int *list, double *buf) { int j; int m = 0; for (int i = 0; i < n; i++) { j = list[i]; buf[m++] = vbin[j].n; buf[m++] = vbin[j].vave[0]; buf[m++] = vbin[j].vave[1]; buf[m++] = vbin[j].vave[2]; buf[m++] = vbin[j].random; } } /* ---------------------------------------------------------------------- unpack velocity bin data from a message buffer and sum values to my bins ------------------------------------------------------------------------- */ void FixSRD::vbin_unpack(double *buf, BinAve *vbin, int n, int *list) { int j; int m = 0; for (int i = 0; i < n; i++) { j = list[i]; vbin[j].n += static_cast<int> (buf[m++]); vbin[j].vave[0] += buf[m++]; vbin[j].vave[1] += buf[m++]; vbin[j].vave[2] += buf[m++]; vbin[j].random += buf[m++]; } } /* ---------------------------------------------------------------------- detect all collisions between SRD and BIG particles or WALLS assume SRD can be inside at most one BIG particle or WALL at a time unoverlap SRDs for each collision ------------------------------------------------------------------------- */ void FixSRD::collisions_single() { int i,j,k,m,type,mbig,ibin,ibounce,inside,collide_flag; double dt,t_remain; double norm[3],xscoll[3],xbcoll[3],vsnew[3]; Big *big; // outer loop over SRD particles // inner loop over BIG particles or WALLS that overlap SRD particle bin // if overlap between SRD and BIG particle or wall: // for exact, compute collision pt in time // for inexact, push SRD to surf of BIG particle or WALL // update x,v of SRD and f,torque on BIG particle // re-bin SRD particle after collision // iterate until the SRD particle has no overlaps with BIG particles or WALLS double **x = atom->x; double **v = atom->v; double **f = atom->f; double **torque = atom->torque; int *mask = atom->mask; int nlocal = atom->nlocal; for (i = 0; i < nlocal; i++) { if (!(mask[i] & groupbit)) continue; ibin = binsrd[i]; if (nbinbig[ibin] == 0) continue; ibounce = 0; collide_flag = 1; dt = dt_big; while (collide_flag) { mbig = nbinbig[ibin]; if (ibounce == 0) ncheck += mbig; collide_flag = 0; for (m = 0; m < mbig; m++) { k = binbig[ibin][m]; big = &biglist[k]; j = big->index; type = big->type; if (type == SPHERE) inside = inside_sphere(x[i],x[j],big); else if (type == ELLIPSOID) inside = inside_ellipsoid(x[i],x[j],big); else inside = inside_wall(x[i],j); if (inside) { if (exactflag) { if (type == SPHERE) t_remain = collision_sphere_exact(x[i],x[j],v[i],v[j],big, xscoll,xbcoll,norm); else if (type == ELLIPSOID) t_remain = collision_ellipsoid_exact(x[i],x[j],v[i],v[j],big, xscoll,xbcoll,norm); else t_remain = collision_wall_exact(x[i],j,v[i],xscoll,xbcoll,norm); } else { t_remain = 0.5*dt; if (type == SPHERE) collision_sphere_inexact(x[i],x[j],big,xscoll,xbcoll,norm); else if (type == ELLIPSOID) collision_ellipsoid_inexact(x[i],x[j],big,xscoll,xbcoll,norm); else collision_wall_inexact(x[i],j,xscoll,xbcoll,norm); } #ifdef SRD_DEBUG if (update->ntimestep == SRD_DEBUG_TIMESTEP && atom->tag[i] == SRD_DEBUG_ATOMID) print_collision(i,j,ibounce,t_remain,dt,xscoll,xbcoll,norm,type); #endif if (t_remain > dt) { ninside++; - if (insideflag == INSIDE_ERROR) { - char str[128]; - if (type != WALL) - sprintf(str,"SRD particle %d started " - "inside big particle %d on step %d bounce %d\n", + if (insideflag == INSIDE_ERROR || insideflag == INSIDE_WARN) { + char str[128],fstr[128]; + if (type != WALL) { + sprintf(fstr,"SRD particle %%d started " + "inside big particle %%d on step %s bounce %%d\n", + BIGINT_FORMAT); + sprintf(str,fstr, atom->tag[i],atom->tag[j],update->ntimestep,ibounce+1); - else - sprintf(str,"SRD particle %d started " - "inside wall %d on step %d bounce %d\n", - atom->tag[i],j,update->ntimestep,ibounce+1); - error->one(str); - } - if (insideflag == INSIDE_WARN) { - char str[128]; - if (type != WALL) - sprintf(str,"SRD particle %d started " - "inside big particle %d on step %d bounce %d\n", - atom->tag[i],atom->tag[j],update->ntimestep,ibounce+1); - else - sprintf(str,"SRD particle %d started " - "inside wall %d on step %d bounce %d\n", + } else { + sprintf(fstr,"SRD particle %%d started " + "inside wall %%d on step %s bounce %%d\n", + BIGINT_FORMAT); + sprintf(str,fstr, atom->tag[i],j,update->ntimestep,ibounce+1); + } + if (insideflag == INSIDE_ERROR) error->one(str); error->warning(str); } break; } if (collidestyle == SLIP) { if (type == SPHERE) slip_sphere(v[i],v[j],norm,vsnew); else if (type == ELLIPSOID) slip_ellipsoid(v[i],v[j],x[j],big,xscoll,norm,vsnew); else slip_wall(v[i],j,norm,vsnew); } else { if (type != WALL) noslip(v[i],v[j],x[j],big,xscoll,norm,vsnew); else noslip_wall(v[i],j,xscoll,norm,vsnew); } if (dimension == 2) vsnew[2] = 0.0; // check on rescaling of vsnew double vsq = vsnew[0]*vsnew[0] + vsnew[1]*vsnew[1] + vsnew[2]*vsnew[2]; if (vsq > vmaxsq) nrescale++; // update BIG particle and WALL and SRD // BIG particle is not torqued if sphere and SLIP collision if (collidestyle == SLIP && type == SPHERE) force_torque(v[i],vsnew,xscoll,xbcoll,f[j],NULL); else if (type != WALL) force_torque(v[i],vsnew,xscoll,xbcoll,f[j],torque[j]); else if (type == WALL) force_wall(v[i],vsnew,j); ibin = binsrd[i] = update_srd(i,t_remain,xscoll,vsnew,x[i],v[i]); if (ibounce == 0) ncollide++; ibounce++; if (ibounce < maxbounceallow || maxbounceallow == 0) collide_flag = 1; dt = t_remain; break; } } } nbounce += ibounce; if (maxbounceallow && ibounce >= maxbounceallow) bouncemaxnum++; if (ibounce > bouncemax) bouncemax = ibounce; } } /* ---------------------------------------------------------------------- detect all collisions between SRD and big particles an SRD can be inside more than one big particle at a time requires finding which big particle SRD collided with first unoverlap SRDs for each collision ------------------------------------------------------------------------- */ void FixSRD::collisions_multi() { int i,j,k,m,type,mbig,ibin,ibounce,inside,jfirst,typefirst; double dt,t_remain,t_first; double norm[3],xscoll[3],xbcoll[3],vsnew[3]; double normfirst[3],xscollfirst[3],xbcollfirst[3]; Big *big; // outer loop over SRD particles // inner loop over BIG particles or WALLS that overlap SRD particle bin // loop over all BIG and WALLS to find which one SRD collided with first // if overlap between SRD and BIG particle or wall: // compute collision pt in time // update x,v of SRD and f,torque on BIG particle // re-bin SRD particle after collision // iterate until the SRD particle has no overlaps with BIG particles or WALLS double **x = atom->x; double **v = atom->v; double **f = atom->f; double **torque = atom->torque; int *mask = atom->mask; int nlocal = atom->nlocal; for (i = 0; i < nlocal; i++) { if (!(mask[i] & groupbit)) continue; ibin = binsrd[i]; if (nbinbig[ibin] == 0) continue; ibounce = 0; dt = dt_big; while (1) { mbig = nbinbig[ibin]; if (ibounce == 0) ncheck += mbig; t_first = 0.0; for (m = 0; m < mbig; m++) { k = binbig[ibin][m]; big = &biglist[k]; j = big->index; type = big->type; if (type == SPHERE) inside = inside_sphere(x[i],x[j],big); else if (type == ELLIPSOID) inside = inside_ellipsoid(x[i],x[j],big); else inside = inside_wall(x[i],j); if (inside) { if (type == SPHERE) t_remain = collision_sphere_exact(x[i],x[j],v[i],v[j],big, xscoll,xbcoll,norm); else if (type == ELLIPSOID) t_remain = collision_ellipsoid_exact(x[i],x[j],v[i],v[j],big, xscoll,xbcoll,norm); else t_remain = collision_wall_exact(x[i],j,v[i],xscoll,xbcoll,norm); #ifdef SRD_DEBUG if (update->ntimestep == SRD_DEBUG_TIMESTEP && atom->tag[i] == SRD_DEBUG_ATOMID) print_collision(i,j,ibounce,t_remain,dt,xscoll,xbcoll,norm,type); #endif if (t_remain > dt || t_remain < 0.0) { ninside++; - if (insideflag == INSIDE_ERROR) { - char str[128]; - sprintf(str,"SRD particle %d started " - "inside big particle %d on step %d bounce %d\n", - atom->tag[i],atom->tag[j],update->ntimestep,ibounce+1); - error->one(str); - } - if (insideflag == INSIDE_WARN) { - char str[128]; - sprintf(str,"SRD particle %d started " - "inside big particle %d on step %d bounce %d\n", + if (insideflag == INSIDE_ERROR || insideflag == INSIDE_WARN) { + char str[128],fstr[128]; + sprintf(fstr,"SRD particle %%d started " + "inside big particle %%d on step %s bounce %%d\n", + BIGINT_FORMAT); + sprintf(str,fstr, atom->tag[i],atom->tag[j],update->ntimestep,ibounce+1); + if (insideflag == INSIDE_ERROR) error->one(str); error->warning(str); } t_first = 0.0; break; } if (t_remain > t_first) { t_first = t_remain; jfirst = j; typefirst = type; xscollfirst[0] = xscoll[0]; xscollfirst[1] = xscoll[1]; xscollfirst[2] = xscoll[2]; xbcollfirst[0] = xbcoll[0]; xbcollfirst[1] = xbcoll[1]; xbcollfirst[2] = xbcoll[2]; normfirst[0] = norm[0]; normfirst[1] = norm[1]; normfirst[2] = norm[2]; } } } if (t_first == 0.0) break; j = jfirst; type = typefirst; xscoll[0] = xscollfirst[0]; xscoll[1] = xscollfirst[1]; xscoll[2] = xscollfirst[2]; xbcoll[0] = xbcollfirst[0]; xbcoll[1] = xbcollfirst[1]; xbcoll[2] = xbcollfirst[2]; norm[0] = normfirst[0]; norm[1] = normfirst[1]; norm[2] = normfirst[2]; if (collidestyle == SLIP) { if (type == SPHERE) slip_sphere(v[i],v[j],norm,vsnew); else if (type == ELLIPSOID) slip_ellipsoid(v[i],v[j],x[j],big,xscoll,norm,vsnew); else slip_wall(v[i],j,norm,vsnew); } else { if (type != WALL) noslip(v[i],v[j],x[j],big,xscoll,norm,vsnew); else noslip_wall(v[i],j,xscoll,norm,vsnew); } if (dimension == 2) vsnew[2] = 0.0; // check on rescaling of vsnew double vsq = vsnew[0]*vsnew[0] + vsnew[1]*vsnew[1] + vsnew[2]*vsnew[2]; if (vsq > vmaxsq) nrescale++; // update BIG particle and WALL and SRD // BIG particle is not torqued if sphere and SLIP collision if (collidestyle == SLIP && type == SPHERE) force_torque(v[i],vsnew,xscoll,xbcoll,f[j],NULL); else if (type != WALL) force_torque(v[i],vsnew,xscoll,xbcoll,f[j],torque[j]); else if (type == WALL) force_wall(v[i],vsnew,j); ibin = binsrd[i] = update_srd(i,t_first,xscoll,vsnew,x[i],v[i]); if (ibounce == 0) ncollide++; ibounce++; if (ibounce == maxbounceallow) break; dt = t_first; } nbounce += ibounce; if (maxbounceallow && ibounce >= maxbounceallow) bouncemaxnum++; if (ibounce > bouncemax) bouncemax = ibounce; } } /* ---------------------------------------------------------------------- check if SRD particle S is inside spherical big particle B ------------------------------------------------------------------------- */ int FixSRD::inside_sphere(double *xs, double *xb, Big *big) { double dx,dy,dz; dx = xs[0] - xb[0]; dy = xs[1] - xb[1]; dz = xs[2] - xb[2]; if (dx*dx + dy*dy + dz*dz <= big->radsq) return 1; return 0; } /* ---------------------------------------------------------------------- check if SRD particle S is inside ellipsoidal big particle B ------------------------------------------------------------------------- */ int FixSRD::inside_ellipsoid(double *xs, double *xb, Big *big) { double x,y,z; double *ex = big->ex; double *ey = big->ey; double *ez = big->ez; double xs_xb[3]; xs_xb[0] = xs[0] - xb[0]; xs_xb[1] = xs[1] - xb[1]; xs_xb[2] = xs[2] - xb[2]; x = xs_xb[0]*ex[0] + xs_xb[1]*ex[1] + xs_xb[2]*ex[2]; y = xs_xb[0]*ey[0] + xs_xb[1]*ey[1] + xs_xb[2]*ey[2]; z = xs_xb[0]*ez[0] + xs_xb[1]*ez[1] + xs_xb[2]*ez[2]; if (x*x*big->aradsqinv + y*y*big->bradsqinv + z*z*big->cradsqinv <= 1.0) return 1; return 0; } /* ---------------------------------------------------------------------- check if SRD particle S is inside wall IWALL ------------------------------------------------------------------------- */ int FixSRD::inside_wall(double *xs, int iwall) { int dim = wallwhich[iwall] / 2; int side = wallwhich[iwall] % 2; if (side == 0 && xs[dim] < xwall[iwall]) return 1; if (side && xs[dim] > xwall[iwall]) return 1; return 0; } /* ---------------------------------------------------------------------- collision of SRD particle S with surface of spherical big particle B exact because compute time of collision dt = time previous to now at which collision occurs xscoll = collision pt = position of SRD at time of collision xbcoll = position of big particle at time of collision norm = surface normal of collision pt at time of collision ------------------------------------------------------------------------- */ double FixSRD::collision_sphere_exact(double *xs, double *xb, double *vs, double *vb, Big *big, double *xscoll, double *xbcoll, double *norm) { double vs_dot_vs,vb_dot_vb,vs_dot_vb; double vs_dot_xb,vb_dot_xs,vs_dot_xs,vb_dot_xb; double xs_dot_xs,xb_dot_xb,xs_dot_xb; double a,b,c,scale,dt; vs_dot_vs = vs[0]*vs[0] + vs[1]*vs[1] + vs[2]*vs[2]; vb_dot_vb = vb[0]*vb[0] + vb[1]*vb[1] + vb[2]*vb[2]; vs_dot_vb = vs[0]*vb[0] + vs[1]*vb[1] + vs[2]*vb[2]; vs_dot_xb = vs[0]*xb[0] + vs[1]*xb[1] + vs[2]*xb[2]; vb_dot_xs = vb[0]*xs[0] + vb[1]*xs[1] + vb[2]*xs[2]; vs_dot_xs = vs[0]*xs[0] + vs[1]*xs[1] + vs[2]*xs[2]; vb_dot_xb = vb[0]*xb[0] + vb[1]*xb[1] + vb[2]*xb[2]; xs_dot_xs = xs[0]*xs[0] + xs[1]*xs[1] + xs[2]*xs[2]; xb_dot_xb = xb[0]*xb[0] + xb[1]*xb[1] + xb[2]*xb[2]; xs_dot_xb = xs[0]*xb[0] + xs[1]*xb[1] + xs[2]*xb[2]; a = vs_dot_vs + vb_dot_vb - 2.0*vs_dot_vb; b = 2.0 * (vs_dot_xb + vb_dot_xs - vs_dot_xs - vb_dot_xb); c = xs_dot_xs + xb_dot_xb - 2.0*xs_dot_xb - big->radsq; dt = (-b + sqrt(b*b - 4.0*a*c)) / (2.0*a); xscoll[0] = xs[0] - dt*vs[0]; xscoll[1] = xs[1] - dt*vs[1]; xscoll[2] = xs[2] - dt*vs[2]; xbcoll[0] = xb[0] - dt*vb[0]; xbcoll[1] = xb[1] - dt*vb[1]; xbcoll[2] = xb[2] - dt*vb[2]; norm[0] = xscoll[0] - xbcoll[0]; norm[1] = xscoll[1] - xbcoll[1]; norm[2] = xscoll[2] - xbcoll[2]; scale = 1.0/sqrt(norm[0]*norm[0] + norm[1]*norm[1] + norm[2]*norm[2]); norm[0] *= scale; norm[1] *= scale; norm[2] *= scale; return dt; } /* ---------------------------------------------------------------------- collision of SRD particle S with surface of spherical big particle B inexact because just push SRD to surface of big particle at end of step time of collision = end of step xscoll = collision pt = position of SRD at time of collision xbcoll = xb = position of big particle at time of collision norm = surface normal of collision pt at time of collision ------------------------------------------------------------------------- */ void FixSRD::collision_sphere_inexact(double *xs, double *xb, Big *big, double *xscoll, double *xbcoll, double *norm) { double scale; norm[0] = xs[0] - xb[0]; norm[1] = xs[1] - xb[1]; norm[2] = xs[2] - xb[2]; scale = 1.0/sqrt(norm[0]*norm[0] + norm[1]*norm[1] + norm[2]*norm[2]); norm[0] *= scale; norm[1] *= scale; norm[2] *= scale; xscoll[0] = xb[0] + big->radius*norm[0]; xscoll[1] = xb[1] + big->radius*norm[1]; xscoll[2] = xb[2] + big->radius*norm[2]; xbcoll[0] = xb[0]; xbcoll[1] = xb[1]; xbcoll[2] = xb[2]; } /* ---------------------------------------------------------------------- collision of SRD particle S with surface of ellipsoidal big particle B exact because compute time of collision dt = time previous to now at which collision occurs xscoll = collision pt = position of SRD at time of collision xbcoll = position of big particle at time of collision norm = surface normal of collision pt at time of collision ------------------------------------------------------------------------- */ double FixSRD::collision_ellipsoid_exact(double *xs, double *xb, double *vs, double *vb, Big *big, double *xscoll, double *xbcoll, double *norm) { double vs_vb[3],xs_xb[3],omega_ex[3],omega_ey[3],omega_ez[3]; double excoll[3],eycoll[3],ezcoll[3],delta[3],xbody[3],nbody[3]; double ax,bx,cx,ay,by,cy,az,bz,cz; double a,b,c,dt,scale; double *omega = big->omega; double *ex = big->ex; double *ey = big->ey; double *ez = big->ez; vs_vb[0] = vs[0]-vb[0]; vs_vb[1] = vs[1]-vb[1]; vs_vb[2] = vs[2]-vb[2]; xs_xb[0] = xs[0]-xb[0]; xs_xb[1] = xs[1]-xb[1]; xs_xb[2] = xs[2]-xb[2]; omega_ex[0] = omega[1]*ex[2] - omega[2]*ex[1]; omega_ex[1] = omega[2]*ex[0] - omega[0]*ex[2]; omega_ex[2] = omega[0]*ex[1] - omega[1]*ex[0]; omega_ey[0] = omega[1]*ey[2] - omega[2]*ey[1]; omega_ey[1] = omega[2]*ey[0] - omega[0]*ey[2]; omega_ey[2] = omega[0]*ey[1] - omega[1]*ey[0]; omega_ez[0] = omega[1]*ez[2] - omega[2]*ez[1]; omega_ez[1] = omega[2]*ez[0] - omega[0]*ez[2]; omega_ez[2] = omega[0]*ez[1] - omega[1]*ez[0]; ax = vs_vb[0]*omega_ex[0] + vs_vb[1]*omega_ex[1] + vs_vb[2]*omega_ex[2]; bx = -(vs_vb[0]*ex[0] + vs_vb[1]*ex[1] + vs_vb[2]*ex[2]); bx -= xs_xb[0]*omega_ex[0] + xs_xb[1]*omega_ex[1] + xs_xb[2]*omega_ex[2]; cx = xs_xb[0]*ex[0] + xs_xb[1]*ex[1] + xs_xb[2]*ex[2]; ay = vs_vb[0]*omega_ey[0] + vs_vb[1]*omega_ey[1] + vs_vb[2]*omega_ey[2]; by = -(vs_vb[0]*ey[0] + vs_vb[1]*ey[1] + vs_vb[2]*ey[2]); by -= xs_xb[0]*omega_ey[0] + xs_xb[1]*omega_ey[1] + xs_xb[2]*omega_ey[2]; cy = xs_xb[0]*ey[0] + xs_xb[1]*ey[1] + xs_xb[2]*ey[2]; az = vs_vb[0]*omega_ez[0] + vs_vb[1]*omega_ez[1] + vs_vb[2]*omega_ez[2]; bz = -(vs_vb[0]*ez[0] + vs_vb[1]*ez[1] + vs_vb[2]*ez[2]); bz -= xs_xb[0]*omega_ez[0] + xs_xb[1]*omega_ez[1] + xs_xb[2]*omega_ez[2]; cz = xs_xb[0]*ez[0] + xs_xb[1]*ez[1] + xs_xb[2]*ez[2]; a = (bx*bx + 2.0*ax*cx)*big->aradsqinv + (by*by + 2.0*ay*cy)*big->bradsqinv + (bz*bz + 2.0*az*cz)*big->cradsqinv; b = 2.0 * (bx*cx*big->aradsqinv + by*cy*big->bradsqinv + bz*cz*big->cradsqinv); c = cx*cx*big->aradsqinv + cy*cy*big->bradsqinv + cz*cz*big->cradsqinv - 1.0; dt = (-b + sqrt(b*b - 4.0*a*c)) / (2.0*a); xscoll[0] = xs[0] - dt*vs[0]; xscoll[1] = xs[1] - dt*vs[1]; xscoll[2] = xs[2] - dt*vs[2]; xbcoll[0] = xb[0] - dt*vb[0]; xbcoll[1] = xb[1] - dt*vb[1]; xbcoll[2] = xb[2] - dt*vb[2]; // calculate normal to ellipsoid at collision pt // Excoll,Eycoll,Ezcoll = orientation of ellipsoid at collision time // nbody = normal in body frame of ellipsoid (Excoll,Eycoll,Ezcoll) // norm = normal in space frame // only worry about normalizing final norm vector excoll[0] = ex[0] - dt * (omega[1]*ex[2] - omega[2]*ex[1]); excoll[1] = ex[1] - dt * (omega[2]*ex[0] - omega[0]*ex[2]); excoll[2] = ex[2] - dt * (omega[0]*ex[1] - omega[1]*ex[0]); eycoll[0] = ey[0] - dt * (omega[1]*ey[2] - omega[2]*ey[1]); eycoll[1] = ey[1] - dt * (omega[2]*ey[0] - omega[0]*ey[2]); eycoll[2] = ey[2] - dt * (omega[0]*ey[1] - omega[1]*ey[0]); ezcoll[0] = ez[0] - dt * (omega[1]*ez[2] - omega[2]*ez[1]); ezcoll[1] = ez[1] - dt * (omega[2]*ez[0] - omega[0]*ez[2]); ezcoll[2] = ez[2] - dt * (omega[0]*ez[1] - omega[1]*ez[0]); delta[0] = xscoll[0] - xbcoll[0]; delta[1] = xscoll[1] - xbcoll[1]; delta[2] = xscoll[2] - xbcoll[2]; xbody[0] = delta[0]*excoll[0] + delta[1]*excoll[1] + delta[2]*excoll[2]; xbody[1] = delta[0]*eycoll[0] + delta[1]*eycoll[1] + delta[2]*eycoll[2]; xbody[2] = delta[0]*ezcoll[0] + delta[1]*ezcoll[1] + delta[2]*ezcoll[2]; nbody[0] = xbody[0]*big->aradsqinv; nbody[1] = xbody[1]*big->bradsqinv; nbody[2] = xbody[2]*big->cradsqinv; norm[0] = excoll[0]*nbody[0] + eycoll[0]*nbody[1] + ezcoll[0]*nbody[2]; norm[1] = excoll[1]*nbody[0] + eycoll[1]*nbody[1] + ezcoll[1]*nbody[2]; norm[2] = excoll[2]*nbody[0] + eycoll[2]*nbody[1] + ezcoll[2]*nbody[2]; scale = 1.0/sqrt(norm[0]*norm[0] + norm[1]*norm[1] + norm[2]*norm[2]); norm[0] *= scale; norm[1] *= scale; norm[2] *= scale; return dt; } /* ---------------------------------------------------------------------- collision of SRD particle S with surface of ellipsoidal big particle B inexact because just push SRD to surface of big particle at end of step ------------------------------------------------------------------------- */ void FixSRD::collision_ellipsoid_inexact(double *xs, double *xb, Big *big, double *xscoll, double *xbcoll, double *norm) { double xs_xb[3],delta[3],xbody[3],nbody[3]; double x,y,z,scale; double *ex = big->ex; double *ey = big->ey; double *ez = big->ez; xs_xb[0] = xs[0] - xb[0]; xs_xb[1] = xs[1] - xb[1]; xs_xb[2] = xs[2] - xb[2]; x = xs_xb[0]*ex[0] + xs_xb[1]*ex[1] + xs_xb[2]*ex[2]; y = xs_xb[0]*ey[0] + xs_xb[1]*ey[1] + xs_xb[2]*ey[2]; z = xs_xb[0]*ez[0] + xs_xb[1]*ez[1] + xs_xb[2]*ez[2]; scale = 1.0/sqrt(x*x*big->aradsqinv + y*y*big->bradsqinv + z*z*big->cradsqinv); x *= scale; y *= scale; z *= scale; xscoll[0] = x*ex[0] + y*ey[0] + z*ez[0] + xb[0]; xscoll[1] = x*ex[1] + y*ey[1] + z*ez[1] + xb[1]; xscoll[2] = x*ex[2] + y*ey[2] + z*ez[2] + xb[2]; xbcoll[0] = xb[0]; xbcoll[1] = xb[1]; xbcoll[2] = xb[2]; // calculate normal to ellipsoid at collision pt // nbody = normal in body frame of ellipsoid // norm = normal in space frame // only worry about normalizing final norm vector delta[0] = xscoll[0] - xbcoll[0]; delta[1] = xscoll[1] - xbcoll[1]; delta[2] = xscoll[2] - xbcoll[2]; xbody[0] = delta[0]*ex[0] + delta[1]*ex[1] + delta[2]*ex[2]; xbody[1] = delta[0]*ey[0] + delta[1]*ey[1] + delta[2]*ey[2]; xbody[2] = delta[0]*ez[0] + delta[1]*ez[1] + delta[2]*ez[2]; nbody[0] = xbody[0]*big->aradsqinv; nbody[1] = xbody[1]*big->bradsqinv; nbody[2] = xbody[2]*big->cradsqinv; norm[0] = ex[0]*nbody[0] + ey[0]*nbody[1] + ez[0]*nbody[2]; norm[1] = ex[1]*nbody[0] + ey[1]*nbody[1] + ez[1]*nbody[2]; norm[2] = ex[2]*nbody[0] + ey[2]*nbody[1] + ez[2]*nbody[2]; scale = 1.0/sqrt(norm[0]*norm[0] + norm[1]*norm[1] + norm[2]*norm[2]); norm[0] *= scale; norm[1] *= scale; norm[2] *= scale; } /* ---------------------------------------------------------------------- collision of SRD particle S with wall IWALL exact because compute time of collision dt = time previous to now at which collision occurs xscoll = collision pt = position of SRD at time of collision norm = surface normal of collision pt at time of collision ------------------------------------------------------------------------- */ double FixSRD::collision_wall_exact(double *xs, int iwall, double *vs, double *xscoll, double *xbcoll, double *norm) { int dim = wallwhich[iwall] / 2; double dt = (xs[dim] - xwall[iwall]) / (vs[dim] - vwall[iwall]); xscoll[0] = xs[0] - dt*vs[0]; xscoll[1] = xs[1] - dt*vs[1]; xscoll[2] = xs[2] - dt*vs[2]; xbcoll[0] = xbcoll[1] = xbcoll[2] = 0.0; xbcoll[dim] = xwall[iwall] - dt*vwall[iwall]; int side = wallwhich[iwall] % 2; norm[0] = norm[1] = norm[2] = 0.0; if (side == 0) norm[dim] = 1.0; else norm[dim] = -1.0; return dt; } /* ---------------------------------------------------------------------- collision of SRD particle S with wall IWALL inexact because just push SRD to surface of wall at end of step time of collision = end of step xscoll = collision pt = position of SRD at time of collision norm = surface normal of collision pt at time of collision ------------------------------------------------------------------------- */ void FixSRD::collision_wall_inexact(double *xs, int iwall, double *xscoll, double *xbcoll, double *norm) { int dim = wallwhich[iwall] / 2; xscoll[0] = xs[0]; xscoll[1] = xs[1]; xscoll[2] = xs[2]; xscoll[dim] = xwall[iwall]; xbcoll[0] = xbcoll[1] = xbcoll[2] = 0.0; xbcoll[dim] = xwall[iwall]; int side = wallwhich[iwall] % 2; norm[0] = norm[1] = norm[2] = 0.0; if (side == 0) norm[dim] = 1.0; else norm[dim] = -1.0; } /* ---------------------------------------------------------------------- SLIP collision with sphere vs = velocity of SRD, vb = velocity of BIG norm = unit normal from surface of BIG at collision pt v of BIG particle in direction of surf normal is added to v of SRD return vsnew of SRD ------------------------------------------------------------------------- */ void FixSRD::slip_sphere(double *vs, double *vb, double *norm, double *vsnew) { double r1,r2,vnmag,vs_dot_n,vsurf_dot_n; double tangent[3]; while (1) { r1 = sigma * random->gaussian(); r2 = sigma * random->gaussian(); vnmag = sqrt(r1*r1 + r2*r2); if (vnmag*vnmag <= vmaxsq) break; } vs_dot_n = vs[0]*norm[0] + vs[1]*norm[1] + vs[2]*norm[2]; tangent[0] = vs[0] - vs_dot_n*norm[0]; tangent[1] = vs[1] - vs_dot_n*norm[1]; tangent[2] = vs[2] - vs_dot_n*norm[2]; // vsurf = velocity of collision pt = translation/rotation of BIG particle // for sphere, only vb (translation) can contribute in normal direction vsurf_dot_n = vb[0]*norm[0] + vb[1]*norm[1] + vb[2]*norm[2]; vsnew[0] = (vnmag+vsurf_dot_n)*norm[0] + tangent[0]; vsnew[1] = (vnmag+vsurf_dot_n)*norm[1] + tangent[1]; vsnew[2] = (vnmag+vsurf_dot_n)*norm[2] + tangent[2]; } /* ---------------------------------------------------------------------- SLIP collision with ellipsoid vs = velocity of SRD, vb = velocity of BIG xb = position of BIG, omega = rotation of BIG xsurf = collision pt on surf of BIG norm = unit normal from surface of BIG at collision pt v of BIG particle in direction of surf normal is added to v of SRD includes component due to rotation of ellipsoid return vsnew of SRD ------------------------------------------------------------------------- */ void FixSRD::slip_ellipsoid(double *vs, double *vb, double *xb, Big *big, double *xsurf, double *norm, double *vsnew) { double r1,r2,vnmag,vs_dot_n,vsurf_dot_n; double tangent[3],vsurf[3]; double *omega = big->omega; while (1) { r1 = sigma * random->gaussian(); r2 = sigma * random->gaussian(); vnmag = sqrt(r1*r1 + r2*r2); if (vnmag*vnmag <= vmaxsq) break; } vs_dot_n = vs[0]*norm[0] + vs[1]*norm[1] + vs[2]*norm[2]; tangent[0] = vs[0] - vs_dot_n*norm[0]; tangent[1] = vs[1] - vs_dot_n*norm[1]; tangent[2] = vs[2] - vs_dot_n*norm[2]; // vsurf = velocity of collision pt = translation/rotation of BIG particle vsurf[0] = vb[0] + omega[1]*(xsurf[2]-xb[2]) - omega[2]*(xsurf[1]-xb[1]); vsurf[1] = vb[1] + omega[2]*(xsurf[0]-xb[0]) - omega[0]*(xsurf[2]-xb[2]); vsurf[2] = vb[2] + omega[0]*(xsurf[1]-xb[1]) - omega[1]*(xsurf[0]-xb[0]); vsurf_dot_n = vsurf[0]*norm[0] + vsurf[1]*norm[1] + vsurf[2]*norm[2]; vsnew[0] = (vnmag+vsurf_dot_n)*norm[0] + tangent[0]; vsnew[1] = (vnmag+vsurf_dot_n)*norm[1] + tangent[1]; vsnew[2] = (vnmag+vsurf_dot_n)*norm[2] + tangent[2]; } /* ---------------------------------------------------------------------- SLIP collision with wall IWALL vs = velocity of SRD norm = unit normal from WALL at collision pt v of WALL in direction of surf normal is added to v of SRD return vsnew of SRD ------------------------------------------------------------------------- */ void FixSRD::slip_wall(double *vs, int iwall, double *norm, double *vsnew) { double vs_dot_n,scale,r1,r2,vnmag,vtmag1,vtmag2; double tangent1[3],tangent2[3]; vs_dot_n = vs[0]*norm[0] + vs[1]*norm[1] + vs[2]*norm[2]; tangent1[0] = vs[0] - vs_dot_n*norm[0]; tangent1[1] = vs[1] - vs_dot_n*norm[1]; tangent1[2] = vs[2] - vs_dot_n*norm[2]; scale = 1.0/sqrt(tangent1[0]*tangent1[0] + tangent1[1]*tangent1[1] + tangent1[2]*tangent1[2]); tangent1[0] *= scale; tangent1[1] *= scale; tangent1[2] *= scale; tangent2[0] = norm[1]*tangent1[2] - norm[2]*tangent1[1]; tangent2[1] = norm[2]*tangent1[0] - norm[0]*tangent1[2]; tangent2[2] = norm[0]*tangent1[1] - norm[1]*tangent1[0]; while (1) { r1 = sigma * random->gaussian(); r2 = sigma * random->gaussian(); vnmag = sqrt(r1*r1 + r2*r2); vtmag1 = sigma * random->gaussian(); vtmag2 = sigma * random->gaussian(); if (vnmag*vnmag + vtmag1*vtmag1 + vtmag2*vtmag2 <= vmaxsq) break; } vsnew[0] = vnmag*norm[0] + vtmag1*tangent1[0] + vtmag2*tangent2[0]; vsnew[1] = vnmag*norm[1] + vtmag1*tangent1[1] + vtmag2*tangent2[1]; vsnew[2] = vnmag*norm[2] + vtmag1*tangent1[2] + vtmag2*tangent2[2]; // add in velocity of collision pt = velocity of wall int dim = wallwhich[iwall] / 2; vsnew[dim] += vwall[iwall]; } /* ---------------------------------------------------------------------- NO-SLIP collision with sphere or ellipsoid vs = velocity of SRD, vb = velocity of BIG xb = position of BIG, omega = rotation of BIG xsurf = collision pt on surf of BIG norm = unit normal from surface of BIG at collision pt v of collision pt is added to v of SRD includes component due to rotation of BIG return vsnew of SRD ------------------------------------------------------------------------- */ void FixSRD::noslip(double *vs, double *vb, double *xb, Big *big, double *xsurf, double *norm, double *vsnew) { double vs_dot_n,scale,r1,r2,vnmag,vtmag1,vtmag2; double tangent1[3],tangent2[3]; double *omega = big->omega; vs_dot_n = vs[0]*norm[0] + vs[1]*norm[1] + vs[2]*norm[2]; tangent1[0] = vs[0] - vs_dot_n*norm[0]; tangent1[1] = vs[1] - vs_dot_n*norm[1]; tangent1[2] = vs[2] - vs_dot_n*norm[2]; scale = 1.0/sqrt(tangent1[0]*tangent1[0] + tangent1[1]*tangent1[1] + tangent1[2]*tangent1[2]); tangent1[0] *= scale; tangent1[1] *= scale; tangent1[2] *= scale; tangent2[0] = norm[1]*tangent1[2] - norm[2]*tangent1[1]; tangent2[1] = norm[2]*tangent1[0] - norm[0]*tangent1[2]; tangent2[2] = norm[0]*tangent1[1] - norm[1]*tangent1[0]; while (1) { r1 = sigma * random->gaussian(); r2 = sigma * random->gaussian(); vnmag = sqrt(r1*r1 + r2*r2); vtmag1 = sigma * random->gaussian(); vtmag2 = sigma * random->gaussian(); if (vnmag*vnmag + vtmag1*vtmag1 + vtmag2*vtmag2 <= vmaxsq) break; } vsnew[0] = vnmag*norm[0] + vtmag1*tangent1[0] + vtmag2*tangent2[0]; vsnew[1] = vnmag*norm[1] + vtmag1*tangent1[1] + vtmag2*tangent2[1]; vsnew[2] = vnmag*norm[2] + vtmag1*tangent1[2] + vtmag2*tangent2[2]; // add in velocity of collision pt = translation/rotation of BIG particle vsnew[0] += vb[0] + omega[1]*(xsurf[2]-xb[2]) - omega[2]*(xsurf[1]-xb[1]); vsnew[1] += vb[1] + omega[2]*(xsurf[0]-xb[0]) - omega[0]*(xsurf[2]-xb[2]); vsnew[2] += vb[2] + omega[0]*(xsurf[1]-xb[1]) - omega[1]*(xsurf[0]-xb[0]); } /* ---------------------------------------------------------------------- NO-SLIP collision with wall IWALL vs = velocity of SRD xsurf = collision pt on surf of WALL norm = unit normal from WALL at collision pt v of collision pt is added to v of SRD return vsnew of SRD ------------------------------------------------------------------------- */ void FixSRD::noslip_wall(double *vs, int iwall, double *xsurf, double *norm, double *vsnew) { double vs_dot_n,scale,r1,r2,vnmag,vtmag1,vtmag2; double tangent1[3],tangent2[3]; vs_dot_n = vs[0]*norm[0] + vs[1]*norm[1] + vs[2]*norm[2]; tangent1[0] = vs[0] - vs_dot_n*norm[0]; tangent1[1] = vs[1] - vs_dot_n*norm[1]; tangent1[2] = vs[2] - vs_dot_n*norm[2]; scale = 1.0/sqrt(tangent1[0]*tangent1[0] + tangent1[1]*tangent1[1] + tangent1[2]*tangent1[2]); tangent1[0] *= scale; tangent1[1] *= scale; tangent1[2] *= scale; tangent2[0] = norm[1]*tangent1[2] - norm[2]*tangent1[1]; tangent2[1] = norm[2]*tangent1[0] - norm[0]*tangent1[2]; tangent2[2] = norm[0]*tangent1[1] - norm[1]*tangent1[0]; while (1) { r1 = sigma * random->gaussian(); r2 = sigma * random->gaussian(); vnmag = sqrt(r1*r1 + r2*r2); vtmag1 = sigma * random->gaussian(); vtmag2 = sigma * random->gaussian(); if (vnmag*vnmag + vtmag1*vtmag1 + vtmag2*vtmag2 <= vmaxsq) break; } vsnew[0] = vnmag*norm[0] + vtmag1*tangent1[0] + vtmag2*tangent2[0]; vsnew[1] = vnmag*norm[1] + vtmag1*tangent1[1] + vtmag2*tangent2[1]; vsnew[2] = vnmag*norm[2] + vtmag1*tangent1[2] + vtmag2*tangent2[2]; // add in velocity of collision pt = velocity of wall int dim = wallwhich[iwall] / 2; vsnew[dim] += vwall[iwall]; } /* ---------------------------------------------------------------------- impart force and torque to BIG particle force on BIG particle = -dp/dt of SRD particle torque on BIG particle = r cross (-dp/dt) ------------------------------------------------------------------------- */ void FixSRD::force_torque(double *vsold, double *vsnew, double *xs, double *xb, double *fb, double *tb) { double dpdt[3],xs_xb[3]; double factor = mass_srd / dt_big / force->ftm2v; dpdt[0] = factor * (vsnew[0] - vsold[0]); dpdt[1] = factor * (vsnew[1] - vsold[1]); dpdt[2] = factor * (vsnew[2] - vsold[2]); fb[0] -= dpdt[0]; fb[1] -= dpdt[1]; fb[2] -= dpdt[2]; // no torque if SLIP collision and BIG is a sphere if (tb) { xs_xb[0] = xs[0]-xb[0]; xs_xb[1] = xs[1]-xb[1]; xs_xb[2] = xs[2]-xb[2]; tb[0] -= xs_xb[1]*dpdt[2] - xs_xb[2]*dpdt[1]; tb[1] -= xs_xb[2]*dpdt[0] - xs_xb[0]*dpdt[2]; tb[2] -= xs_xb[0]*dpdt[1] - xs_xb[1]*dpdt[0]; } } /* ---------------------------------------------------------------------- impart force to WALL force on WALL = -dp/dt of SRD particle ------------------------------------------------------------------------- */ void FixSRD::force_wall(double *vsold, double *vsnew, int iwall) { double dpdt[3],xs_xb[3]; double factor = mass_srd / dt_big / force->ftm2v; dpdt[0] = factor * (vsnew[0] - vsold[0]); dpdt[1] = factor * (vsnew[1] - vsold[1]); dpdt[2] = factor * (vsnew[2] - vsold[2]); fwall[iwall][0] -= dpdt[0]; fwall[iwall][1] -= dpdt[1]; fwall[iwall][2] -= dpdt[2]; } /* ---------------------------------------------------------------------- update SRD particle position & velocity & search bin assignment check if SRD moved outside of valid region if so, may overlap off-processor BIG particle ------------------------------------------------------------------------- */ int FixSRD::update_srd(int i, double dt, double *xscoll, double *vsnew, double *xs, double *vs) { int ix,iy,iz; vs[0] = vsnew[0]; vs[1] = vsnew[1]; vs[2] = vsnew[2]; xs[0] = xscoll[0] + dt*vsnew[0]; xs[1] = xscoll[1] + dt*vsnew[1]; xs[2] = xscoll[2] + dt*vsnew[2]; if (triclinic) domain->x2lamda(xs,xs); if (xs[0] < srdlo[0] || xs[0] > srdhi[0] || xs[1] < srdlo[1] || xs[1] > srdhi[1] || xs[2] < srdlo[2] || xs[2] > srdhi[2]) { printf("Bad SRD particle move\n"); - printf(" particle %d on proc %d at timestep %d\n", - atom->tag[i],me,update->ntimestep); + char fstr[64]; + sprintf(fstr," particle %%d on proc %%d at timestep %s\n",BIGINT_FORMAT); + printf(fstr,atom->tag[i],me,update->ntimestep); printf(" xnew %g %g %g\n",xs[0],xs[1],xs[2]); printf(" srdlo/hi x %g %g\n",srdlo[0],srdhi[0]); printf(" srdlo/hi y %g %g\n",srdlo[1],srdhi[1]); printf(" srdlo/hi z %g %g\n",srdlo[2],srdhi[2]); error->warning("Fix srd particle moved outside valid domain"); } if (triclinic) domain->lamda2x(xs,xs); ix = static_cast<int> ((xs[0]-xblo2)*bininv2x); iy = static_cast<int> ((xs[1]-yblo2)*bininv2y); iz = static_cast<int> ((xs[2]-zblo2)*bininv2z); return iz*nbin2y*nbin2x + iy*nbin2x + ix; } /* ---------------------------------------------------------------------- setup all SRD parameters with big particles ------------------------------------------------------------------------- */ void FixSRD::parameterize() { double PI = 4.0*atan(1.0); // timesteps dt_big = update->dt; dt_srd = nevery * update->dt; // maxbigdiam,minbigdiam = max/min diameter of any big particle // big particle must either have radius > 0 or shape > 0 defined // apply radfactor at end double *radius = atom->radius; double **shape = atom->shape; int *type = atom->type; int *mask = atom->mask; int nlocal = atom->nlocal; any_ellipsoids = 0; maxbigdiam = 0.0; minbigdiam = BIG; for (int i = 0; i < nlocal; i++) if (mask[i] & biggroupbit) { if (radius) { if (radius[i] == 0.0) error->one("Big particle in fix srd cannot be point particle"); maxbigdiam = MAX(maxbigdiam,2.0*radius[i]); minbigdiam = MIN(minbigdiam,2.0*radius[i]); } else { if (shape[type[i]][0] == 0.0) error->one("Big particle in fix srd cannot be point particle"); maxbigdiam = MAX(maxbigdiam,2.0*shape[type[i]][0]); maxbigdiam = MAX(maxbigdiam,2.0*shape[type[i]][1]); maxbigdiam = MAX(maxbigdiam,2.0*shape[type[i]][2]); minbigdiam = MIN(minbigdiam,2.0*shape[type[i]][0]); minbigdiam = MIN(minbigdiam,2.0*shape[type[i]][1]); minbigdiam = MIN(minbigdiam,2.0*shape[type[i]][2]); if (shape[type[i]][0] != shape[type[i]][1] || shape[type[i]][0] != shape[type[i]][2]) any_ellipsoids = 1; } } double tmp = maxbigdiam; MPI_Allreduce(&tmp,&maxbigdiam,1,MPI_DOUBLE,MPI_MAX,world); tmp = minbigdiam; MPI_Allreduce(&tmp,&minbigdiam,1,MPI_DOUBLE,MPI_MIN,world); maxbigdiam *= radfactor; minbigdiam *= radfactor; int itmp = any_ellipsoids; MPI_Allreduce(&itmp,&any_ellipsoids,1,MPI_INT,MPI_MAX,world); // big particles are only torqued if are ellipsoids or NOSLIP collisions if (any_ellipsoids == 0 && collidestyle == SLIP) torqueflag = 0; else torqueflag = 1; // mass of SRD particles, require monodispersity double *rmass = atom->rmass; double *mass = atom->mass; int flag = 0; mass_srd = 0.0; for (int i = 0; i < nlocal; i++) if (mask[i] & groupbit) { if (rmass) { if (mass_srd == 0.0) mass_srd = rmass[i]; else if (rmass[i] != mass_srd) flag = 1; } else { if (mass_srd == 0.0) mass_srd = mass[type[i]]; else if (mass[type[i]] != mass_srd) flag = 1; } } int flagall; MPI_Allreduce(&flag,&flagall,1,MPI_INT,MPI_MAX,world); if (flagall) error->all("Fix srd requires SRD particles all have same mass"); // set temperature and lamda of SRD particles from each other // lamda = dt_srd * sqrt(boltz * temperature_srd / mass_srd); if (lamdaflag == 0) lamda = dt_srd * sqrt(force->boltz*temperature_srd/mass_srd/force->mvv2e); else temperature_srd = force->mvv2e * (lamda/dt_srd)*(lamda/dt_srd) * mass_srd/force->boltz; // vmax = maximum velocity of an SRD particle // dmax = maximum distance an SRD can move = 4*lamda = vmax * dt_srd sigma = lamda/dt_srd; dmax = 4.0*lamda; vmax = dmax/dt_srd; vmaxsq = vmax*vmax; // volbig = total volume of all big particles // apply radfactor to reduce final volume double volbig = 0.0; if (dimension == 3) { for (int i = 0; i < nlocal; i++) if (mask[i] & biggroupbit) { if (radius) volbig += 4.0/3.0*PI*radius[i]*radius[i]*radius[i]; else volbig += 4.0/3.0*PI * shape[type[i]][0]*shape[type[i]][1]*shape[type[i]][2]; } } else { for (int i = 0; i < nlocal; i++) if (mask[i] & biggroupbit) { if (radius) volbig += PI*radius[i]*radius[i]; else volbig += PI*shape[type[i]][0]*shape[type[i]][1]; } } tmp = volbig; MPI_Allreduce(&tmp,&volbig,1,MPI_DOUBLE,MPI_SUM,world); if (dimension == 3) volbig *= radfactor*radfactor*radfactor; else volbig *= radfactor*radfactor; // particle counts bigint mbig = 0; if (bigexist) mbig = group->count(biggroup); bigint nsrd = group->count(igroup); // mass_big = total mass of all big particles mass_big = 0.0; for (int i = 0; i < nlocal; i++) if (mask[i] & biggroupbit) { if (rmass) mass_big += rmass[i]; else mass_big += mass[type[i]]; } tmp = mass_big; MPI_Allreduce(&tmp,&mass_big,1,MPI_DOUBLE,MPI_SUM,world); // mass density ratio = big / SRD double density_big = 0.0; if (bigexist) density_big = mass_big / volbig; double volsrd,density_srd; if (dimension == 3) { volsrd = (domain->xprd * domain->yprd * domain->zprd) - volbig; density_srd = nsrd * mass_srd / (domain->xprd*domain->yprd*domain->zprd - volbig); } else { volsrd = (domain->xprd * domain->yprd) - volbig; density_srd = nsrd * mass_srd / (domain->xprd*domain->yprd - volbig); } double mdratio = density_big/density_srd; // create grid for binning/rotating SRD particles from gridsrd setup_velocity_bins(); // binsize3 = binsize1 in box units (not lamda units for triclinic) double binsize3x = binsize1x; double binsize3y = binsize1y; double binsize3z = binsize1z; if (triclinic) { binsize3x = binsize1x * domain->xprd; binsize3y = binsize1y * domain->yprd; binsize3z = binsize1z * domain->zprd; } // srd_per_grid = # of SRD particles per SRD grid cell double ncell; if (dimension == 3) ncell = volsrd / (binsize3x*binsize3y*binsize3z); else ncell = volsrd / (binsize3x*binsize3y); srd_per_cell = (double) nsrd / ncell; // kinematic viscosity of SRD fluid // output in cm^2/sec units, converted by xxt2kmu double viscosity; if (dimension == 3) viscosity = gridsrd*gridsrd/(18.0*dt_srd) * (1.0-(1.0-exp(-srd_per_cell))/srd_per_cell) + (force->boltz*temperature_srd*dt_srd/(4.0*mass_srd*force->mvv2e)) * ((srd_per_cell+2.0)/(srd_per_cell-1.0)); else viscosity = (force->boltz*temperature_srd*dt_srd/(2.0*mass_srd*force->mvv2e)) * (srd_per_cell/(srd_per_cell-1.0 + exp(-srd_per_cell)) - 1.0) + (gridsrd*gridsrd)/(12.0*dt_srd) * ((srd_per_cell-1.0 + exp(-srd_per_cell))/srd_per_cell); viscosity *= force->xxt2kmu; // print SRD parameters if (me == 0) { + char str[64]; + sprintf(str," SRD/big particles = %s %s\n",BIGINT_FORMAT,BIGINT_FORMAT); if (screen) { fprintf(screen,"SRD info:\n"); - fprintf(screen," SRD/big particles = %lu %lu\n",nsrd,mbig); + fprintf(screen,str,nsrd,mbig); fprintf(screen," big particle diameter max/min = %g %g\n", maxbigdiam,minbigdiam); fprintf(screen," SRD temperature & lamda = %g %g\n", temperature_srd,lamda); fprintf(screen," SRD max distance & max velocity = %g %g\n",dmax,vmax); fprintf(screen," SRD grid counts: %d %d %d\n",nbin1x,nbin1y,nbin1z); fprintf(screen," SRD grid size: request, actual (xyz) = %g, %g %g %g\n", gridsrd,binsize3x,binsize3y,binsize3z); fprintf(screen," SRD per actual grid cell = %g\n",srd_per_cell); fprintf(screen," SRD viscosity = %g\n",viscosity); fprintf(screen," big/SRD mass density ratio = %g\n",mdratio); } if (logfile) { fprintf(logfile,"SRD info:\n"); - fprintf(logfile," SRD/big particles = %lu %lu\n",nsrd,mbig); + fprintf(logfile,str,nsrd,mbig); fprintf(logfile," big particle diameter max/min = %g %g\n", maxbigdiam,minbigdiam); fprintf(logfile," SRD temperature & lamda = %g %g\n", temperature_srd,lamda); fprintf(logfile," SRD max distance & max velocity = %g %g\n",dmax,vmax); fprintf(logfile," SRD grid counts: %d %d %d\n",nbin1x,nbin1y,nbin1z); fprintf(logfile," SRD grid size: request, actual (xyz) = %g, %g %g %g\n", gridsrd,binsize3x,binsize3y,binsize3z); fprintf(logfile," SRD per actual grid cell = %g\n",srd_per_cell); fprintf(logfile," SRD viscosity = %g\n",viscosity); fprintf(logfile," big/SRD mass density ratio = %g\n",mdratio); } } // error if less than 1 SRD bin per processor in some dim if (nbin1x < comm->procgrid[0] || nbin1y < comm->procgrid[1] || nbin1z < comm->procgrid[2]) error->all("Fewer SRD bins than processors in some dimension"); // check if SRD bins are within tolerance for shape and size int tolflag = 0; if (binsize3y/binsize3x > 1.0+cubictol || binsize3x/binsize3y > 1.0+cubictol) tolflag = 1; if (dimension == 3) { if (binsize3z/binsize3x > 1.0+cubictol || binsize3x/binsize3z > 1.0+cubictol) tolflag = 1; } if (tolflag) { if (cubicflag == CUBIC_ERROR) error->all("SRD bins for fix srd are not cubic enough"); if (me == 0) error->warning("SRD bins for fix srd are not cubic enough"); } tolflag = 0; if (binsize3x/gridsrd > 1.0+cubictol || gridsrd/binsize3x > 1.0+cubictol) tolflag = 1; if (binsize3y/gridsrd > 1.0+cubictol || gridsrd/binsize3y > 1.0+cubictol) tolflag = 1; if (dimension == 3) { if (binsize3z/gridsrd > 1.0+cubictol || gridsrd/binsize3z > 1.0+cubictol) tolflag = 1; } if (tolflag) { if (cubicflag == CUBIC_ERROR) error->all("SRD bin size for fix srd differs from user request"); if (me == 0) error->warning("SRD bin size for fix srd differs from user request"); } // error if lamda < 0.6 of SRD grid size and no shifting allowed // turn on shifting in this case if allowed double maxgridsrd = MAX(binsize3x,binsize3y); if (dimension == 3) maxgridsrd = MAX(maxgridsrd,binsize3z); shiftflag = 0; if (lamda < 0.6*maxgridsrd && shiftuser == SHIFT_NO) error->all("Fix srd lamda must be >= 0.6 of SRD grid size"); else if (lamda < 0.6*maxgridsrd && shiftuser == SHIFT_POSSIBLE) { shiftflag = 1; if (me == 0) error->warning("SRD bin shifting turned on due to small lamda"); } else if (shiftuser == SHIFT_YES) shiftflag = 1; // warnings if (bigexist && maxgridsrd > 0.25 * minbigdiam && me == 0) error->warning("Fix srd grid size > 1/4 of big particle diameter"); if (viscosity < 0.0 && me == 0) error->warning("Fix srd viscosity < 0.0 due to low SRD density"); if (bigexist && dt_big*vmax > minbigdiam && me == 0) error->warning("Fix srd particles may move > big particle diameter"); if (wallexist && collidestyle == NOSLIP && shiftflag == 1) error->warning("Fix srd no-slip wall collisions with bin shifting"); } /* ---------------------------------------------------------------------- set static parameters of each big particle, owned and ghost called each reneighboring use radfactor in distance parameters ------------------------------------------------------------------------- */ void FixSRD::big_static() { int i; double rad,arad,brad,crad; double *radius = atom->radius; double **shape = atom->shape; int *type = atom->type; int omega_flag = atom->omega_flag; double skinhalf = 0.5 * neighbor->skin; for (int k = 0; k < nbig; k++) { i = biglist[k].index; if (radius) { biglist[k].type = SPHERE; biglist[k].typesphere = SPHERE_RADIUS; biglist[k].typeangular = ANGULAR_OMEGA; rad = radfactor*radius[i]; biglist[k].radius = rad; biglist[k].radsq = rad*rad; biglist[k].cutbinsq = (rad+skinhalf) * (rad+skinhalf); } else if (shape[type[i]][0] == shape[type[i]][1] && shape[type[i]][0] == shape[type[i]][2]) { biglist[k].type = SPHERE; biglist[k].typesphere = SPHERE_SHAPE; // either atom->omega is defined or atom->angmom, cannot both be defined if (omega_flag) biglist[k].typeangular = ANGULAR_OMEGA; else biglist[k].typeangular = ANGULAR_ANGMOM; rad = radfactor*shape[type[i]][0]; biglist[k].radius = rad; biglist[k].radsq = rad*rad; biglist[k].cutbinsq = (rad+skinhalf) * (rad+skinhalf); } else { biglist[k].type = ELLIPSOID; biglist[k].typeangular = ANGULAR_ANGMOM; arad = radfactor*shape[type[i]][0]; brad = radfactor*shape[type[i]][1]; crad = radfactor*shape[type[i]][2]; biglist[k].aradsqinv = 1.0/(arad*arad); biglist[k].bradsqinv = 1.0/(brad*brad); biglist[k].cradsqinv = 1.0/(crad*crad); rad = MAX(arad,brad); rad = MAX(rad,crad); biglist[k].cutbinsq = (rad+skinhalf) * (rad+skinhalf); } } } /* ---------------------------------------------------------------------- set dynamics parameters of each big particle, owned and ghost for ELLIPSOID, need current omega and ex,ey,ez for SPHERE, need current omega from atom->omega or atom->angmom called each timestep ------------------------------------------------------------------------- */ void FixSRD::big_dynamic() { int i,itype; double inertia; double **omega = atom->omega; double **angmom = atom->angmom; double **quat = atom->quat; double **shape = atom->shape; double *mass = atom->mass; int *type = atom->type; for (int k = 0; k < nbig; k++) { i = biglist[k].index; // ellipsoid with angmom // calculate ex,ey,ez and omega from quaternion and angmom if (biglist[k].type == ELLIPSOID) { exyz_from_q(quat[i],biglist[k].ex,biglist[k].ey,biglist[k].ez); omega_from_mq(angmom[i],biglist[k].ex,biglist[k].ey,biglist[k].ez, mass[type[i]],shape[type[i]],biglist[k].omega); // sphere with omega and shape or radius // set omega from atom->omega directly } else if (biglist[k].typeangular == ANGULAR_OMEGA) { biglist[k].omega[0] = omega[i][0]; biglist[k].omega[1] = omega[i][1]; biglist[k].omega[2] = omega[i][2]; // sphere with angmom and shape // calculate omega from angmom } else if (biglist[k].typeangular == ANGULAR_ANGMOM) { itype = type[i]; inertia = INERTIA * mass[itype]*shape[itype][0]*shape[itype][0]; biglist[k].omega[0] = angmom[i][0] / inertia; biglist[k].omega[1] = angmom[i][1] / inertia; biglist[k].omega[2] = angmom[i][2] / inertia; } } } /* ---------------------------------------------------------------------- set bounds for big and SRD particle movement called at setup() and when box size changes (but not shape) ------------------------------------------------------------------------- */ void FixSRD::setup_bounds() { // triclinic scale factors // convert a real distance (perpendicular to box face) to a lamda distance double length0,length1,length2; if (triclinic) { double *h_inv = domain->h_inv; length0 = sqrt(h_inv[0]*h_inv[0] + h_inv[5]*h_inv[5] + h_inv[4]*h_inv[4]); length1 = sqrt(h_inv[1]*h_inv[1] + h_inv[3]*h_inv[3]); length2 = h_inv[2]; } // collision object = CO = big particle or wall // big particles can be owned or ghost or unknown, walls are all owned // dist_ghost = distance from sub-domain (SD) that // owned/ghost CO may move to before reneigh, // used to bound search bins in setup_search_bins() // dist_srd = distance from SD at which SRD could collide with unknown CO, // used to error check bounds of SRD movement after collisions via srdlo/hi // dist_srd_reneigh = distance from SD at which an SRD should trigger // a reneigh, b/c next SRD move might overlap with unknown CO, // used for SRD triggering of reneighboring via srdlo/hi_reneigh // onemove = max distance an SRD can move in one step // if big_particles (and possibly walls): // dist_ghost = cut + 1/2 skin due to moving away before reneigh // dist_srd = cut - 1/2 skin - 1/2 diam due to ghost CO moving towards // dist_reneigh = dist_srd - onemove // if walls and no big particles: // dist_ghost = 0.0, since not used // if no big particles or walls: // dist_ghost and dist_srd = 0.0, since not used since no search bins // dist_srd_reneigh = subsize - onemove = // max distance to move without being lost during comm->exchange() // subsize = perp distance between sub-domain faces (orthog or triclinic) double cut = MAX(neighbor->cutneighmax,comm->cutghostuser); double onemove = dt_big*vmax; if (bigexist) { dist_ghost = cut + 0.5*neighbor->skin; dist_srd = cut - 0.5*neighbor->skin - 0.5*maxbigdiam; dist_srd_reneigh = dist_srd - onemove; } else if (wallexist) { dist_ghost = 4*onemove; dist_srd = 4*onemove; dist_srd_reneigh = 4*onemove - onemove; } else { dist_ghost = dist_srd = 0.0; double subsize; if (triclinic == 0) { subsize = domain->prd[0]/comm->procgrid[0]; subsize = MIN(subsize,domain->prd[1]/comm->procgrid[1]); if (dimension == 3) subsize = MIN(subsize,domain->prd[2]/comm->procgrid[2]); } else { subsize = 1.0/comm->procgrid[0]/length0; subsize = MIN(subsize,1.0/comm->procgrid[1]/length1); if (dimension == 3) subsize = MIN(subsize,1.0/comm->procgrid[2]/length2); } dist_srd_reneigh = subsize - onemove; } // lo/hi = bbox on this proc which SRD particles must stay inside // lo/hi reneigh = bbox on this proc outside of which SRDs trigger a reneigh // for triclinic, these bbox are in lamda units if (triclinic == 0) { srdlo[0] = domain->sublo[0] - dist_srd; srdhi[0] = domain->subhi[0] + dist_srd; srdlo[1] = domain->sublo[1] - dist_srd; srdhi[1] = domain->subhi[1] + dist_srd; srdlo[2] = domain->sublo[2] - dist_srd; srdhi[2] = domain->subhi[2] + dist_srd; srdlo_reneigh[0] = domain->sublo[0] - dist_srd_reneigh; srdhi_reneigh[0] = domain->subhi[0] + dist_srd_reneigh; srdlo_reneigh[1] = domain->sublo[1] - dist_srd_reneigh; srdhi_reneigh[1] = domain->subhi[1] + dist_srd_reneigh; srdlo_reneigh[2] = domain->sublo[2] - dist_srd_reneigh; srdhi_reneigh[2] = domain->subhi[2] + dist_srd_reneigh; } else { srdlo[0] = domain->sublo_lamda[0] - dist_srd*length0; srdhi[0] = domain->subhi_lamda[0] + dist_srd*length0; srdlo[1] = domain->sublo_lamda[1] - dist_srd*length1; srdhi[1] = domain->subhi_lamda[1] + dist_srd*length1; srdlo[2] = domain->sublo_lamda[2] - dist_srd*length2; srdhi[2] = domain->subhi_lamda[2] + dist_srd*length2; srdlo_reneigh[0] = domain->sublo_lamda[0] - dist_srd_reneigh*length0; srdhi_reneigh[0] = domain->subhi_lamda[0] + dist_srd_reneigh*length0; srdlo_reneigh[1] = domain->sublo_lamda[1] - dist_srd_reneigh*length1; srdhi_reneigh[1] = domain->subhi_lamda[1] + dist_srd_reneigh*length1; srdlo_reneigh[2] = domain->sublo_lamda[2] - dist_srd_reneigh*length2; srdhi_reneigh[2] = domain->subhi_lamda[2] + dist_srd_reneigh*length2; } } /* ---------------------------------------------------------------------- setup bins used for binning SRD particles for velocity reset gridsrd = desired bin size also setup bin shifting parameters also setup comm of bins that straddle processor boundaries called at beginning of each run called every reneighbor if box size changes, but not if box shape changes ------------------------------------------------------------------------- */ void FixSRD::setup_velocity_bins() { // require integer # of bins across global domain nbin1x = static_cast<int> (domain->xprd/gridsrd + 0.5); nbin1y = static_cast<int> (domain->yprd/gridsrd + 0.5); nbin1z = static_cast<int> (domain->zprd/gridsrd + 0.5); if (dimension == 2) nbin1z = 1; if (nbin1x == 0) nbin1x = 1; if (nbin1y == 0) nbin1y = 1; if (nbin1z == 0) nbin1z = 1; if (triclinic == 0) { binsize1x = domain->xprd / nbin1x; binsize1y = domain->yprd / nbin1y; binsize1z = domain->zprd / nbin1z; bininv1x = 1.0/binsize1x; bininv1y = 1.0/binsize1y; bininv1z = 1.0/binsize1z; } else { binsize1x = 1.0 / nbin1x; binsize1y = 1.0 / nbin1y; binsize1z = 1.0 / nbin1z; bininv1x = nbin1x; bininv1y = nbin1y; bininv1z = nbin1z; } nbins1 = nbin1x*nbin1y*nbin1z; // setup two shifts, 0 = no shift, 1 = shift // initialize no shift case since static // shift case is dynamic, has to be initialized each time shift occurs // setup_velocity_shift allocates memory for vbin and sendlist/recvlist double *boxlo; if (triclinic == 0) boxlo = domain->boxlo; else boxlo = domain->boxlo_lamda; shifts[0].corner[0] = boxlo[0]; shifts[0].corner[1] = boxlo[1]; shifts[0].corner[2] = boxlo[2]; setup_velocity_shift(0,0); shifts[1].corner[0] = boxlo[0]; shifts[1].corner[1] = boxlo[1]; shifts[1].corner[2] = boxlo[2]; setup_velocity_shift(1,0); // allocate binhead based on max # of bins in either shift int max = shifts[0].nbins; max = MAX(max,shifts[1].nbins); if (max > maxbin1) { memory->sfree(binhead); maxbin1 = max; binhead = (int *) memory->smalloc(max*sizeof(int),"fix/srd:binhead"); } // allocate sbuf,rbuf based on biggest bin message max = 0; for (int ishift = 0; ishift < 2; ishift++) for (int iswap = 0; iswap < 2*dimension; iswap++) { max = MAX(max,shifts[ishift].bcomm[iswap].nsend); max = MAX(max,shifts[ishift].bcomm[iswap].nrecv); } if (max > maxbuf) { memory->sfree(sbuf1); memory->sfree(sbuf2); memory->sfree(rbuf1); memory->sfree(rbuf2); maxbuf = max; sbuf1 = (double *) memory->smalloc(max*VBINSIZE*sizeof(double),"fix/srd:sbuf"); sbuf2 = (double *) memory->smalloc(max*VBINSIZE*sizeof(double),"fix/srd:sbuf"); rbuf1 = (double *) memory->smalloc(max*VBINSIZE*sizeof(double),"fix/srd:rbuf"); rbuf2 = (double *) memory->smalloc(max*VBINSIZE*sizeof(double),"fix/srd:rbuf"); } // commflag = 1 if any comm required due to bins overlapping proc boundaries shifts[0].commflag = 0; if (nbin1x % comm->procgrid[0]) shifts[0].commflag = 1; if (nbin1y % comm->procgrid[1]) shifts[0].commflag = 1; if (nbin1z % comm->procgrid[2]) shifts[0].commflag = 1; shifts[1].commflag = 1; } /* ---------------------------------------------------------------------- setup velocity shift parameters set binlo[]/binhi[] and nbins,nbinx,nbiny,nbinz for this proc set bcomm[6] params based on bin overlaps with proc boundaries no comm of bins across non-periodic global boundaries set vbin owner flags for bins I am owner of ishift = 0, dynamic = 0: set all settings since are static allocate and set bcomm params and vbins do not comm bins that align with proc boundaries ishift = 1, dynamic = 0: set max bounds on bin counts and message sizes allocate and set bcomm params and vbins based on max bounds other settings will later change dynamically ishift = 1, dynamic = 1: set actual bin bounds and counts for specific shift set bcomm params and vbins (already allocated) called by setup_velocity_bins() and reset_velocities() ------------------------------------------------------------------------- */ void FixSRD::setup_velocity_shift(int ishift, int dynamic) { int i,j,k,m,id,nsend; int *sendlist; BinComm *first,*second; BinAve *vbin; double *sublo,*subhi; if (triclinic == 0) { sublo = domain->sublo; subhi = domain->subhi; } else { sublo = domain->sublo_lamda; subhi = domain->subhi_lamda; } int *binlo = shifts[ishift].binlo; int *binhi = shifts[ishift].binhi; double *corner = shifts[ishift].corner; int *procgrid = comm->procgrid; int *myloc = comm->myloc; binlo[0] = static_cast<int> ((sublo[0]-corner[0])*bininv1x); binlo[1] = static_cast<int> ((sublo[1]-corner[1])*bininv1y); binlo[2] = static_cast<int> ((sublo[2]-corner[2])*bininv1z); if (dimension == 2) shifts[ishift].binlo[2] = 0; binhi[0] = static_cast<int> ((subhi[0]-corner[0])*bininv1x); binhi[1] = static_cast<int> ((subhi[1]-corner[1])*bininv1y); binhi[2] = static_cast<int> ((subhi[2]-corner[2])*bininv1z); if (dimension == 2) shifts[ishift].binhi[2] = 0; if (ishift == 0) { if (myloc[0]*nbin1x % procgrid[0] == 0) binlo[0] = myloc[0]*nbin1x/procgrid[0]; if (myloc[1]*nbin1y % procgrid[1] == 0) binlo[1] = myloc[1]*nbin1y/procgrid[1]; if (myloc[2]*nbin1z % procgrid[2] == 0) binlo[2] = myloc[2]*nbin1z/procgrid[2]; if ((myloc[0]+1)*nbin1x % procgrid[0] == 0) binhi[0] = (myloc[0]+1)*nbin1x/procgrid[0] - 1; if ((myloc[1]+1)*nbin1y % procgrid[1] == 0) binhi[1] = (myloc[1]+1)*nbin1y/procgrid[1] - 1; if ((myloc[2]+1)*nbin1z % procgrid[2] == 0) binhi[2] = (myloc[2]+1)*nbin1z/procgrid[2] - 1; } int nbinx = binhi[0] - binlo[0] + 1; int nbiny = binhi[1] - binlo[1] + 1; int nbinz = binhi[2] - binlo[2] + 1; // allow for one extra bin if shifting will occur if (ishift == 1 && dynamic == 0) { nbinx++; nbiny++; if (dimension == 3) nbinz++; } int nbins = nbinx*nbiny*nbinz; int nbinxy = nbinx*nbiny; int nbinsq = nbinx*nbiny; nbinsq = MAX(nbiny*nbinz,nbinsq); nbinsq = MAX(nbinx*nbinz,nbinsq); shifts[ishift].nbins = nbins; shifts[ishift].nbinx = nbinx; shifts[ishift].nbiny = nbiny; shifts[ishift].nbinz = nbinz; int reallocflag = 0; if (dynamic == 0 && nbinsq > shifts[ishift].maxbinsq) { shifts[ishift].maxbinsq = nbinsq; reallocflag = 1; } // bcomm neighbors // first = send in lo direction, recv from hi direction // second = send in hi direction, recv from lo direction if (dynamic == 0) { shifts[ishift].bcomm[0].sendproc = comm->procneigh[0][0]; shifts[ishift].bcomm[0].recvproc = comm->procneigh[0][1]; shifts[ishift].bcomm[1].sendproc = comm->procneigh[0][1]; shifts[ishift].bcomm[1].recvproc = comm->procneigh[0][0]; shifts[ishift].bcomm[2].sendproc = comm->procneigh[1][0]; shifts[ishift].bcomm[2].recvproc = comm->procneigh[1][1]; shifts[ishift].bcomm[3].sendproc = comm->procneigh[1][1]; shifts[ishift].bcomm[3].recvproc = comm->procneigh[1][0]; shifts[ishift].bcomm[4].sendproc = comm->procneigh[2][0]; shifts[ishift].bcomm[4].recvproc = comm->procneigh[2][1]; shifts[ishift].bcomm[5].sendproc = comm->procneigh[2][1]; shifts[ishift].bcomm[5].recvproc = comm->procneigh[2][0]; } // set nsend,nrecv and sendlist,recvlist for each swap in x,y,z // set nsend,nrecv = 0 if static bins align with proc boundary // or to prevent dynamic bin swapping across non-periodic global boundary // allocate sendlist,recvlist only for dynamic = 0 first = &shifts[ishift].bcomm[0]; second = &shifts[ishift].bcomm[1]; first->nsend = first->nrecv = second->nsend = second->nrecv = nbiny*nbinz; if (ishift == 0) { if (myloc[0]*nbin1x % procgrid[0] == 0) first->nsend = second->nrecv = 0; if ((myloc[0]+1)*nbin1x % procgrid[0] == 0) second->nsend = first->nrecv = 0; } else if (dynamic == 0 && domain->xperiodic == 0) { if (myloc[0] == 0) first->nsend = second->nrecv = 0; if (myloc[0] == procgrid[0]-1) second->nsend = first->nrecv = 0; } if (reallocflag) { memory->sfree(first->sendlist); memory->sfree(first->recvlist); memory->sfree(second->sendlist); memory->sfree(second->recvlist); first->sendlist = (int *) memory->smalloc(nbinsq*sizeof(int),"fix/srd:sendlist"); first->recvlist = (int *) memory->smalloc(nbinsq*sizeof(int),"fix/srd:sendlist"); second->sendlist = (int *) memory->smalloc(nbinsq*sizeof(int),"fix/srd:sendlist"); second->recvlist = (int *) memory->smalloc(nbinsq*sizeof(int),"fix/srd:sendlist"); } m = 0; i = 0; for (j = 0; j < nbiny; j++) for (k = 0; k < nbinz; k++) { id = k*nbinxy + j*nbinx + i; first->sendlist[m] = second->recvlist[m] = id; m++; } m = 0; i = nbinx-1; for (j = 0; j < nbiny; j++) for (k = 0; k < nbinz; k++) { id = k*nbinxy + j*nbinx + i; second->sendlist[m] = first->recvlist[m] = id; m++; } first = &shifts[ishift].bcomm[2]; second = &shifts[ishift].bcomm[3]; first->nsend = first->nrecv = second->nsend = second->nrecv = nbinx*nbinz; if (ishift == 0) { if (myloc[1]*nbin1y % procgrid[1] == 0) first->nsend = second->nrecv = 0; if ((myloc[1]+1)*nbin1y % procgrid[1] == 0) second->nsend = first->nrecv = 0; } else if (dynamic == 0 && domain->yperiodic == 0) { if (myloc[1] == 0) first->nsend = second->nrecv = 0; if (myloc[1] == procgrid[1]-1) second->nsend = first->nrecv = 0; } if (reallocflag) { memory->sfree(first->sendlist); memory->sfree(first->recvlist); memory->sfree(second->sendlist); memory->sfree(second->recvlist); first->sendlist = (int *) memory->smalloc(nbinsq*sizeof(int),"fix/srd:sendlist"); first->recvlist = (int *) memory->smalloc(nbinsq*sizeof(int),"fix/srd:sendlist"); second->sendlist = (int *) memory->smalloc(nbinsq*sizeof(int),"fix/srd:sendlist"); second->recvlist = (int *) memory->smalloc(nbinsq*sizeof(int),"fix/srd:sendlist"); } m = 0; j = 0; for (i = 0; i < nbinx; i++) for (k = 0; k < nbinz; k++) { id = k*nbinxy + j*nbinx + i; first->sendlist[m] = second->recvlist[m] = id; m++; } m = 0; j = nbiny-1; for (i = 0; i < nbinx; i++) for (k = 0; k < nbinz; k++) { id = k*nbinxy + j*nbinx + i; second->sendlist[m] = first->recvlist[m] = id; m++; } if (dimension == 3) { first = &shifts[ishift].bcomm[4]; second = &shifts[ishift].bcomm[5]; first->nsend = first->nrecv = second->nsend = second->nrecv = nbinx*nbiny; if (ishift == 0) { if (myloc[2]*nbin1z % procgrid[2] == 0) first->nsend = second->nrecv = 0; if ((myloc[2]+1)*nbin1z % procgrid[2] == 0) second->nsend = first->nrecv = 0; } else if (dynamic == 0 && domain->zperiodic == 0) { if (myloc[2] == 0) first->nsend = second->nrecv = 0; if (myloc[2] == procgrid[2]-1) second->nsend = first->nrecv = 0; } if (reallocflag) { memory->sfree(first->sendlist); memory->sfree(first->recvlist); memory->sfree(second->sendlist); memory->sfree(second->recvlist); first->sendlist = (int *) memory->smalloc(nbinx*nbiny*sizeof(int),"fix/srd:sendlist"); first->recvlist = (int *) memory->smalloc(nbinx*nbiny*sizeof(int),"fix/srd:sendlist"); second->sendlist = (int *) memory->smalloc(nbinx*nbiny*sizeof(int),"fix/srd:sendlist"); second->recvlist = (int *) memory->smalloc(nbinx*nbiny*sizeof(int),"fix/srd:sendlist"); } m = 0; k = 0; for (i = 0; i < nbinx; i++) for (j = 0; j < nbiny; j++) { id = k*nbinxy + j*nbinx + i; first->sendlist[m] = second->recvlist[m] = id; m++; } m = 0; k = nbinz-1; for (i = 0; i < nbinx; i++) for (j = 0; j < nbiny; j++) { id = k*nbinxy + j*nbinx + i; second->sendlist[m] = first->recvlist[m] = id; m++; } } // allocate vbins, only for dynamic = 0 if (dynamic == 0 && nbins > shifts[ishift].maxvbin) { memory->sfree(shifts[ishift].vbin); shifts[ishift].maxvbin = nbins; shifts[ishift].vbin = (BinAve *) memory->smalloc(nbins*sizeof(BinAve),"fix/srd:vbin"); } // for vbins I own, set owner = 1 // if bin never sent to anyone, I own it // if bin sent to lower numbered proc, I do not own it // if bin sent to self, I do not own it on even swap (avoids double counting) vbin = shifts[ishift].vbin; for (i = 0; i < nbins; i++) vbin[i].owner = 1; for (int iswap = 0; iswap < 2*dimension; iswap++) { if (shifts[ishift].bcomm[iswap].sendproc > me) continue; if (shifts[ishift].bcomm[iswap].sendproc == me && iswap % 2 == 0) continue; nsend = shifts[ishift].bcomm[iswap].nsend; sendlist = shifts[ishift].bcomm[iswap].sendlist; for (m = 0; m < nsend; m++) vbin[sendlist[m]].owner = 0; } // if triclinic and streamflag: // set xctr (in lamda units) for all nbins so can compute bin vstream if (triclinic && streamflag) { m = 0; for (k = 0; k < nbinz; k++) for (j = 0; j < nbiny; j++) for (i = 0; i < nbinx; i++) { vbin[m].xctr[0] = corner[0] + (i+binlo[0]+0.5)/nbin1x; vbin[m].xctr[1] = corner[1] + (j+binlo[1]+0.5)/nbin1y; vbin[m].xctr[2] = corner[2] + (k+binlo[2]+0.5)/nbin1z; m++; } } } /* ---------------------------------------------------------------------- setup bins used for big and SRD particle searching gridsearch = desired bin size bins are orthogonal whether simulation box is orthogonal or triclinic for orthogonal boxes, called at each setup since cutghost may change for triclinic boxes, called at every reneigh, since tilt may change sets the following: nbin2 xyz = # of bins in each dim binsize2 and bininv2 xyz = size of bins in each dim xyz blo2 = origin of bins ------------------------------------------------------------------------- */ void FixSRD::setup_search_bins() { // subboxlo/hi = real space bbox which // owned/ghost big particles or walls can be in // start with bounding box for my sub-domain, add dist_ghost // for triclinic, need to: // a) convert dist_ghost to lamda space via length012 // b) lo/hi = sub-domain big particle bbox in lamda space // c) convert lo/hi to real space bounding box via domain->bbox() // similar to neighbor::setup_bins() and comm::cutghost[] calculation double subboxlo[3],subboxhi[3]; if (triclinic == 0) { subboxlo[0] = domain->sublo[0] - dist_ghost; subboxlo[1] = domain->sublo[1] - dist_ghost; subboxlo[2] = domain->sublo[2] - dist_ghost; subboxhi[0] = domain->subhi[0] + dist_ghost; subboxhi[1] = domain->subhi[1] + dist_ghost; subboxhi[2] = domain->subhi[2] + dist_ghost; } else { double *h_inv = domain->h_inv; double length0,length1,length2; length0 = sqrt(h_inv[0]*h_inv[0] + h_inv[5]*h_inv[5] + h_inv[4]*h_inv[4]); length1 = sqrt(h_inv[1]*h_inv[1] + h_inv[3]*h_inv[3]); length2 = h_inv[2]; double lo[3],hi[3]; lo[0] = domain->sublo_lamda[0] - dist_ghost*length0; lo[1] = domain->sublo_lamda[1] - dist_ghost*length1; lo[2] = domain->sublo_lamda[2] - dist_ghost*length2; hi[0] = domain->subhi_lamda[0] + dist_ghost*length0; hi[1] = domain->subhi_lamda[1] + dist_ghost*length1; hi[2] = domain->subhi_lamda[2] + dist_ghost*length2; domain->bbox(lo,hi,subboxlo,subboxhi); } // require integer # of bins for that volume nbin2x = static_cast<int> ((subboxhi[0] - subboxlo[0]) / gridsearch); nbin2y = static_cast<int> ((subboxhi[1] - subboxlo[1]) / gridsearch); nbin2z = static_cast<int> ((subboxhi[2] - subboxlo[2]) / gridsearch); if (dimension == 2) nbin2z = 1; if (nbin2x == 0) nbin2x = 1; if (nbin2y == 0) nbin2y = 1; if (nbin2z == 0) nbin2z = 1; binsize2x = (subboxhi[0] - subboxlo[0]) / nbin2x; binsize2y = (subboxhi[1] - subboxlo[1]) / nbin2y; binsize2z = (subboxhi[2] - subboxlo[2]) / nbin2z; bininv2x = 1.0/binsize2x; bininv2y = 1.0/binsize2y; bininv2z = 1.0/binsize2z; // add bins on either end due to extent of big particles // radmax = max distance from central bin that biggest particle overlaps // includes skin movement // nx,ny,nz = max # of bins to search away from central bin double radmax = 0.5*maxbigdiam + 0.5*neighbor->skin; int nx = static_cast<int> (radmax/binsize2x) + 1; int ny = static_cast<int> (radmax/binsize2y) + 1; int nz = static_cast<int> (radmax/binsize2z) + 1; if (dimension == 2) nz = 0; nbin2x += 2*nx; nbin2y += 2*ny; nbin2z += 2*nz; xblo2 = subboxlo[0] - nx*binsize2x; yblo2 = subboxlo[1] - ny*binsize2y; zblo2 = subboxlo[2] - nz*binsize2z; if (dimension == 2) zblo2 = domain->boxlo[2]; // allocate bins // first deallocate previous bins if necessary nbins2 = nbin2x*nbin2y*nbin2z; if (nbins2 > maxbin2) { memory->sfree(nbinbig); memory->destroy_2d_int_array(binbig); maxbin2 = nbins2; nbinbig = (int *) memory->smalloc(nbins2*sizeof(int),"fix/srd:nbinbig"); binbig = memory->create_2d_int_array(nbins2,ATOMPERBIN,"fix/srd:binbig"); } } /* ---------------------------------------------------------------------- compute stencil of bin offsets for a big particle overlapping search bins ------------------------------------------------------------------------- */ void FixSRD::setup_search_stencil() { // radmax = max distance from central bin that any big particle overlaps // includes skin movement // nx,ny,nz = max # of bins to search away from central bin double radmax = 0.5*maxbigdiam + 0.5*neighbor->skin; double radsq = radmax*radmax; int nx = static_cast<int> (radmax/binsize2x) + 1; int ny = static_cast<int> (radmax/binsize2y) + 1; int nz = static_cast<int> (radmax/binsize2z) + 1; if (dimension == 2) nz = 0; // allocate stencil array // deallocate previous stencil if necessary int max = (2*nx+1) * (2*ny+1) * (2*nz+1); if (max > maxstencil) { memory->destroy_2d_int_array(stencil); maxstencil = max; stencil = memory->create_2d_int_array(max,4,"fix/srd:stencil"); } // loop over all bins // add bin to stencil: // if distance of closest corners of bin and central bin is within cutoff nstencil = 0; for (int k = -nz; k <= nz; k++) for (int j = -ny; j <= ny; j++) for (int i = -nx; i <= nx; i++) if (bin_bin_distance(i,j,k) < radsq) { stencil[nstencil][0] = i; stencil[nstencil][1] = j; stencil[nstencil][2] = k; stencil[nstencil][3] = k*nbin2y*nbin2x + j*nbin2x + i; nstencil++; } } /* ---------------------------------------------------------------------- compute closest squared distance between point x and bin ibin ------------------------------------------------------------------------- */ double FixSRD::point_bin_distance(double *x, int i, int j, int k) { double delx,dely,delz; double xlo = xblo2 + i*binsize2x; double xhi = xlo + binsize2x; double ylo = yblo2 + j*binsize2y; double yhi = ylo + binsize2y; double zlo = zblo2 + k*binsize2z; double zhi = zlo + binsize2z; if (x[0] < xlo) delx = xlo - x[0]; else if (x[0] > xhi) delx = x[0] - xhi; else delx = 0.0; if (x[1] < ylo) dely = ylo - x[1]; else if (x[1] > yhi) dely = x[1] - yhi; else dely = 0.0; if (x[2] < zlo) delz = zlo - x[2]; else if (x[2] > zhi) delz = x[2] - zhi; else delz = 0.0; return (delx*delx + dely*dely + delz*delz); } /* ---------------------------------------------------------------------- compute closest squared distance between 2 bins central bin (0,0,0) and bin (i,j,k) ------------------------------------------------------------------------- */ double FixSRD::bin_bin_distance(int i, int j, int k) { double delx,dely,delz; if (i > 0) delx = (i-1)*binsize2x; else if (i == 0) delx = 0.0; else delx = (i+1)*binsize2x; if (j > 0) dely = (j-1)*binsize2y; else if (j == 0) dely = 0.0; else dely = (j+1)*binsize2y; if (k > 0) delz = (k-1)*binsize2z; else if (k == 0) delz = 0.0; else delz = (k+1)*binsize2z; return (delx*delx + dely*dely + delz*delz); } /* ---------------------------------------------------------------------- compute space-frame ex,ey,ez from current quaternion q ex,ey,ez = space-frame coords of 1st,2nd,3rd principal axis operation is ex = q' d q = Q d, where d is (1,0,0) = 1st axis in body frame ------------------------------------------------------------------------- */ void FixSRD::exyz_from_q(double *q, double *ex, double *ey, double *ez) { ex[0] = q[0]*q[0] + q[1]*q[1] - q[2]*q[2] - q[3]*q[3]; ex[1] = 2.0 * (q[1]*q[2] + q[0]*q[3]); ex[2] = 2.0 * (q[1]*q[3] - q[0]*q[2]); ey[0] = 2.0 * (q[1]*q[2] - q[0]*q[3]); ey[1] = q[0]*q[0] - q[1]*q[1] + q[2]*q[2] - q[3]*q[3]; ey[2] = 2.0 * (q[2]*q[3] + q[0]*q[1]); ez[0] = 2.0 * (q[1]*q[3] + q[0]*q[2]); ez[1] = 2.0 * (q[2]*q[3] - q[0]*q[1]); ez[2] = q[0]*q[0] - q[1]*q[1] - q[2]*q[2] + q[3]*q[3]; } /* ---------------------------------------------------------------------- compute omega from angular momentum w = omega = angular velocity in space frame wbody = angular velocity in body frame set wbody component to 0.0 if inertia component is 0.0 otherwise body can spin easily around that axis project space-frame angular momentum onto body axes and divide by principal moments ------------------------------------------------------------------------- */ void FixSRD::omega_from_mq(double *m, double *ex, double *ey, double *ez, double mass, double *shape, double *w) { double inertia[3],wbody[3]; inertia[0] = 0.2*mass * (shape[1]*shape[1]+shape[2]*shape[2]); inertia[1] = 0.2*mass * (shape[0]*shape[0]+shape[2]*shape[2]); inertia[2] = 0.2*mass * (shape[0]*shape[0]+shape[1]*shape[1]); wbody[0] = (m[0]*ex[0] + m[1]*ex[1] + m[2]*ex[2]) / inertia[0]; wbody[1] = (m[0]*ey[0] + m[1]*ey[1] + m[2]*ey[2]) / inertia[1]; wbody[2] = (m[0]*ez[0] + m[1]*ez[1] + m[2]*ez[2]) / inertia[2]; w[0] = wbody[0]*ex[0] + wbody[1]*ey[0] + wbody[2]*ez[0]; w[1] = wbody[0]*ex[1] + wbody[1]*ey[1] + wbody[2]*ez[1]; w[2] = wbody[0]*ex[2] + wbody[1]*ey[2] + wbody[2]*ez[2]; } /* ---------------------------------------------------------------------- */ int FixSRD::pack_reverse_comm(int n, int first, double *buf) { int i,m,last; m = 0; last = first + n; if (torqueflag) { for (i = first; i < last; i++) { buf[m++] = flocal[i][0]; buf[m++] = flocal[i][1]; buf[m++] = flocal[i][2]; buf[m++] = tlocal[i][0]; buf[m++] = tlocal[i][1]; buf[m++] = tlocal[i][2]; } } else { for (i = first; i < last; i++) { buf[m++] = flocal[i][0]; buf[m++] = flocal[i][1]; buf[m++] = flocal[i][2]; } } return comm_reverse; } /* ---------------------------------------------------------------------- */ void FixSRD::unpack_reverse_comm(int n, int *list, double *buf) { int i,j,m; m = 0; if (torqueflag) { for (i = 0; i < n; i++) { j = list[i]; flocal[j][0] += buf[m++]; flocal[j][1] += buf[m++]; flocal[j][2] += buf[m++]; tlocal[j][0] += buf[m++]; tlocal[j][1] += buf[m++]; tlocal[j][2] += buf[m++]; } } else { for (i = 0; i < n; i++) { j = list[i]; flocal[j][0] += buf[m++]; flocal[j][1] += buf[m++]; flocal[j][2] += buf[m++]; } } } /* ---------------------------------------------------------------------- SRD stats ------------------------------------------------------------------------- */ double FixSRD::compute_vector(int n) { // only sum across procs one time if (stats_flag == 0) { stats[0] = ncheck; stats[1] = ncollide; stats[2] = nbounce; stats[3] = ninside; stats[4] = nrescale; stats[5] = nbins2; stats[6] = nbins1; stats[7] = srd_bin_count; stats[8] = srd_bin_temp; stats[9] = bouncemaxnum; stats[10] = bouncemax; stats[11] = reneighcount; MPI_Allreduce(stats,stats_all,10,MPI_DOUBLE,MPI_SUM,world); MPI_Allreduce(&stats[10],&stats_all[10],1,MPI_DOUBLE,MPI_MAX,world); if (stats_all[7] != 0.0) stats_all[8] /= stats_all[7]; stats_all[6] /= nprocs; stats_flag = 1; } return stats_all[n]; } /* ---------------------------------------------------------------------- */ void FixSRD::velocity_stats(int groupnum) { int bitmask = group->bitmask[groupnum]; double **v = atom->v; int *mask = atom->mask; int nlocal = atom->nlocal; double vone; double vave = 0.0; double vmax = 0.0; for (int i = 0; i < nlocal; i++) if (mask[i] & bitmask) { vone = sqrt(v[i][0]*v[i][0] + v[i][1]*v[i][1] + v[i][2]*v[i][2]); vave += vone; if (vone > vmax) vmax = vone; } double all; MPI_Allreduce(&vave,&all,1,MPI_DOUBLE,MPI_SUM,world); double count = group->count(groupnum); if (count != 0.0) vave = all/count; else vave = 0.0; MPI_Allreduce(&vmax,&all,1,MPI_DOUBLE,MPI_MAX,world); vmax = all; if (me == 0) { if (screen) fprintf(screen," ave/max %s velocity = %g %g\n", group->names[groupnum],vave,vmax); if (logfile) fprintf(logfile," ave/max %s velocity = %g %g\n", group->names[groupnum],vave,vmax); } } /* ---------------------------------------------------------------------- */ double FixSRD::memory_usage() { double bytes = 0.0; bytes += (shifts[0].nbins + shifts[1].nbins) * sizeof(BinAve); bytes += nmax * sizeof(int); if (bigexist) { bytes += nbins2 * sizeof(int); bytes += nbins2*ATOMPERBIN * sizeof(int); } bytes += nmax * sizeof(int); return bytes; } /* ---------------------------------------------------------------------- useful debugging functions ------------------------------------------------------------------------- */ double FixSRD::distance(int i, int j) { double dx = atom->x[i][0] - atom->x[j][0]; double dy = atom->x[i][1] - atom->x[j][1]; double dz = atom->x[i][2] - atom->x[j][2]; return sqrt(dx*dx + dy*dy + dz*dz); } /* ---------------------------------------------------------------------- */ void FixSRD::print_collision(int i, int j, int ibounce, double t_remain, double dt, double *xscoll, double *xbcoll, double *norm, int type) { double xsstart[3],xbstart[3]; double **x = atom->x; double **v = atom->v; if (type != WALL) { printf("COLLISION between SRD %d and BIG %d\n",atom->tag[i],atom->tag[j]); printf(" bounce # = %d\n",ibounce+1); printf(" local indices: %d %d\n",i,j); printf(" timestep = %g\n",dt); printf(" time remaining post-collision = %g\n",t_remain); xsstart[0] = x[i][0] - dt*v[i][0]; xsstart[1] = x[i][1] - dt*v[i][1]; xsstart[2] = x[i][2] - dt*v[i][2]; xbstart[0] = x[j][0] - dt*v[j][0]; xbstart[1] = x[j][1] - dt*v[j][1]; xbstart[2] = x[j][2] - dt*v[j][2]; printf(" SRD start position = %g %g %g\n", xsstart[0],xsstart[1],xsstart[2]); printf(" BIG start position = %g %g %g\n", xbstart[0],xbstart[1],xbstart[2]); printf(" SRD coll position = %g %g %g\n", xscoll[0],xscoll[1],xscoll[2]); printf(" BIG coll position = %g %g %g\n", xbcoll[0],xbcoll[1],xbcoll[2]); printf(" SRD end position = %g %g %g\n",x[i][0],x[i][1],x[i][2]); printf(" BIG end position = %g %g %g\n",x[j][0],x[j][1],x[j][2]); printf(" SRD vel = %g %g %g\n",v[i][0],v[i][1],v[i][2]); printf(" BIG vel = %g %g %g\n",v[j][0],v[j][1],v[j][2]); printf(" surf norm = %g %g %g\n",norm[0],norm[1],norm[2]); double rstart = sqrt((xsstart[0]-xbstart[0])*(xsstart[0]-xbstart[0]) + (xsstart[1]-xbstart[1])*(xsstart[1]-xbstart[1]) + (xsstart[2]-xbstart[2])*(xsstart[2]-xbstart[2])); double rcoll = sqrt((xscoll[0]-xbcoll[0])*(xscoll[0]-xbcoll[0]) + (xscoll[1]-xbcoll[1])*(xscoll[1]-xbcoll[1]) + (xscoll[2]-xbcoll[2])*(xscoll[2]-xbcoll[2])); double rend = sqrt((x[i][0]-x[j][0])*(x[i][0]-x[j][0]) + (x[i][1]-x[j][1])*(x[i][1]-x[j][1]) + (x[i][2]-x[j][2])*(x[i][2]-x[j][2])); printf(" separation at start = %g\n",rstart); printf(" separation at coll = %g\n",rcoll); printf(" separation at end = %g\n",rend); } else { int dim = wallwhich[j] / 2; printf("COLLISION between SRD %d and WALL %d\n",atom->tag[i],j); printf(" bounce # = %d\n",ibounce+1); printf(" local indices: %d %d\n",i,j); printf(" timestep = %g\n",dt); printf(" time remaining post-collision = %g\n",t_remain); xsstart[0] = x[i][0] - dt*v[i][0]; xsstart[1] = x[i][1] - dt*v[i][1]; xsstart[2] = x[i][2] - dt*v[i][2]; xbstart[0] = xbstart[1] = xbstart[2] = 0.0; xbstart[dim] = xwall[j] - dt*vwall[j]; printf(" SRD start position = %g %g %g\n", xsstart[0],xsstart[1],xsstart[2]); printf(" WALL start position = %g\n",xbstart[dim]); printf(" SRD coll position = %g %g %g\n", xscoll[0],xscoll[1],xscoll[2]); printf(" WALL coll position = %g\n",xbcoll[dim]); printf(" SRD end position = %g %g %g\n",x[i][0],x[i][1],x[i][2]); printf(" WALL end position = %g\n",xwall[j]); printf(" SRD vel = %g %g %g\n",v[i][0],v[i][1],v[i][2]); printf(" WALL vel = %g\n",vwall[j]); printf(" surf norm = %g %g %g\n",norm[0],norm[1],norm[2]); double rstart = xsstart[dim]-xbstart[dim]; double rcoll = xscoll[dim]-xbcoll[dim]; double rend = x[dim][0]-xwall[j]; printf(" separation at start = %g\n",rstart); printf(" separation at coll = %g\n",rcoll); printf(" separation at end = %g\n",rend); } } diff --git a/src/SRD/fix_wall_srd.cpp b/src/SRD/fix_wall_srd.cpp index 359ad63d6..9c8eb4ce5 100644 --- a/src/SRD/fix_wall_srd.cpp +++ b/src/SRD/fix_wall_srd.cpp @@ -1,261 +1,261 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ #include "stdlib.h" #include "string.h" #include "fix_wall_srd.h" #include "atom.h" #include "modify.h" #include "fix.h" #include "domain.h" #include "lattice.h" #include "input.h" #include "modify.h" #include "update.h" #include "variable.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; enum{XLO,XHI,YLO,YHI,ZLO,ZHI}; enum{NONE,EDGE,CONSTANT,VARIABLE}; /* ---------------------------------------------------------------------- */ FixWallSRD::FixWallSRD(LAMMPS *lmp, int narg, char **arg) : Fix(lmp, narg, arg) { if (narg < 4) error->all("Illegal fix wall/srd command"); // parse args nwall = 0; int scaleflag = 1; int iarg = 3; while (iarg < narg) { if ((strcmp(arg[iarg],"xlo") == 0) || (strcmp(arg[iarg],"xhi") == 0) || (strcmp(arg[iarg],"ylo") == 0) || (strcmp(arg[iarg],"yhi") == 0) || (strcmp(arg[iarg],"zlo") == 0) || (strcmp(arg[iarg],"zhi") == 0)) { if (iarg+2 > narg) error->all("Illegal fix wall/srd command"); int newwall; if (strcmp(arg[iarg],"xlo") == 0) newwall = XLO; else if (strcmp(arg[iarg],"xhi") == 0) newwall = XHI; else if (strcmp(arg[iarg],"ylo") == 0) newwall = YLO; else if (strcmp(arg[iarg],"yhi") == 0) newwall = YHI; else if (strcmp(arg[iarg],"zlo") == 0) newwall = ZLO; else if (strcmp(arg[iarg],"zhi") == 0) newwall = ZHI; for (int m = 0; m < nwall; m++) if (newwall == wallwhich[m]) error->all("Wall defined twice in fix wall/srd command"); wallwhich[nwall] = newwall; if (strcmp(arg[iarg+1],"EDGE") == 0) { wallstyle[nwall] = EDGE; int dim = wallwhich[nwall] / 2; int side = wallwhich[nwall] % 2; if (side == 0) coord0[nwall] = domain->boxlo[dim]; else coord0[nwall] = domain->boxhi[dim]; } else if (strstr(arg[iarg+1],"v_") == arg[iarg+1]) { wallstyle[nwall] = VARIABLE; int n = strlen(&arg[iarg+1][2]) + 1; varstr[nwall] = new char[n]; strcpy(varstr[nwall],&arg[iarg+1][2]); } else { wallstyle[nwall] = CONSTANT; coord0[nwall] = atof(arg[iarg+1]); } nwall++; iarg += 2; } else if (strcmp(arg[iarg],"units") == 0) { if (iarg+2 > narg) error->all("Illegal wall/srd command"); if (strcmp(arg[iarg+1],"box") == 0) scaleflag = 0; else if (strcmp(arg[iarg+1],"lattice") == 0) scaleflag = 1; else error->all("Illegal fix wall/srd command"); iarg += 2; } else error->all("Illegal fix wall/srd command"); } // error check if (nwall == 0) error->all("Illegal fix wall command"); for (int m = 0; m < nwall; m++) { if ((wallwhich[m] == XLO || wallwhich[m] == XHI) && domain->xperiodic) error->all("Cannot use fix wall/srd in periodic dimension"); if ((wallwhich[m] == YLO || wallwhich[m] == YHI) && domain->yperiodic) error->all("Cannot use fix wall/srd in periodic dimension"); if ((wallwhich[m] == ZLO || wallwhich[m] == ZHI) && domain->zperiodic) error->all("Cannot use fix wall/srd in periodic dimension"); } for (int m = 0; m < nwall; m++) if ((wallwhich[m] == ZLO || wallwhich[m] == ZHI) && domain->dimension == 2) error->all("Cannot use fix wall/srd zlo/zhi for a 2d simulation"); // setup wall force array array_flag = 1; size_array_rows = nwall; size_array_cols = 3; global_freq = 1; extarray = 1; fwall = memory->create_2d_double_array(nwall,3,"wall/srd:fwall"); fwall_all = memory->create_2d_double_array(nwall,3,"wall/srd:fwall_all"); // scale coord for CONSTANT walls int flag = 0; for (int m = 0; m < nwall; m++) if (wallstyle[m] == CONSTANT) flag = 1; if (flag) { if (scaleflag && domain->lattice == NULL) error->all("Use of fix wall with undefined lattice"); double xscale,yscale,zscale; if (scaleflag) { xscale = domain->lattice->xlattice; yscale = domain->lattice->ylattice; zscale = domain->lattice->zlattice; } else xscale = yscale = zscale = 1.0; double scale; for (int m = 0; m < nwall; m++) { if (wallwhich[m] < YLO) scale = xscale; else if (wallwhich[m] < ZLO) scale = yscale; else scale = zscale; if (wallstyle[m] == CONSTANT) coord0[m] *= scale; } } // set overlap if walls exist in multiple dimensions int dimflag[3]; dimflag[0] = dimflag[1] = dimflag[2] = 0; for (int m = 0; m < nwall; m++) dimflag[wallwhich[m]/2] = 1; if (dimflag[0] + dimflag[1] + dimflag[2] > 1) overlap = 1; else overlap = 0; // set time_depend and varflag if any wall positions are variable varflag = 0; for (int m = 0; m < nwall; m++) if (wallstyle[m] == VARIABLE) time_depend = varflag = 1; laststep = -1; } /* ---------------------------------------------------------------------- */ FixWallSRD::~FixWallSRD() { for (int m = 0; m < nwall; m++) if (wallstyle[m] == VARIABLE) delete [] varstr[m]; memory->destroy_2d_double_array(fwall); memory->destroy_2d_double_array(fwall_all); } /* ---------------------------------------------------------------------- */ int FixWallSRD::setmask() { int mask = 0; return mask; } /* ---------------------------------------------------------------------- */ void FixWallSRD::init() { int flag = 0; for (int m = 0; m < modify->nfix; m++) if (strcmp(modify->fix[m]->style,"srd") == 0) flag = 1; if (!flag) error->all("Cannot use fix wall/srd without fix srd"); for (int m = 0; m < nwall; m++) { if (wallstyle[m] != VARIABLE) continue; varindex[m] = input->variable->find(varstr[m]); if (varindex[m] < 0) error->all("Variable name for fix wall/srd does not exist"); if (!input->variable->equalstyle(varindex[m])) error->all("Variable for fix wall/srd is invalid style"); } dt = update->dt; } /* ---------------------------------------------------------------------- return force component on a wall ------------------------------------------------------------------------- */ double FixWallSRD::compute_array(int i, int j) { // only sum across procs one time if (force_flag == 0) { MPI_Allreduce(&fwall[0][0],&fwall_all[0][0],3*nwall, MPI_DOUBLE,MPI_SUM,world); force_flag = 1; } return fwall_all[i][j]; } /* ---------------------------------------------------------------------- set wall position and velocity, zero forces on walls evaluate variable if necessary, wrap with clear/add if flag, then being called on reneighbor, so archive wall positions ------------------------------------------------------------------------- */ void FixWallSRD::wall_params(int flag) { double xnew; if (varflag) modify->clearstep_compute(); - int ntimestep = update->ntimestep; + bigint ntimestep = update->ntimestep; for (int m = 0; m < nwall; m++) { if (wallstyle[m] == VARIABLE) xnew = input->variable->compute_equal(varindex[m]); else xnew = coord0[m]; if (laststep < 0) { xwall[m] = xwalllast[m] = xnew; vwall[m] = 0.0; } else if (laststep < ntimestep) { xwalllast[m] = xwall[m]; xwall[m] = xnew; vwall[m] = (xwall[m] - xwalllast[m]) / dt; } fwall[m][0] = fwall[m][1] = fwall[m][2] = 0.0; } laststep = ntimestep; if (varflag) modify->addstep_compute(update->ntimestep + 1); if (flag) for (int m = 0; m < nwall; m++) xwallhold[m] = xwall[m]; force_flag = 0; } diff --git a/src/SRD/fix_wall_srd.h b/src/SRD/fix_wall_srd.h index c10ec1253..ed5afcde3 100644 --- a/src/SRD/fix_wall_srd.h +++ b/src/SRD/fix_wall_srd.h @@ -1,59 +1,60 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain 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(wall/srd,FixWallSRD) #else #ifndef LMP_FIX_WALL_SRD_H #define LMP_FIX_WALL_SRD_H #include "fix.h" +#include "lmptype.h" namespace LAMMPS_NS { class FixWallSRD : public Fix { public: int nwall,varflag,overlap; int wallwhich[6]; double xwall[6],xwallhold[6],vwall[6]; double **fwall; FixWallSRD(class LAMMPS *, int, char **); ~FixWallSRD(); int setmask(); void init(); double compute_array(int, int); void wall_params(int); private: int wallstyle[6]; double coord0[6]; char *varstr[6]; int varindex[6]; double dt; double xwalllast[6]; - int laststep; + bigint laststep; double **fwall_all; int force_flag; }; } #endif #endif diff --git a/src/STUBS/mpi.cpp b/src/STUBS/mpi.cpp index 5087707d5..a0333a9c8 100644 --- a/src/STUBS/mpi.cpp +++ b/src/STUBS/mpi.cpp @@ -1,413 +1,413 @@ /* ----------------------------------------------------------------------- LAMMPS 2003 (July 31) - Molecular Dynamics Simulator Sandia National Laboratories, www.cs.sandia.gov/~sjplimp/lammps.html Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------ */ /* Single-processor "stub" versions of MPI routines */ #include "stdlib.h" #include "string.h" #include "stdio.h" #include "stdint.h" #include <sys/time.h> #include "mpi.h" /* lo-level function prototypes */ void mpi_copy_int(void *, void *, int); void mpi_copy_float(void *, void *, int); void mpi_copy_double(void *, void *, int); void mpi_copy_char(void *, void *, int); void mpi_copy_byte(void *, void *, int); /* lo-level data structure */ struct { double value; int proc; } double_int; /* ---------------------------------------------------------------------- */ /* MPI Functions */ /* ---------------------------------------------------------------------- */ int MPI_Init(int *argc, char ***argv) {return 0;} /* ---------------------------------------------------------------------- */ int MPI_Initialized(int *flag) { *flag = 1; return 0; } /* ---------------------------------------------------------------------- */ int MPI_Comm_rank(MPI_Comm comm, int *me) { *me = 0; return 0; } /* ---------------------------------------------------------------------- */ int MPI_Comm_size(MPI_Comm comm, int *nprocs) { *nprocs = 1; return 0; } /* ---------------------------------------------------------------------- */ int MPI_Abort(MPI_Comm comm, int errorcode) { exit(1); return 0; } /* ---------------------------------------------------------------------- */ int MPI_Finalize() {return 0;} /* ---------------------------------------------------------------------- */ double MPI_Wtime() { double time; struct timeval tv; gettimeofday(&tv,NULL); time = 1.0 * tv.tv_sec + 1.0e-6 * tv.tv_usec; return time; } /* ---------------------------------------------------------------------- */ int MPI_Type_size(MPI_Datatype datatype, int *size) { if (datatype == MPI_INT) *size = sizeof(int); else if (datatype == MPI_FLOAT) *size = sizeof(float); else if (datatype == MPI_DOUBLE) *size = sizeof(double); else if (datatype == MPI_CHAR) *size = sizeof(char); else if (datatype == MPI_BYTE) *size = sizeof(char); - else if (datatype == MPI_UNSIGNED_LONG_LONG) *size = sizeof(uint64_t); + else if (datatype == MPI_LONG_LONG) *size = sizeof(uint64_t); else if (datatype == MPI_DOUBLE_INT) *size = sizeof(double_int); } /* ---------------------------------------------------------------------- */ int MPI_Send(void *buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm) { printf("MPI Stub WARNING: Should not send message to self\n"); return 0; } /* ---------------------------------------------------------------------- */ int MPI_Rsend(void *buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm) { printf("MPI Stub WARNING: Should not rsend message to self\n"); return 0; } /* ---------------------------------------------------------------------- */ int MPI_Recv(void *buf, int count, MPI_Datatype datatype, int source, int tag, MPI_Comm comm, MPI_Status *status) { printf("MPI Stub WARNING: Should not recv message from self\n"); return 0; } /* ---------------------------------------------------------------------- */ int MPI_Irecv(void *buf, int count, MPI_Datatype datatype, int source, int tag, MPI_Comm comm, MPI_Request *request) { printf("MPI Stub WARNING: Should not recv message from self\n"); return 0; } /* ---------------------------------------------------------------------- */ int MPI_Wait(MPI_Request *request, MPI_Status *status) { printf("MPI Stub WARNING: Should not wait on message from self\n"); return 0; } /* ---------------------------------------------------------------------- */ int MPI_Waitall(int n, MPI_Request *request, MPI_Status *status) { printf("MPI Stub WARNING: Should not wait on message from self\n"); return 0; } /* ---------------------------------------------------------------------- */ int MPI_Waitany(int count, MPI_Request *request, int *index, MPI_Status *status) { printf("MPI Stub WARNING: Should not wait on message from self\n"); return 0; } /* ---------------------------------------------------------------------- */ int MPI_Sendrecv(void *sbuf, int scount, MPI_Datatype sdatatype, int dest, int stag, void *rbuf, int rcount, MPI_Datatype rdatatype, int source, int rtag, MPI_Comm comm, MPI_Status *status) { printf("MPI Stub WARNING: Should not send message to self\n"); return 0; } /* ---------------------------------------------------------------------- */ int MPI_Get_count(MPI_Status *status, MPI_Datatype datatype, int *count) { printf("MPI Stub WARNING: Should not get count of message to self\n"); return 0; } /* ---------------------------------------------------------------------- */ int MPI_Comm_split(MPI_Comm comm, int color, int key, MPI_Comm *comm_out) { *comm_out = comm; return 0; } /* ---------------------------------------------------------------------- */ int MPI_Comm_dup(MPI_Comm comm, MPI_Comm *comm_out) { *comm_out = comm; return 0; } /* ---------------------------------------------------------------------- */ int MPI_Comm_free(MPI_Comm *comm) {return 0;} /* ---------------------------------------------------------------------- */ int MPI_Cart_create(MPI_Comm comm_old, int ndims, int *dims, int *periods, int reorder, MPI_Comm *comm_cart) { *comm_cart = comm_old; return 0; } /* ---------------------------------------------------------------------- */ int MPI_Cart_get(MPI_Comm comm, int maxdims, int *dims, int *periods, int *coords) { dims[0] = dims[1] = dims[2] = 1; periods[0] = periods[1] = periods[2] = 1; coords[0] = coords[1] = coords[2] = 0; return 0; } /* ---------------------------------------------------------------------- */ int MPI_Cart_shift(MPI_Comm comm, int direction, int displ, int *source, int *dest) { *source = *dest = 0; return 0; } /* ---------------------------------------------------------------------- */ int MPI_Cart_rank(MPI_Comm comm, int *coords, int *rank) { *rank = 0; return 0; } /* ---------------------------------------------------------------------- */ int MPI_Barrier(MPI_Comm comm) {return 0;} /* ---------------------------------------------------------------------- */ int MPI_Bcast(void *buf, int count, MPI_Datatype datatype, int root, MPI_Comm comm) {return 0;} /* ---------------------------------------------------------------------- */ /* copy values from data1 to data2 */ int MPI_Allreduce(void *sendbuf, void *recvbuf, int count, MPI_Datatype datatype, MPI_Op op, MPI_Comm comm) { int n; if (datatype == MPI_INT) n = count*sizeof(int); else if (datatype == MPI_FLOAT) n = count*sizeof(float); else if (datatype == MPI_DOUBLE) n = count*sizeof(double); else if (datatype == MPI_CHAR) n = count*sizeof(char); else if (datatype == MPI_BYTE) n = count*sizeof(char); - else if (datatype == MPI_UNSIGNED_LONG_LONG) n = count*sizeof(uint64_t); + else if (datatype == MPI_LONG_LONG) n = count*sizeof(uint64_t); else if (datatype == MPI_DOUBLE_INT) n = count*sizeof(double_int); memcpy(recvbuf,sendbuf,n); return 0; } /* ---------------------------------------------------------------------- */ /* copy values from data1 to data2 */ int MPI_Reduce(void *sendbuf, void *recvbuf, int count, MPI_Datatype datatype, MPI_Op op, int root, MPI_Comm comm) { int n; if (datatype == MPI_INT) n = count*sizeof(int); else if (datatype == MPI_FLOAT) n = count*sizeof(float); else if (datatype == MPI_DOUBLE) n = count*sizeof(double); else if (datatype == MPI_CHAR) n = count*sizeof(char); else if (datatype == MPI_BYTE) n = count*sizeof(char); - else if (datatype == MPI_UNSIGNED_LONG_LONG) n = count*sizeof(uint64_t); + else if (datatype == MPI_LONG_LONG) n = count*sizeof(uint64_t); else if (datatype == MPI_DOUBLE_INT) n = count*sizeof(double_int); memcpy(recvbuf,sendbuf,n); return 0; } /* ---------------------------------------------------------------------- */ int MPI_Scan(void *sendbuf, void *recvbuf, int count, MPI_Datatype datatype, MPI_Op op, MPI_Comm comm) { int n; if (datatype == MPI_INT) n = count*sizeof(int); else if (datatype == MPI_FLOAT) n = count*sizeof(float); else if (datatype == MPI_DOUBLE) n = count*sizeof(double); else if (datatype == MPI_CHAR) n = count*sizeof(char); else if (datatype == MPI_BYTE) n = count*sizeof(char); - else if (datatype == MPI_UNSIGNED_LONG_LONG) n = count*sizeof(uint64_t); + else if (datatype == MPI_LONG_LONG) n = count*sizeof(uint64_t); else if (datatype == MPI_DOUBLE_INT) n = count*sizeof(double_int); memcpy(recvbuf,sendbuf,n); return 0; } /* ---------------------------------------------------------------------- */ /* copy values from data1 to data2 */ int MPI_Allgather(void *sendbuf, int sendcount, MPI_Datatype sendtype, void *recvbuf, int recvcount, MPI_Datatype recvtype, MPI_Comm comm) { int n; if (sendtype == MPI_INT) n = sendcount*sizeof(int); else if (sendtype == MPI_FLOAT) n = sendcount*sizeof(float); else if (sendtype == MPI_DOUBLE) n = sendcount*sizeof(double); else if (sendtype == MPI_CHAR) n = sendcount*sizeof(char); else if (sendtype == MPI_BYTE) n = sendcount*sizeof(char); - else if (sendtype == MPI_UNSIGNED_LONG_LONG) n = sendcount*sizeof(uint64_t); + else if (sendtype == MPI_LONG_LONG) n = sendcount*sizeof(uint64_t); else if (sendtype == MPI_DOUBLE_INT) n = sendcount*sizeof(double_int); memcpy(recvbuf,sendbuf,n); return 0; } /* ---------------------------------------------------------------------- */ /* copy values from data1 to data2 */ int MPI_Allgatherv(void *sendbuf, int sendcount, MPI_Datatype sendtype, void *recvbuf, int *recvcounts, int *displs, MPI_Datatype recvtype, MPI_Comm comm) { int n; if (sendtype == MPI_INT) n = sendcount*sizeof(int); else if (sendtype == MPI_FLOAT) n = sendcount*sizeof(float); else if (sendtype == MPI_DOUBLE) n = sendcount*sizeof(double); else if (sendtype == MPI_CHAR) n = sendcount*sizeof(char); else if (sendtype == MPI_BYTE) n = sendcount*sizeof(char); - else if (sendtype == MPI_UNSIGNED_LONG_LONG) n = sendcount*sizeof(uint64_t); + else if (sendtype == MPI_LONG_LONG) n = sendcount*sizeof(uint64_t); else if (sendtype == MPI_DOUBLE_INT) n = sendcount*sizeof(double_int); memcpy(recvbuf,sendbuf,n); return 0; } /* ---------------------------------------------------------------------- */ /* copy values from data1 to data2 */ int MPI_Reduce_scatter(void *sendbuf, void *recvbuf, int *recvcounts, MPI_Datatype datatype, MPI_Op op, MPI_Comm comm) { int n; if (datatype == MPI_INT) n = *recvcounts*sizeof(int); else if (datatype == MPI_FLOAT) n = *recvcounts*sizeof(float); else if (datatype == MPI_DOUBLE) n = *recvcounts*sizeof(double); else if (datatype == MPI_CHAR) n = *recvcounts*sizeof(char); else if (datatype == MPI_BYTE) n = *recvcounts*sizeof(char); - else if (datatype == MPI_UNSIGNED_LONG_LONG) n = *recvcounts*sizeof(uint64_t); + else if (datatype == MPI_LONG_LONG) n = *recvcounts*sizeof(uint64_t); else if (datatype == MPI_DOUBLE_INT) n = *recvcounts*sizeof(double_int); memcpy(recvbuf,sendbuf,n); return 0; } /* ---------------------------------------------------------------------- */ /* copy values from data1 to data2 */ int MPI_Gather(void *sendbuf, int sendcount, MPI_Datatype sendtype, void *recvbuf, int recvcount, MPI_Datatype recvtype, int root, MPI_Comm comm) { int n; if (sendtype == MPI_INT) n = sendcount*sizeof(int); else if (sendtype == MPI_FLOAT) n = sendcount*sizeof(float); else if (sendtype == MPI_DOUBLE) n = sendcount*sizeof(double); else if (sendtype == MPI_CHAR) n = sendcount*sizeof(char); else if (sendtype == MPI_BYTE) n = sendcount*sizeof(char); - else if (sendtype == MPI_UNSIGNED_LONG_LONG) n = sendcount*sizeof(uint64_t); + else if (sendtype == MPI_LONG_LONG) n = sendcount*sizeof(uint64_t); else if (sendtype == MPI_DOUBLE_INT) n = sendcount*sizeof(double_int); memcpy(recvbuf,sendbuf,n); return 0; } /* ---------------------------------------------------------------------- */ /* copy values from data1 to data2 */ int MPI_Gatherv(void *sendbuf, int sendcount, MPI_Datatype sendtype, void *recvbuf, int *recvcounts, int *displs, MPI_Datatype recvtype, int root, MPI_Comm comm) { int n; if (sendtype == MPI_INT) n = sendcount*sizeof(int); else if (sendtype == MPI_FLOAT) n = sendcount*sizeof(float); else if (sendtype == MPI_DOUBLE) n = sendcount*sizeof(double); else if (sendtype == MPI_CHAR) n = sendcount*sizeof(char); else if (sendtype == MPI_BYTE) n = sendcount*sizeof(char); - else if (sendtype == MPI_UNSIGNED_LONG_LONG) n = sendcount*sizeof(uint64_t); + else if (sendtype == MPI_LONG_LONG) n = sendcount*sizeof(uint64_t); else if (sendtype == MPI_DOUBLE_INT) n = sendcount*sizeof(double_int); memcpy(recvbuf,sendbuf,n); return 0; } diff --git a/src/STUBS/mpi.h b/src/STUBS/mpi.h index 8c70c9f0f..7104993f5 100644 --- a/src/STUBS/mpi.h +++ b/src/STUBS/mpi.h @@ -1,117 +1,117 @@ /* ----------------------------------------------------------------------- LAMMPS 2003 (July 31) - Molecular Dynamics Simulator Sandia National Laboratories, www.cs.sandia.gov/~sjplimp/lammps.html Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain 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 MPI_STUBS #define MPI_STUBS /* Dummy defs for MPI stubs */ #define MPI_COMM_WORLD 0 #define MPI_SUCCESS 0 #define MPI_INT 1 #define MPI_FLOAT 2 #define MPI_DOUBLE 3 #define MPI_CHAR 4 #define MPI_BYTE 5 -#define MPI_UNSIGNED_LONG_LONG 6 +#define MPI_LONG_LONG 6 #define MPI_DOUBLE_INT 7 #define MPI_SUM 1 #define MPI_MAX 2 #define MPI_MIN 3 #define MPI_MAXLOC 4 #define MPI_MINLOC 5 #define MPI_LOR 6 #define MPI_ANY_SOURCE -1 #define MPI_Comm int #define MPI_Request int #define MPI_Datatype int #define MPI_Op int /* MPI data structs */ struct MPI_Status { int MPI_SOURCE; }; /* Function prototypes for MPI stubs */ int MPI_Init(int *argc, char ***argv); int MPI_Initialized(int *flag); int MPI_Comm_rank(MPI_Comm comm, int *me); int MPI_Comm_size(MPI_Comm comm, int *nprocs); int MPI_Abort(MPI_Comm comm, int errorcode); int MPI_Finalize(); double MPI_Wtime(); int MPI_Type_size(int, int *); int MPI_Send(void *buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm); int MPI_Rsend(void *buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm); int MPI_Recv(void *buf, int count, MPI_Datatype datatype, int source, int tag, MPI_Comm comm, MPI_Status *status); int MPI_Irecv(void *buf, int count, MPI_Datatype datatype, int source, int tag, MPI_Comm comm, MPI_Request *request); int MPI_Wait(MPI_Request *request, MPI_Status *status); int MPI_Waitall(int n, MPI_Request *request, MPI_Status *status); int MPI_Waitany(int count, MPI_Request *request, int *index, MPI_Status *status); int MPI_Sendrecv(void *sbuf, int scount, MPI_Datatype sdatatype, int dest, int stag, void *rbuf, int rcount, MPI_Datatype rdatatype, int source, int rtag, MPI_Comm comm, MPI_Status *status); int MPI_Get_count(MPI_Status *status, MPI_Datatype datatype, int *count); int MPI_Comm_split(MPI_Comm comm, int color, int key, MPI_Comm *comm_out); int MPI_Comm_dup(MPI_Comm comm, MPI_Comm *comm_out); int MPI_Comm_free(MPI_Comm *comm); int MPI_Cart_create(MPI_Comm comm_old, int ndims, int *dims, int *periods, int reorder, MPI_Comm *comm_cart); int MPI_Cart_get(MPI_Comm comm, int maxdims, int *dims, int *periods, int *coords); int MPI_Cart_shift(MPI_Comm comm, int direction, int displ, int *source, int *dest); int MPI_Cart_rank(MPI_Comm comm, int *coords, int *rank); int MPI_Barrier(MPI_Comm comm); int MPI_Bcast(void *buf, int count, MPI_Datatype datatype, int root, MPI_Comm comm); int MPI_Allreduce(void *sendbuf, void *recvbuf, int count, MPI_Datatype datatype, MPI_Op op, MPI_Comm comm); int MPI_Reduce(void *sendbuf, void *recvbuf, int count, MPI_Datatype datatype, MPI_Op op, int root, MPI_Comm comm); int MPI_Scan(void *sendbuf, void *recvbuf, int count, MPI_Datatype datatype, MPI_Op op, MPI_Comm comm); int MPI_Allgather(void *sendbuf, int sendcount, MPI_Datatype sendtype, void *recvbuf, int recvcount, MPI_Datatype recvtype, MPI_Comm comm); int MPI_Allgatherv(void *sendbuf, int sendcount, MPI_Datatype sendtype, void *recvbuf, int *recvcounts, int *displs, MPI_Datatype recvtype, MPI_Comm comm); int MPI_Reduce_scatter(void *sendbuf, void *recvbuf, int *recvcounts, MPI_Datatype datatype, MPI_Op op, MPI_Comm comm); int MPI_Gather(void *sendbuf, int sendcount, MPI_Datatype sendtype, void *recvbuf, int recvcount, MPI_Datatype recvtype, int root, MPI_Comm comm); int MPI_Gatherv(void *sendbuf, int sendcount, MPI_Datatype sendtype, void *recvbuf, int *recvcounts, int *displs, MPI_Datatype recvtype, int root, MPI_Comm comm); #endif diff --git a/src/USER-EFF/Install.sh b/src/USER-EFF/Install.sh index 407168c56..64a7b71c0 100644 --- a/src/USER-EFF/Install.sh +++ b/src/USER-EFF/Install.sh @@ -1,73 +1,73 @@ # Install/unInstall package files in LAMMPS if (test $1 = 1) then cp -p atom_vec_electron.cpp .. cp -p pair_eff_cut.cpp .. cp -p compute_ke_eff.cpp .. cp -p compute_ke_atom_eff.cpp .. cp -p compute_temp_deform_eff.cpp .. cp -p compute_temp_eff.cpp .. cp -p compute_temp_region_eff.cpp .. cp -p fix_langevin_eff.cpp .. cp -p fix_nh_eff.cpp .. cp -p fix_nve_eff.cpp .. cp -p fix_nvt_eff.cpp .. cp -p fix_nvt_sllod_eff.cpp .. cp -p fix_npt_eff.cpp .. cp -p fix_nph_eff.cpp .. cp -p fix_temp_rescale_eff.cpp .. cp -p atom_vec_electron.h .. cp -p pair_eff_cut.h .. cp -p pair_eff_inline.h .. cp -p compute_ke_eff.h .. cp -p compute_ke_atom_eff.h .. cp -p compute_temp_deform_eff.h .. cp -p compute_temp_eff.h .. cp -p compute_temp_region_eff.h .. cp -p fix_langevin_eff.h .. cp -p fix_nh_eff.h .. cp -p fix_nve_eff.h .. cp -p fix_nvt_eff.h .. cp -p fix_nvt_sllod_eff.h .. cp -p fix_npt_eff.h .. cp -p fix_nph_eff.h .. cp -p fix_temp_rescale_eff.h .. elif (test $1 = 0) then rm ../atom_vec_electron.cpp rm ../pair_eff_cut.cpp rm ../compute_ke_eff.cpp rm ../compute_ke_atom_eff.cpp rm ../compute_temp_deform_eff.cpp rm ../compute_temp_eff.cpp rm ../compute_temp_region_eff.cpp - rm ../fix_langevin_eff.cpp .. + rm ../fix_langevin_eff.cpp rm ../fix_nh_eff.cpp rm ../fix_nve_eff.cpp rm ../fix_nvt_eff.cpp rm ../fix_nvt_sllod_eff.cpp rm ../fix_npt_eff.cpp rm ../fix_nph_eff.cpp rm ../fix_temp_rescale_eff.cpp rm ../atom_vec_electron.h rm ../pair_eff_cut.h rm ../pair_eff_inline.h rm ../compute_ke_eff.h rm ../compute_ke_atom_eff.h rm ../compute_temp_deform_eff.h rm ../compute_temp_eff.h rm ../compute_temp_region_eff.h - rm ../fix_langevin_eff.h .. + rm ../fix_langevin_eff.h rm ../fix_nh_eff.h rm ../fix_nve_eff.h rm ../fix_nvt_eff.h rm ../fix_nvt_sllod_eff.h rm ../fix_npt_eff.h rm ../fix_nph_eff.h rm ../fix_temp_rescale_eff.h fi diff --git a/src/USER-EFF/atom_vec_electron.cpp b/src/USER-EFF/atom_vec_electron.cpp index f3a399768..ceba59846 100644 --- a/src/USER-EFF/atom_vec_electron.cpp +++ b/src/USER-EFF/atom_vec_electron.cpp @@ -1,798 +1,801 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- Contributing author: Andres Jaramillo-Botero (Caltech) ------------------------------------------------------------------------- */ -#include "math.h" #include "stdlib.h" #include "atom_vec_electron.h" +#include "lmptype.h" #include "atom.h" #include "domain.h" #include "modify.h" #include "force.h" #include "fix.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; #define DELTA 10000 /* ---------------------------------------------------------------------- */ AtomVecElectron::AtomVecElectron(LAMMPS *lmp, int narg, char **arg) : AtomVec(lmp, narg, arg) { comm_x_only = comm_f_only = 0; mass_type = 1; molecular = 0; size_forward = 5; size_reverse = 4; size_border = 10; size_velocity = 4; size_data_atom = 8; size_data_vel = 5; xcol_data = 6; atom->q_flag = atom->spin_flag = atom->eradius_flag = atom->ervel_flag = atom->erforce_flag = 1; } /* ---------------------------------------------------------------------- grow atom-electron arrays n = 0 grows arrays by DELTA n > 0 allocates arrays to size n ------------------------------------------------------------------------- */ void AtomVecElectron::grow(int n) { if (n == 0) nmax += DELTA; else nmax = n; atom->nmax = nmax; - + if (nmax < 0 || nmax > MAXSMALLINT) + error->one("Per-processor system is too big"); + tag = atom->tag = (int *) memory->srealloc(atom->tag,nmax*sizeof(int),"atom:tag"); type = atom->type = (int *) memory->srealloc(atom->type,nmax*sizeof(int),"atom:type"); mask = atom->mask = (int *) memory->srealloc(atom->mask,nmax*sizeof(int),"atom:mask"); image = atom->image = (int *) memory->srealloc(atom->image,nmax*sizeof(int),"atom:image"); x = atom->x = memory->grow_2d_double_array(atom->x,nmax,3,"atom:x"); v = atom->v = memory->grow_2d_double_array(atom->v,nmax,3,"atom:v"); f = atom->f = memory->grow_2d_double_array(atom->f,nmax,3,"atom:f"); q = atom->q = (double *) memory->srealloc(atom->q,nmax*sizeof(double),"atom:q"); spin = atom->spin = (int *) memory->srealloc(atom->spin,nmax*sizeof(int),"atom:spin"); eradius = atom->eradius = (double *) memory->srealloc(atom->eradius,nmax*sizeof(double),"atom:eradius"); ervel = atom->ervel = (double *) memory->srealloc(atom->ervel,nmax*sizeof(double),"atom:ervel"); erforce = atom->erforce = (double *) memory->srealloc(atom->erforce,nmax*sizeof(double),"atom:erforce"); if (atom->nextra_grow) for (int iextra = 0; iextra < atom->nextra_grow; iextra++) modify->fix[atom->extra_grow[iextra]]->grow_arrays(nmax); } /* ---------------------------------------------------------------------- reset local array ptrs ------------------------------------------------------------------------- */ void AtomVecElectron::grow_reset() { tag = atom->tag; type = atom->type; mask = atom->mask; image = atom->image; x = atom->x; v = atom->v; f = atom->f; - q = atom->q; eradius = atom->eradius; ervel = atom->ervel; erforce = atom->erforce; + q = atom->q; + eradius = atom->eradius; ervel = atom->ervel; erforce = atom->erforce; } /* ---------------------------------------------------------------------- */ void AtomVecElectron::copy(int i, int j) { tag[j] = tag[i]; type[j] = type[i]; mask[j] = mask[i]; image[j] = image[i]; x[j][0] = x[i][0]; x[j][1] = x[i][1]; x[j][2] = x[i][2]; v[j][0] = v[i][0]; v[j][1] = v[i][1]; v[j][2] = v[i][2]; q[j] = q[i]; spin[j] = spin[i]; eradius[j] = eradius[i]; ervel[j] = ervel[i]; if (atom->nextra_grow) for (int iextra = 0; iextra < atom->nextra_grow; iextra++) modify->fix[atom->extra_grow[iextra]]->copy_arrays(i,j); } /* ---------------------------------------------------------------------- */ int AtomVecElectron::pack_comm(int n, int *list, double *buf, int pbc_flag, int *pbc) { int i,j,m; double dx,dy,dz; m = 0; if (pbc_flag == 0) { for (i = 0; i < n; i++) { j = list[i]; buf[m++] = x[j][0]; buf[m++] = x[j][1]; buf[m++] = x[j][2]; buf[m++] = eradius[j]; buf[m++] = ervel[j]; } } else { if (domain->triclinic == 0) { dx = pbc[0]*domain->xprd; dy = pbc[1]*domain->yprd; dz = pbc[2]*domain->zprd; } else { dx = pbc[0]*domain->xprd + pbc[5]*domain->xy + pbc[4]*domain->xz; dy = pbc[1]*domain->yprd + pbc[3]*domain->yz; dz = pbc[2]*domain->zprd; } for (i = 0; i < n; i++) { j = list[i]; buf[m++] = x[j][0] + dx; buf[m++] = x[j][1] + dy; buf[m++] = x[j][2] + dz; buf[m++] = eradius[j]; buf[m++] = ervel[j]; } } return m; } /* ---------------------------------------------------------------------- */ int AtomVecElectron::pack_comm_vel(int n, int *list, double *buf, int pbc_flag, int *pbc) { int i,j,m; double dx,dy,dz; 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++] = eradius[j]; buf[m++] = ervel[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++] = v[j][0]; buf[m++] = v[j][1]; buf[m++] = v[j][2]; buf[m++] = eradius[j]; buf[m++] = ervel[j]; } } return m; } /* ---------------------------------------------------------------------- */ void AtomVecElectron::unpack_comm(int n, int first, double *buf) { int i,m,last; m = 0; last = first + n; for (i = first; i < last; i++) { x[i][0] = buf[m++]; x[i][1] = buf[m++]; x[i][2] = buf[m++]; eradius[i] = buf[m++]; ervel[i] = buf[m++]; } } /* ---------------------------------------------------------------------- */ void AtomVecElectron::unpack_comm_vel(int n, int first, double *buf) { int i,m,last; m = 0; last = first + n; for (i = first; i < last; i++) { x[i][0] = buf[m++]; x[i][1] = buf[m++]; x[i][2] = buf[m++]; v[i][0] = buf[m++]; v[i][1] = buf[m++]; v[i][2] = buf[m++]; eradius[i] = buf[m++]; ervel[i] = buf[m++]; } } /* ---------------------------------------------------------------------- */ int AtomVecElectron::pack_comm_one(int i, double *buf) { buf[0] = eradius[i]; buf[1] = ervel[i]; return 2; } /* ---------------------------------------------------------------------- */ int AtomVecElectron::unpack_comm_one(int i, double *buf) { eradius[i] = buf[0]; ervel[i] = buf[1]; return 2; } /* ---------------------------------------------------------------------- */ int AtomVecElectron::pack_reverse(int n, int first, double *buf) { int i,m,last; m = 0; last = first + n; for (i = first; i < last; i++) { buf[m++] = f[i][0]; buf[m++] = f[i][1]; buf[m++] = f[i][2]; buf[m++] = erforce[i]; } return m; } /* ---------------------------------------------------------------------- */ int AtomVecElectron::pack_reverse_one(int i, double *buf) { buf[0] = erforce[i]; return 1; } /* ---------------------------------------------------------------------- */ void AtomVecElectron::unpack_reverse(int n, int *list, double *buf) { int i,j,m; m = 0; for (i = 0; i < n; i++) { j = list[i]; f[j][0] += buf[m++]; f[j][1] += buf[m++]; f[j][2] += buf[m++]; erforce[j] += buf[m++]; } } /* ---------------------------------------------------------------------- */ int AtomVecElectron::unpack_reverse_one(int i, double *buf) { erforce[i] += buf[0]; return 1; } /* ---------------------------------------------------------------------- */ int AtomVecElectron::pack_border_vel(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++] = v[j][0]; buf[m++] = v[j][1]; buf[m++] = v[j][2]; buf[m++] = q[j]; buf[m++] = spin[j]; buf[m++] = eradius[j]; buf[m++] = ervel[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++] = v[j][0]; buf[m++] = v[j][1]; buf[m++] = v[j][2]; buf[m++] = q[j]; buf[m++] = spin[j]; buf[m++] = eradius[j]; buf[m++] = ervel[j]; } } return m; } /* ---------------------------------------------------------------------- */ void AtomVecElectron::unpack_border_vel(int n, int first, double *buf) { int i,m,last; m = 0; last = first + n; for (i = first; i < last; i++) { if (i == nmax) grow(0); x[i][0] = buf[m++]; x[i][1] = buf[m++]; x[i][2] = buf[m++]; tag[i] = static_cast<int> (buf[m++]); type[i] = static_cast<int> (buf[m++]); mask[i] = static_cast<int> (buf[m++]); v[i][0] = buf[m++]; v[i][1] = buf[m++]; v[i][2] = buf[m++]; q[i] = buf[m++]; spin[i] = static_cast<int> (buf[m++]); eradius[i] = buf[m++]; ervel[i] = buf[m++]; } } /* ---------------------------------------------------------------------- */ int AtomVecElectron::pack_border(int n, int *list, double *buf, int pbc_flag, int *pbc) { int i,j,m; double dx,dy,dz; m = 0; if (pbc_flag == 0) { for (i = 0; i < n; i++) { j = list[i]; buf[m++] = x[j][0]; buf[m++] = x[j][1]; buf[m++] = x[j][2]; buf[m++] = tag[j]; buf[m++] = type[j]; buf[m++] = mask[j]; buf[m++] = q[j]; buf[m++] = spin[j]; buf[m++] = eradius[j]; buf[m++] = ervel[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++] = q[j]; buf[m++] = spin[j]; buf[m++] = eradius[j]; buf[m++] = ervel[j]; } } return m; } /* ---------------------------------------------------------------------- */ int AtomVecElectron::pack_border_one(int i, double *buf) { buf[0] = q[i]; buf[1] = spin[i]; buf[2] = eradius[i]; buf[3] = ervel[i]; return 4; } /* ---------------------------------------------------------------------- */ void AtomVecElectron::unpack_border(int n, int first, double *buf) { int i,m,last; m = 0; last = first + n; for (i = first; i < last; i++) { if (i == nmax) grow(0); x[i][0] = buf[m++]; x[i][1] = buf[m++]; x[i][2] = buf[m++]; tag[i] = static_cast<int> (buf[m++]); type[i] = static_cast<int> (buf[m++]); mask[i] = static_cast<int> (buf[m++]); q[i] = buf[m++]; spin[i] = static_cast<int> (buf[m++]); eradius[i] = buf[m++]; ervel[i] = buf[m++]; } } /* ---------------------------------------------------------------------- */ int AtomVecElectron::unpack_border_one(int i, double *buf) { q[i] = buf[0]; spin[i] = static_cast<int> (buf[1]); eradius[i] = buf[2]; ervel[i] = buf[3]; return 4; } /* ---------------------------------------------------------------------- pack data for atom I for sending to another proc xyz must be 1st 3 values, so comm::exchange() can test on them ------------------------------------------------------------------------- */ int AtomVecElectron::pack_exchange(int i, double *buf) { int m = 1; buf[m++] = x[i][0]; buf[m++] = x[i][1]; buf[m++] = x[i][2]; buf[m++] = v[i][0]; buf[m++] = v[i][1]; buf[m++] = v[i][2]; buf[m++] = tag[i]; buf[m++] = type[i]; buf[m++] = mask[i]; buf[m++] = image[i]; buf[m++] = q[i]; buf[m++] = spin[i]; buf[m++] = eradius[i]; buf[m++] = ervel[i]; if (atom->nextra_grow) for (int iextra = 0; iextra < atom->nextra_grow; iextra++) m += modify->fix[atom->extra_grow[iextra]]->pack_exchange(i,&buf[m]); buf[0] = m; return m; } /* ---------------------------------------------------------------------- */ int AtomVecElectron::unpack_exchange(double *buf) { int nlocal = atom->nlocal; if (nlocal == nmax) grow(0); int m = 1; x[nlocal][0] = buf[m++]; x[nlocal][1] = buf[m++]; x[nlocal][2] = buf[m++]; v[nlocal][0] = buf[m++]; v[nlocal][1] = buf[m++]; v[nlocal][2] = buf[m++]; tag[nlocal] = static_cast<int> (buf[m++]); type[nlocal] = static_cast<int> (buf[m++]); mask[nlocal] = static_cast<int> (buf[m++]); image[nlocal] = static_cast<int> (buf[m++]); q[nlocal] = buf[m++]; spin[nlocal] = static_cast<int> (buf[m++]); eradius[nlocal] = buf[m++]; ervel[nlocal] = buf[m++]; if (atom->nextra_grow) for (int iextra = 0; iextra < atom->nextra_grow; iextra++) m += modify->fix[atom->extra_grow[iextra]]-> unpack_exchange(nlocal,&buf[m]); atom->nlocal++; return m; } /* ---------------------------------------------------------------------- size of restart data for all atoms owned by this proc include extra data stored by fixes ------------------------------------------------------------------------- */ int AtomVecElectron::size_restart() { int i; int nlocal = atom->nlocal; int n = 15 * nlocal; // Associated with pack_restart if (atom->nextra_restart) for (int iextra = 0; iextra < atom->nextra_restart; iextra++) for (i = 0; i < nlocal; i++) n += modify->fix[atom->extra_restart[iextra]]->size_restart(i); return n; } /* ---------------------------------------------------------------------- pack atom I's data for restart file including extra quantities xyz must be 1st 3 values, so that read_restart can test on them molecular types may be negative, but write as positive ------------------------------------------------------------------------- */ int AtomVecElectron::pack_restart(int i, double *buf) { int m = 1; buf[m++] = x[i][0]; buf[m++] = x[i][1]; buf[m++] = x[i][2]; buf[m++] = tag[i]; buf[m++] = type[i]; buf[m++] = mask[i]; buf[m++] = image[i]; buf[m++] = v[i][0]; buf[m++] = v[i][1]; buf[m++] = v[i][2]; buf[m++] = q[i]; buf[m++] = spin[i]; buf[m++] = eradius[i]; buf[m++] = ervel[i]; if (atom->nextra_restart) for (int iextra = 0; iextra < atom->nextra_restart; iextra++) m += modify->fix[atom->extra_restart[iextra]]->pack_restart(i,&buf[m]); buf[0] = m; return m; } /* ---------------------------------------------------------------------- unpack data for one atom from restart file including extra quantities ------------------------------------------------------------------------- */ int AtomVecElectron::unpack_restart(double *buf) { int nlocal = atom->nlocal; if (nlocal == nmax) { grow(0); if (atom->nextra_store) atom->extra = memory->grow_2d_double_array(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] = static_cast<int> (buf[m++]); v[nlocal][0] = buf[m++]; v[nlocal][1] = buf[m++]; v[nlocal][2] = buf[m++]; q[nlocal] = buf[m++]; spin[nlocal] = static_cast<int> (buf[m++]); eradius[nlocal] = buf[m++]; ervel[nlocal] = buf[m++]; double **extra = atom->extra; if (atom->nextra_store) { int size = static_cast<int> (buf[0]) - m; for (int i = 0; i < size; i++) extra[nlocal][i] = buf[m++]; } atom->nlocal++; return m; } /* ---------------------------------------------------------------------- create one atom of itype at coord set other values to defaults ------------------------------------------------------------------------- */ void AtomVecElectron::create_atom(int itype, double *coord) { int nlocal = atom->nlocal; if (nlocal == nmax) grow(0); tag[nlocal] = 0; type[nlocal] = itype; x[nlocal][0] = coord[0]; x[nlocal][1] = coord[1]; x[nlocal][2] = coord[2]; mask[nlocal] = 1; image[nlocal] = (512 << 20) | (512 << 10) | 512; v[nlocal][0] = 0.0; v[nlocal][1] = 0.0; v[nlocal][2] = 0.0; q[nlocal] = 0.0; spin[nlocal] = 1; eradius[nlocal] = 1.0; ervel[nlocal] = 0.0; atom->nlocal++; } /* ---------------------------------------------------------------------- unpack one line from Atoms section of data file initialize other atom quantities ------------------------------------------------------------------------- */ void AtomVecElectron::data_atom(double *coord, int imagetmp, char **values) { int nlocal = atom->nlocal; if (nlocal == nmax) grow(0); tag[nlocal] = atoi(values[0]); if (tag[nlocal] <= 0) error->one("Invalid atom ID in Atoms section of data file"); type[nlocal] = atoi(values[1]); if (type[nlocal] <= 0 || type[nlocal] > atom->ntypes) error->one("Invalid atom type in Atoms section of data file"); q[nlocal] = atof(values[2]); spin[nlocal] = atoi(values[3]); eradius[nlocal] = atof(values[4]); x[nlocal][0] = coord[0]; x[nlocal][1] = coord[1]; x[nlocal][2] = coord[2]; image[nlocal] = imagetmp; mask[nlocal] = 1; v[nlocal][0] = 0.0; v[nlocal][1] = 0.0; v[nlocal][2] = 0.0; ervel[nlocal] = 0.0; atom->nlocal++; } /* ---------------------------------------------------------------------- unpack hybrid quantities from one line in Atoms section of data file initialize other atom quantities for this sub-style ------------------------------------------------------------------------- */ int AtomVecElectron::data_atom_hybrid(int nlocal, char **values) { q[nlocal] = atof(values[0]); spin[nlocal] = atoi(values[1]); eradius[nlocal] = atof(values[2]); if (eradius[nlocal] < 0.0) error->one("Invalid eradius in Atoms section of data file"); v[nlocal][0] = 0.0; v[nlocal][1] = 0.0; v[nlocal][2] = 0.0; ervel[nlocal] = 0.0; return 2; } /* ---------------------------------------------------------------------- unpack one line from Velocities section of data file ------------------------------------------------------------------------- */ void AtomVecElectron::data_vel(int m, char **values) { v[m][0] = atof(values[0]); v[m][1] = atof(values[1]); v[m][2] = atof(values[2]); ervel[m] = atof(values[3]); } /* ---------------------------------------------------------------------- unpack hybrid quantities from one line in Velocities section of data file ------------------------------------------------------------------------- */ int AtomVecElectron::data_vel_hybrid(int m, char **values) { ervel[m] = atof(values[0]); return 1; } /* ---------------------------------------------------------------------- return # of bytes of allocated memory ------------------------------------------------------------------------- */ double AtomVecElectron::memory_usage() { double bytes = 0.0; if (atom->memcheck("tag")) bytes += nmax * sizeof(int); if (atom->memcheck("type")) bytes += nmax * sizeof(int); if (atom->memcheck("mask")) bytes += nmax * sizeof(int); if (atom->memcheck("image")) bytes += nmax * sizeof(int); if (atom->memcheck("x")) bytes += nmax*3 * sizeof(double); if (atom->memcheck("v")) bytes += nmax*3 * sizeof(double); if (atom->memcheck("f")) bytes += nmax*3 * sizeof(double); if (atom->memcheck("q")) bytes += nmax * sizeof(double); if (atom->memcheck("spin")) bytes += nmax * sizeof(int); if (atom->memcheck("eradius")) bytes += nmax * sizeof(double); if (atom->memcheck("ervel")) bytes += nmax * sizeof(double); if (atom->memcheck("erforce")) bytes += nmax * sizeof(double); return bytes; } diff --git a/src/USER-IMD/fix_imd.cpp b/src/USER-IMD/fix_imd.cpp index 427d6ed49..380f67cc2 100644 --- a/src/USER-IMD/fix_imd.cpp +++ b/src/USER-IMD/fix_imd.cpp @@ -1,1357 +1,1355 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- The FixIMD class contains code from VMD and NAMD which is copyrighted by the Board of Trustees of the University of Illinois and is free to use with LAMMPS according to point 2 of the UIUC license (10% clause): " Licensee may, at its own expense, create and freely distribute complimentary works that interoperate with the Software, directing others to the TCBG server to license and obtain the Software itself. Licensee may, at its own expense, modify the Software to make derivative works. Except as explicitly provided below, this License shall apply to any derivative work as it does to the original Software distributed by Illinois. Any derivative work should be clearly marked and renamed to notify users that it is a modified version and not the original Software distributed by Illinois. Licensee agrees to reproduce the copyright notice and other proprietary markings on any derivative work and to include in the documentation of such work the acknowledgement: "This software includes code developed by the Theoretical and Computational Biophysics Group in the Beckman Institute for Advanced Science and Technology at the University of Illinois at Urbana-Champaign." Licensee may redistribute without restriction works with up to 1/2 of their non-comment source code derived from at most 1/10 of the non-comment source code developed by Illinois and contained in the Software, provided that the above directions for notice and acknowledgement are observed. Any other distribution of the Software or any derivative work requires a separate license with Illinois. Licensee may contact Illinois (vmd@ks.uiuc.edu) to negotiate an appropriate license for such distribution." ------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- Contributing author: Axel Kohlmeyer (TempleU) IMD API, hash, and socket code written by: John E. Stone, Justin Gullingsrud, and James Phillips, (TCBG, Beckman Institute, UIUC) ------------------------------------------------------------------------- */ #include <math.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #if defined(_MSC_VER) #include <winsock2.h> #else #include <arpa/inet.h> #include <fcntl.h> #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/time.h> #include <netinet/in.h> #include <netdb.h> #include <sys/file.h> #endif #include <errno.h> #include "fix_imd.h" #include "atom.h" #include "comm.h" #include "update.h" #include "respa.h" #include "domain.h" #include "error.h" #include "group.h" #include "memory.h" /********** API definitions of the VMD/NAMD code ************************ * This code was taken and adapted from VMD-1.8.7/NAMD-2.7 in Sep 2009. * * If there are any bugs or problems, please contact akohlmey@gmail.com * ************************************************************************/ /*************************************************************************** *cr *cr (C) Copyright 1995-2009 The Board of Trustees of the *cr University of Illinois *cr All Rights Reserved *cr ***************************************************************************/ /* part 1: integer hash table */ /** hash table top level data structure */ typedef struct inthash_t { struct inthash_node_t **bucket; /* array of hash nodes */ int size; /* size of the array */ int entries; /* number of entries in table */ int downshift; /* shift cound, used in hash function */ int mask; /* used to select bits for hashing */ } inthash_t; /** hash table node data structure */ typedef struct inthash_node_t { int data; /* data in hash node */ int key; /* key for hash lookup */ struct inthash_node_t *next; /* next node in hash chain */ } inthash_node_t; #define HASH_FAIL -1 #define HASH_LIMIT 0.5 /* initialize new hash table */ static void inthash_init(inthash_t *tptr, int buckets); /* lookup entry in hash table */ static int inthash_lookup(const inthash_t *tptr, int key); /* generate list of keys for reverse lookups. */ static int *inthash_keys(inthash_t *tptr); /* insert an entry into hash table. */ static int inthash_insert(inthash_t *tptr, int key, int data); /* delete the hash table */ static void inthash_destroy(inthash_t *tptr); /* part 2: Interactive MD (IMD) API */ #include <limits.h> #if ( INT_MAX == 2147483647 ) typedef int int32; #else typedef short int32; #endif typedef struct { int32 type; int32 length; } IMDheader; #define IMDHEADERSIZE 8 #define IMDVERSION 2 typedef enum IMDType_t { IMD_DISCONNECT, /**< close IMD connection, leaving sim running */ IMD_ENERGIES, /**< energy data block */ IMD_FCOORDS, /**< atom coordinates */ IMD_GO, /**< start the simulation */ IMD_HANDSHAKE, /**< endianism and version check message */ IMD_KILL, /**< kill the simulation job, shutdown IMD */ IMD_MDCOMM, /**< MDComm style force data */ IMD_PAUSE, /**< pause the running simulation */ IMD_TRATE, /**< set IMD update transmission rate */ IMD_IOERROR /**< indicate an I/O error */ } IMDType; /**< IMD command message type enumerations */ typedef struct { int32 tstep; /**< integer timestep index */ float T; /**< Temperature in degrees Kelvin */ float Etot; /**< Total energy, in Kcal/mol */ float Epot; /**< Potential energy, in Kcal/mol */ float Evdw; /**< Van der Waals energy, in Kcal/mol */ float Eelec; /**< Electrostatic energy, in Kcal/mol */ float Ebond; /**< Bond energy, Kcal/mol */ float Eangle; /**< Angle energy, Kcal/mol */ float Edihe; /**< Dihedral energy, Kcal/mol */ float Eimpr; /**< Improper energy, Kcal/mol */ } IMDEnergies; /**< IMD simulation energy report structure */ /** Send control messages - these consist of a header with no subsequent data */ static int imd_handshake(void *); /**< check endianness, version compat */ /** Receive header and data */ static IMDType imd_recv_header(void *, int32 *); /** Receive MDComm-style forces, units are Kcal/mol/angstrom */ static int imd_recv_mdcomm(void *, int32, int32 *, float *); /** Receive energies */ static int imd_recv_energies(void *, IMDEnergies *); /** Receive atom coordinates. */ static int imd_recv_fcoords(void *, int32, float *); /** Prepare IMD data packet header */ static void imd_fill_header(IMDheader *header, IMDType type, int32 length); /** Write data to socket */ static int32 imd_writen(void *s, const char *ptr, int32 n); /* part 3: abstracts platform-dependent routines/APIs for using sockets */ typedef struct { struct sockaddr_in addr; /* address of socket provided by bind() */ int addrlen; /* size of the addr struct */ int sd; /* socket file descriptor */ } imdsocket; static int imdsock_init(void); static void *imdsock_create(void); static int imdsock_bind(void *, int); static int imdsock_listen(void *); static void *imdsock_accept(void *); /* return new socket */ static int imdsock_write(void *, const void *, int); static int imdsock_read(void *, void *, int); static int imdsock_selread(void *, int); static int imdsock_selwrite(void *, int); static void imdsock_shutdown(void *); static void imdsock_destroy(void *); /*************************************************************** * End of API definitions of the VMD/NAMD code. * * The implementation follows at the end of the file. * ***************************************************************/ using namespace LAMMPS_NS; /* adapted sort for in-place sorting of map indices. */ static void id_sort(int *idmap, int left, int right); /* struct for packed data communication of coordinates and forces. */ struct commdata { int tag; float x,y,z; }; /*************************************************************** * create class and parse arguments in LAMMPS script. Syntax: * fix ID group-ID imd <imd_trate> <imd_port> [unwrap (on|off)] [fscale <imd_fscale>] ***************************************************************/ FixIMD::FixIMD(LAMMPS *lmp, int narg, char **arg) : Fix(lmp, narg, arg) { if (narg < 4) error->all("Illegal fix imd command"); imd_port = atoi(arg[3]); if (imd_port < 1024) error->all("Illegal fix imd parameter: port < 1024"); /* default values for optional flags */ unwrap_flag = 0; nowait_flag = 0; connect_msg = 1; imd_fscale = 1.0; imd_trate = 1; /* parse optional arguments */ int argsdone = 4; while (argsdone+1 < narg) { if (0 == strcmp(arg[argsdone], "unwrap")) { if (0 == strcmp(arg[argsdone+1], "on")) { unwrap_flag = 1; } else { unwrap_flag = 0; } } else if (0 == strcmp(arg[argsdone], "nowait")) { if (0 == strcmp(arg[argsdone+1], "on")) { nowait_flag = 1; } else { nowait_flag = 0; } } else if (0 == strcmp(arg[argsdone], "fscale")) { imd_fscale = atof(arg[argsdone+1]); } else if (0 == strcmp(arg[argsdone], "trate")) { imd_trate = atoi(arg[argsdone+1]); } else { error->all("Unknown fix imd parameter"); } ++argsdone; ++argsdone; } /* sanity check on parameters */ if (imd_trate < 1) error->all("Illegal fix imd parameter. trate < 1."); - bigint n; - if (igroup == group->find("all")) n = atom->natoms; - else n = group->count(igroup); - if (n > MAXINT32) error->all("Too many atoms for fix imd"); + bigint n = group->count(igroup); + if (n > MAXSMALLINT) error->all("Too many atoms for fix imd"); num_coords = static_cast<int> (n); MPI_Comm_rank(world,&me); /* initialize various imd state variables. */ clientsock = NULL; localsock = NULL; nlevels_respa = 0; imd_inactive = 0; imd_terminate = 0; imd_forces = 0; force_buf = NULL; maxbuf = 0; comm_buf = NULL; idmap = NULL; rev_idmap = NULL; if (me == 0) { /* set up incoming socket on MPI rank 0. */ imdsock_init(); localsock = imdsock_create(); clientsock = NULL; if (imdsock_bind(localsock,imd_port)) { perror("bind to socket failed"); imdsock_destroy(localsock); imd_terminate = 1; } else { imdsock_listen(localsock); } } MPI_Bcast(&imd_terminate, 1, MPI_INT, 0, world); if (imd_terminate) error->all("LAMMPS Terminated on error in IMD."); /* storage required to communicate a single coordinate or force. */ size_one = sizeof(struct commdata); } /********************************* * Clean up on deleting the fix. * *********************************/ FixIMD::~FixIMD() { inthash_t *hashtable = (inthash_t *)idmap; memory->sfree(comm_buf); memory->sfree(force_buf); inthash_destroy(hashtable); delete hashtable; free(rev_idmap); // close sockets imdsock_shutdown(clientsock); imdsock_destroy(clientsock); imdsock_shutdown(localsock); imdsock_destroy(localsock); clientsock=NULL; localsock=NULL; return; } /* ---------------------------------------------------------------------- */ int FixIMD::setmask() { int mask = 0; mask |= POST_FORCE; mask |= POST_FORCE_RESPA; return mask; } /* ---------------------------------------------------------------------- */ void FixIMD::init() { if (strcmp(update->integrate_style,"respa") == 0) nlevels_respa = ((Respa *) update->integrate)->nlevels; return; } /* ---------------------------------------------------------------------- */ /* (re-)connect to an IMD client (e.g. VMD). return 1 if new connection was made, 0 if not. */ int FixIMD::reconnect() { /* set up IMD communication, but only if needed. */ imd_inactive = 0; imd_terminate = 0; if (me == 0) { if (clientsock) return 1; if (screen && connect_msg) if (nowait_flag) fprintf(screen,"Listening for IMD connection on port %d.\n",imd_port); else fprintf(screen,"Waiting for IMD connection on port %d.\n",imd_port); connect_msg = 0; clientsock = NULL; if (nowait_flag) { int retval = imdsock_selread(localsock,0); if (retval > 0) { clientsock = imdsock_accept(localsock); } else { imd_inactive = 1; return 0; } } else { int retval=0; do { retval = imdsock_selread(localsock, 60); } while (retval <= 0); clientsock = imdsock_accept(localsock); } if (!imd_inactive && !clientsock) { if (screen) fprintf(screen, "IMD socket accept error. Dropping connection.\n"); imd_terminate = 1; return 0; } else { /* check endianness and IMD protocol version. */ if (imd_handshake(clientsock)) { if (screen) fprintf(screen, "IMD handshake error. Dropping connection.\n"); imdsock_destroy(clientsock); imd_terminate = 1; return 0; } else { int32 length; if (imdsock_selread(clientsock, 1) != 1 || imd_recv_header(clientsock, &length) != IMD_GO) { if (screen) fprintf(screen, "Incompatible IMD client version? Dropping connection.\n"); imdsock_destroy(clientsock); imd_terminate = 1; return 0; } else { return 1; } } } } return 0; } /* ---------------------------------------------------------------------- */ /* wait for IMD client (e.g. VMD) to respond, initialize communication * buffers and collect tag/id maps. */ void FixIMD::setup(int) { /* nme: number of atoms in group on this MPI task * nmax: max number of atoms in group across all MPI tasks * nlocal: all local atoms */ int i,j; int nmax,nme,nlocal; int *mask = atom->mask; int *tag = atom->tag; nlocal = atom->nlocal; nme=0; for (i=0; i < nlocal; ++i) if (mask[i] & groupbit) ++nme; MPI_Allreduce(&nme,&nmax,1,MPI_INT,MPI_MAX,world); maxbuf = nmax*size_one; comm_buf = memory->smalloc(maxbuf,"imd:comm_buf"); connect_msg = 1; reconnect(); MPI_Bcast(&imd_inactive, 1, MPI_INT, 0, world); MPI_Bcast(&imd_terminate, 1, MPI_INT, 0, world); if (imd_terminate) error->all("LAMMPS terminated on error in setting up IMD connection."); /* initialize and build hashtable. */ inthash_t *hashtable=new inthash_t; inthash_init(hashtable, num_coords); idmap = (void *)hashtable; MPI_Status status; MPI_Request request; int tmp, ndata; struct commdata *buf = static_cast<struct commdata *>(comm_buf); if (me == 0) { int *taglist = new int[num_coords]; int numtag=0; /* counter to map atom tags to a 0-based consecutive index list */ for (i=0; i < nlocal; ++i) { if (mask[i] & groupbit) { taglist[numtag] = tag[i]; ++numtag; } } /* loop over procs to receive remote data */ for (i=1; i < comm->nprocs; ++i) { MPI_Irecv(comm_buf, maxbuf, MPI_BYTE, i, 0, world, &request); MPI_Send(&tmp, 0, MPI_INT, i, 0, world); MPI_Wait(&request, &status); MPI_Get_count(&status, MPI_BYTE, &ndata); ndata /= size_one; for (j=0; j < ndata; ++j) { taglist[numtag] = buf[j].tag; ++numtag; } } /* sort list of tags by value to have consistently the * same list when running in parallel and build hash table. */ id_sort(taglist, 0, num_coords-1); for (i=0; i < num_coords; ++i) { inthash_insert(hashtable, taglist[i], i); } delete[] taglist; /* generate reverse index-to-tag map for communicating * IMD forces back to the proper atoms */ rev_idmap=inthash_keys(hashtable); } else { nme=0; for (i=0; i < nlocal; ++i) { if (mask[i] & groupbit) { buf[nme].tag = tag[i]; ++nme; } } /* blocking receive to wait until it is our turn to send data. */ MPI_Recv(&tmp, 0, MPI_INT, 0, 0, world, &status); MPI_Rsend(comm_buf, nme*size_one, MPI_BYTE, 0, 0, world); } return; } /* ---------------------------------------------------------------------- */ /* Main IMD protocol handler: * Send coodinates, energies, and add IMD forces to atoms. */ void FixIMD::post_force(int vflag) { /* check for reconnect */ if (imd_inactive) { reconnect(); MPI_Bcast(&imd_inactive, 1, MPI_INT, 0, world); MPI_Bcast(&imd_terminate, 1, MPI_INT, 0, world); if (imd_terminate) error->all("LAMMPS terminated on error in setting up IMD connection."); if (imd_inactive) return; /* IMD client has detached and not yet come back. do nothing. */ } int *tag = atom->tag; double **x = atom->x; int *image = atom->image; int nlocal = atom->nlocal; int *mask = atom->mask; struct commdata *buf; /* Check if we need to communicate coordinates to the client. * Tuning imd_trate allows to keep the overhead for IMD low * at the expense of a more jumpy display. Rather than using * end_of_step() we do everything here in one go. * * If we don't communicate, only check if we have forces * stored away and apply them. */ if (update->ntimestep % imd_trate) { if (imd_forces > 0) { double **f = atom->f; buf = static_cast<struct commdata *>(force_buf); /* XXX. this is in principle O(N**2) = not good. * however we assume for now that the number of atoms * that we manipulate via IMD will be small compared * to the total system size, so we don't hurt too much. */ for (int j=0; j < imd_forces; ++j) { for (int i=0; i < nlocal; ++i) { if (mask[i] & groupbit) { if (buf[j].tag == tag[i]) { f[i][0] += buf[j].x; f[i][1] += buf[j].y; f[i][2] += buf[j].z; } } } } } return; } /* check and potentially grow local communication buffers. */ int i, k, nmax, nme=0; for (i=0; i < nlocal; ++i) if (mask[i] & groupbit) ++nme; MPI_Allreduce(&nme,&nmax,1,MPI_INT,MPI_MAX,world); if (nmax*size_one > maxbuf) { memory->sfree(comm_buf); maxbuf = nmax*size_one; comm_buf = memory->smalloc(maxbuf,"imd:comm_buf"); } MPI_Status status; MPI_Request request; int tmp, ndata; buf = static_cast<struct commdata *>(comm_buf); if (me == 0) { /* collect data into new array. we bypass the IMD API to save * us one extra copy of the data. */ int msglen = 3*sizeof(float)*num_coords+IMDHEADERSIZE; char *msgdata = new char[msglen]; imd_fill_header((IMDheader *)msgdata, IMD_FCOORDS, num_coords); /* array pointer, to the offset where we receive the coordinates. */ float *recvcoord = (float *) (msgdata+IMDHEADERSIZE); /* add local data */ if (unwrap_flag) { double xprd = domain->xprd; double yprd = domain->yprd; double zprd = domain->zprd; for (i=0; i<nlocal; ++i) { if (mask[i] & groupbit) { const int j = 3*inthash_lookup((inthash_t *)idmap, tag[i]); if (j != HASH_FAIL) { recvcoord[j] = x[i][0] + ((image[i] & 1023) - 512) * xprd; recvcoord[j+1] = x[i][1] + ((image[i] >> 10 & 1023) - 512) * yprd; recvcoord[j+2] = x[i][2] + ((image[i] >> 20) - 512) * zprd; } } } } else { for (i=0; i<nlocal; ++i) { if (mask[i] & groupbit) { const int j = 3*inthash_lookup((inthash_t *)idmap, tag[i]); if (j != HASH_FAIL) { recvcoord[j] = x[i][0]; recvcoord[j+1] = x[i][1]; recvcoord[j+2] = x[i][2]; } } } } /* loop over procs to receive remote data */ for (i=1; i < comm->nprocs; ++i) { MPI_Irecv(comm_buf, maxbuf, MPI_BYTE, i, 0, world, &request); MPI_Send(&tmp, 0, MPI_INT, i, 0, world); MPI_Wait(&request, &status); MPI_Get_count(&status, MPI_BYTE, &ndata); ndata /= size_one; for (k=0; k<ndata; ++k) { const int j = 3*inthash_lookup((inthash_t *)idmap, buf[k].tag); if (j != HASH_FAIL) { recvcoord[j] = buf[k].x; recvcoord[j+1] = buf[k].y; recvcoord[j+2] = buf[k].z; } } } /* done collecting frame data now communicate with IMD client. */ /* send coordinate data, if client is able to accept */ if (clientsock && imdsock_selwrite(clientsock,0)) { imd_writen(clientsock, msgdata, msglen); } delete[] msgdata; /* process all pending incoming data. */ int imd_paused=0; while ((imdsock_selread(clientsock, 0) > 0) || imd_paused) { /* if something requested to turn off IMD while paused get out */ if (imd_inactive) break; int32 length; int msg = imd_recv_header(clientsock, &length); switch(msg) { case IMD_GO: if (screen) fprintf(screen, "Ignoring unexpected IMD_GO message.\n"); break; case IMD_IOERROR: if (screen) fprintf(screen, "IMD connection lost.\n"); /* fallthrough */ case IMD_DISCONNECT: { /* disconnect from client. wait for new connection. */ imd_paused = 0; imd_forces = 0; memory->sfree(force_buf); force_buf = NULL; imdsock_destroy(clientsock); clientsock = NULL; if (screen) fprintf(screen, "IMD client detached. LAMMPS run continues.\n"); connect_msg = 1; reconnect(); if (imd_terminate) imd_inactive = 1; break; } case IMD_KILL: /* stop the simulation job and shutdown IMD */ if (screen) fprintf(screen, "IMD client requested termination of run.\n"); imd_inactive = 1; imd_terminate = 1; imd_paused = 0; imdsock_destroy(clientsock); clientsock = NULL; break; case IMD_PAUSE: /* pause the running simulation. wait for second IMD_PAUSE to continue. */ if (imd_paused) { if (screen) fprintf(screen, "Continuing run on IMD client request.\n"); imd_paused = 0; } else { if (screen) fprintf(screen, "Pausing run on IMD client request.\n"); imd_paused = 1; } break; case IMD_TRATE: /* change the IMD transmission data rate */ if (length > 0) imd_trate = length; if (screen) fprintf(screen, "IMD client requested change of transfer rate. Now it is %d.\n", imd_trate); break; case IMD_ENERGIES: { IMDEnergies dummy_energies; imd_recv_energies(clientsock, &dummy_energies); break; } case IMD_FCOORDS: { float *dummy_coords = new float[3*length]; imd_recv_fcoords(clientsock, length, dummy_coords); delete[] dummy_coords; break; } case IMD_MDCOMM: { int32 *imd_tags = new int32[length]; float *imd_fdat = new float[3*length]; imd_recv_mdcomm(clientsock, length, imd_tags, imd_fdat); if (imd_forces < length) { /* grow holding space for forces, if needed. */ if (force_buf != NULL) memory->sfree(force_buf); force_buf = memory->smalloc(length*size_one, "imd:force_buf"); } imd_forces = length; buf = static_cast<struct commdata *>(force_buf); /* compare data to hash table */ for (int ii=0; ii < length; ++ii) { buf[ii].tag = rev_idmap[imd_tags[ii]]; buf[ii].x = imd_fdat[3*ii]; buf[ii].y = imd_fdat[3*ii+1]; buf[ii].z = imd_fdat[3*ii+2]; } delete[] imd_tags; delete[] imd_fdat; break; } default: if (screen) fprintf(screen, "Unhandled incoming IMD message #%d. length=%d\n", msg, length); break; } } } else { /* copy coordinate data into communication buffer */ nme = 0; if (unwrap_flag) { double xprd = domain->xprd; double yprd = domain->yprd; double zprd = domain->zprd; for (i=0; i<nlocal; ++i) { if (mask[i] & groupbit) { buf[nme].tag = tag[i]; buf[nme].x = x[i][0] + ((image[i] & 1023) - 512) * xprd; buf[nme].y = x[i][1] + ((image[i] >> 10 & 1023) - 512) * yprd; buf[nme].z = x[i][2] + ((image[i] >> 20) - 512) * zprd; ++nme; } } } else { for (i=0; i<nlocal; ++i) { if (mask[i] & groupbit) { buf[nme].tag = tag[i]; buf[nme].x = x[i][0]; buf[nme].y = x[i][1]; buf[nme].z = x[i][2]; ++nme; } } } /* blocking receive to wait until it is our turn to send data. */ MPI_Recv(&tmp, 0, MPI_INT, 0, 0, world, &status); MPI_Rsend(comm_buf, nme*size_one, MPI_BYTE, 0, 0, world); } /* update all tasks with current settings. */ int old_imd_forces = imd_forces; MPI_Bcast(&imd_trate, 1, MPI_INT, 0, world); MPI_Bcast(&imd_inactive, 1, MPI_INT, 0, world); MPI_Bcast(&imd_forces, 1, MPI_INT, 0, world); MPI_Bcast(&imd_terminate, 1, MPI_INT, 0, world); if (imd_terminate) error->all("LAMMPS terminated on IMD request."); if (imd_forces > 0) { /* check if we need to readjust the forces comm buffer on the receiving nodes. */ if (me != 0) { if (old_imd_forces < imd_forces) { /* grow holding space for forces, if needed. */ if (force_buf != NULL) memory->sfree(force_buf); force_buf = memory->smalloc(imd_forces*size_one, "imd:force_buf"); } } MPI_Bcast(force_buf, imd_forces*size_one, MPI_BYTE, 0, world); } return; } /* ---------------------------------------------------------------------- */ void FixIMD::post_force_respa(int vflag, int ilevel, int iloop) { /* only process IMD on the outmost RESPA level. */ if (ilevel == nlevels_respa-1) post_force(vflag); return; } /* ---------------------------------------------------------------------- */ /* local memory usage. approximately. */ double FixIMD::memory_usage(void) { return static_cast<double>(num_coords+maxbuf+imd_forces)*size_one; } /* End of FixIMD class implementation. */ /************************************************************************ * integer list sort code: ************************************************************************/ /* sort for integer map. initial call id_sort(idmap, 0, natoms - 1); */ void id_sort(int *idmap, int left, int right) { int pivot, l_hold, r_hold; l_hold = left; r_hold = right; pivot = idmap[left]; while (left < right) { while ((idmap[right] >= pivot) && (left < right)) right--; if (left != right) { idmap[left] = idmap[right]; left++; } while ((idmap[left] <= pivot) && (left < right)) left++; if (left != right) { idmap[right] = idmap[left]; right--; } } idmap[left] = pivot; pivot = left; left = l_hold; right = r_hold; if (left < pivot) id_sort(idmap, left, pivot-1); if (right > pivot) id_sort(idmap, pivot+1, right); } /***************************************************************************/ /* NOTE: the following code is the based on the example implementation * of the IMD protocol API from VMD and NAMD. The UIUC license allows * to re-use up to 10% of a project's code to be used in other software */ /*************************************************************************** * DESCRIPTION: * Socket interface, abstracts machine dependent APIs/routines. ***************************************************************************/ int imdsock_init(void) { #if defined(_MSC_VER) int rc = 0; static int initialized=0; if (!initialized) { WSADATA wsdata; rc = WSAStartup(MAKEWORD(1,1), &wsdata); if (rc == 0) initialized = 1; } return rc; #else return 0; #endif } void * imdsock_create(void) { imdsocket * s; s = (imdsocket *) malloc(sizeof(imdsocket)); if (s != NULL) memset(s, 0, sizeof(imdsocket)); if ((s->sd = socket(PF_INET, SOCK_STREAM, 0)) == -1) { printf("Failed to open socket."); free(s); return NULL; } return (void *) s; } int imdsock_bind(void * v, int port) { imdsocket *s = (imdsocket *) v; memset(&(s->addr), 0, sizeof(s->addr)); s->addr.sin_family = PF_INET; s->addr.sin_port = htons(port); return bind(s->sd, (struct sockaddr *) &s->addr, sizeof(s->addr)); } int imdsock_listen(void * v) { imdsocket *s = (imdsocket *) v; return listen(s->sd, 5); } void *imdsock_accept(void * v) { int rc; imdsocket *new_s = NULL, *s = (imdsocket *) v; #if defined(ARCH_AIX5) || defined(ARCH_AIX5_64) || defined(ARCH_AIX6_64) unsigned int len; #elif defined(SOCKLEN_T) SOCKLEN_T len; #elif defined(_POSIX_SOURCE) socklen_t len; #else int len; #endif len = sizeof(s->addr); rc = accept(s->sd, (struct sockaddr *) &s->addr, ( socklen_t * ) &len); if (rc >= 0) { new_s = (imdsocket *) malloc(sizeof(imdsocket)); if (new_s != NULL) { *new_s = *s; new_s->sd = rc; } } return (void *)new_s; } int imdsock_write(void * v, const void *buf, int len) { imdsocket *s = (imdsocket *) v; #if defined(_MSC_VER) return send(s->sd, (const char*) buf, len, 0); /* windows lacks the write() call */ #else return write(s->sd, buf, len); #endif } int imdsock_read(void * v, void *buf, int len) { imdsocket *s = (imdsocket *) v; #if defined(_MSC_VER) return recv(s->sd, (char*) buf, len, 0); /* windows lacks the read() call */ #else return read(s->sd, buf, len); #endif } void imdsock_shutdown(void *v) { imdsocket * s = (imdsocket *) v; if (s == NULL) return; #if defined(_MSC_VER) shutdown(s->sd, SD_SEND); #else shutdown(s->sd, 1); /* complete sends and send FIN */ #endif } void imdsock_destroy(void * v) { imdsocket * s = (imdsocket *) v; if (s == NULL) return; #if defined(_MSC_VER) closesocket(s->sd); #else close(s->sd); #endif free(s); } int imdsock_selread(void *v, int sec) { imdsocket *s = (imdsocket *)v; fd_set rfd; struct timeval tv; int rc; if (v == NULL) return 0; FD_ZERO(&rfd); FD_SET(s->sd, &rfd); memset((void *)&tv, 0, sizeof(struct timeval)); tv.tv_sec = sec; do { rc = select(s->sd+1, &rfd, NULL, NULL, &tv); } while (rc < 0 && errno == EINTR); return rc; } int imdsock_selwrite(void *v, int sec) { imdsocket *s = (imdsocket *)v; fd_set wfd; struct timeval tv; int rc; if (v == NULL) return 0; FD_ZERO(&wfd); FD_SET(s->sd, &wfd); memset((void *)&tv, 0, sizeof(struct timeval)); tv.tv_sec = sec; do { rc = select(s->sd + 1, NULL, &wfd, NULL, &tv); } while (rc < 0 && errno == EINTR); return rc; } /* end of socket code. */ /*************************************************************************/ /*************************************************************************/ /* start of imd API code. */ /* Only works with aligned 4-byte quantities, will cause a bus error */ /* on some platforms if used on unaligned data. */ void swap4_aligned(void *v, long ndata) { int *data = (int *) v; long i; int *N; for (i=0; i<ndata; i++) { N = data + i; *N=(((*N>>24)&0xff) | ((*N&0xff)<<24) | ((*N>>8)&0xff00) | ((*N&0xff00)<<8)); } } /** structure used to perform byte swapping operations */ typedef union { int32 i; struct { unsigned int highest : 8; unsigned int high : 8; unsigned int low : 8; unsigned int lowest : 8; } b; } netint; static int32 imd_htonl(int32 h) { netint n; n.b.highest = h >> 24; n.b.high = h >> 16; n.b.low = h >> 8; n.b.lowest = h; return n.i; } static int32 imd_ntohl(int32 n) { netint u; u.i = n; return (u.b.highest << 24 | u.b.high << 16 | u.b.low << 8 | u.b.lowest); } static void imd_fill_header(IMDheader *header, IMDType type, int32 length) { header->type = imd_htonl((int32)type); header->length = imd_htonl(length); } static void swap_header(IMDheader *header) { header->type = imd_ntohl(header->type); header->length= imd_ntohl(header->length); } static int32 imd_readn(void *s, char *ptr, int32 n) { int32 nleft; int32 nread; nleft = n; while (nleft > 0) { if ((nread = imdsock_read(s, ptr, nleft)) < 0) { if (errno == EINTR) nread = 0; /* and call read() again */ else return -1; } else if (nread == 0) break; /* EOF */ nleft -= nread; ptr += nread; } return n-nleft; } static int32 imd_writen(void *s, const char *ptr, int32 n) { int32 nleft; int32 nwritten; nleft = n; while (nleft > 0) { if ((nwritten = imdsock_write(s, ptr, nleft)) <= 0) { if (errno == EINTR) nwritten = 0; else return -1; } nleft -= nwritten; ptr += nwritten; } return n; } int imd_disconnect(void *s) { IMDheader header; imd_fill_header(&header, IMD_DISCONNECT, 0); return (imd_writen(s, (char *)&header, IMDHEADERSIZE) != IMDHEADERSIZE); } int imd_handshake(void *s) { IMDheader header; imd_fill_header(&header, IMD_HANDSHAKE, 1); header.length = IMDVERSION; /* Not byteswapped! */ return (imd_writen(s, (char *)&header, IMDHEADERSIZE) != IMDHEADERSIZE); } /* The IMD receive functions */ IMDType imd_recv_header(void *s, int32 *length) { IMDheader header; if (imd_readn(s, (char *)&header, IMDHEADERSIZE) != IMDHEADERSIZE) return IMD_IOERROR; swap_header(&header); *length = header.length; return IMDType(header.type); } int imd_recv_mdcomm(void *s, int32 n, int32 *indices, float *forces) { if (imd_readn(s, (char *)indices, 4*n) != 4*n) return 1; if (imd_readn(s, (char *)forces, 12*n) != 12*n) return 1; return 0; } int imd_recv_energies(void *s, IMDEnergies *energies) { return (imd_readn(s, (char *)energies, sizeof(IMDEnergies)) != sizeof(IMDEnergies)); } int imd_recv_fcoords(void *s, int32 n, float *coords) { return (imd_readn(s, (char *)coords, 12*n) != 12*n); } /************************************************************************ * integer hash code: ************************************************************************/ /* inthash() - Hash function returns a hash number for a given key. * tptr: Pointer to a hash table, key: The key to create a hash number for */ static int inthash(const inthash_t *tptr, int key) { int hashvalue; hashvalue = (((key*1103515249)>>tptr->downshift) & tptr->mask); if (hashvalue < 0) { hashvalue = 0; } return hashvalue; } /* * rebuild_table_int() - Create new hash table when old one fills up. * * tptr: Pointer to a hash table */ static void rebuild_table_int(inthash_t *tptr) { inthash_node_t **old_bucket, *old_hash, *tmp; int old_size, h, i; old_bucket=tptr->bucket; old_size=tptr->size; /* create a new table and rehash old buckets */ inthash_init(tptr, old_size<<1); for (i=0; i<old_size; i++) { old_hash=old_bucket[i]; while(old_hash) { tmp=old_hash; old_hash=old_hash->next; h=inthash(tptr, tmp->key); tmp->next=tptr->bucket[h]; tptr->bucket[h]=tmp; tptr->entries++; } /* while */ } /* for */ /* free memory used by old table */ free(old_bucket); return; } /* * inthash_init() - Initialize a new hash table. * * tptr: Pointer to the hash table to initialize * buckets: The number of initial buckets to create */ void inthash_init(inthash_t *tptr, int buckets) { /* make sure we allocate something */ if (buckets==0) buckets=16; /* initialize the table */ tptr->entries=0; tptr->size=2; tptr->mask=1; tptr->downshift=29; /* ensure buckets is a power of 2 */ while (tptr->size<buckets) { tptr->size<<=1; tptr->mask=(tptr->mask<<1)+1; tptr->downshift--; } /* while */ /* allocate memory for table */ tptr->bucket=(inthash_node_t **) calloc(tptr->size, sizeof(inthash_node_t *)); return; } /* * inthash_lookup() - Lookup an entry in the hash table and return a pointer to * it or HASH_FAIL if it wasn't found. * * tptr: Pointer to the hash table * key: The key to lookup */ int inthash_lookup(const inthash_t *tptr, int key) { int h; inthash_node_t *node; /* find the entry in the hash table */ h=inthash(tptr, key); for (node=tptr->bucket[h]; node!=NULL; node=node->next) { if (node->key == key) break; } /* return the entry if it exists, or HASH_FAIL */ return(node ? node->data : HASH_FAIL); } /* * inthash_keys() - Return a list of keys. * NOTE: the returned list must be freed with free(3). */ int *inthash_keys(inthash_t *tptr) { int *keys; inthash_node_t *node; keys = (int *)calloc(tptr->entries, sizeof(int)); for (int i=0; i < tptr->size; ++i) { for (node=tptr->bucket[i]; node != NULL; node=node->next) { keys[node->data] = node->key; } } return keys; } /* * inthash_insert() - Insert an entry into the hash table. If the entry already * exists return a pointer to it, otherwise return HASH_FAIL. * * tptr: A pointer to the hash table * key: The key to insert into the hash table * data: A pointer to the data to insert into the hash table */ int inthash_insert(inthash_t *tptr, int key, int data) { int tmp; inthash_node_t *node; int h; /* check to see if the entry exists */ if ((tmp=inthash_lookup(tptr, key)) != HASH_FAIL) return(tmp); /* expand the table if needed */ while (tptr->entries>=HASH_LIMIT*tptr->size) rebuild_table_int(tptr); /* insert the new entry */ h=inthash(tptr, key); node=(struct inthash_node_t *) malloc(sizeof(inthash_node_t)); node->data=data; node->key=key; node->next=tptr->bucket[h]; tptr->bucket[h]=node; tptr->entries++; return HASH_FAIL; } /* * inthash_destroy() - Delete the entire table, and all remaining entries. * */ void inthash_destroy(inthash_t *tptr) { inthash_node_t *node, *last; int i; for (i=0; i<tptr->size; i++) { node = tptr->bucket[i]; while (node != NULL) { last = node; node = node->next; free(last); } } /* free the entire array of buckets */ if (tptr->bucket != NULL) { free(tptr->bucket); memset(tptr, 0, sizeof(inthash_t)); } } // Local Variables: // mode: c++ // compile-command: "make -j4 openmpi" // c-basic-offset: 2 // fill-column: 76 // indent-tabs-mode: nil // End: diff --git a/src/XTC/dump_xtc.cpp b/src/XTC/dump_xtc.cpp index 0aed69ea7..89ea2eb1c 100644 --- a/src/XTC/dump_xtc.cpp +++ b/src/XTC/dump_xtc.cpp @@ -1,1201 +1,1208 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- Contributing authors: Naveen Michaud-Agrawal (Johns Hopkins U) open-source XDR routines from Frans van Hoesel (http://md.chem.rug.nl/hoesel) are included in this file Axel Kohlmeyer (Temple U) port to platforms without XDR support added support for unwrapped trajectories support for groups ------------------------------------------------------------------------- */ #include "math.h" #include "stdio.h" #include "stdlib.h" #include "string.h" #include "limits.h" #include "dump_xtc.h" #include "domain.h" #include "atom.h" #include "update.h" #include "group.h" #include "output.h" #include "error.h" #include "memory.h" using namespace LAMMPS_NS; #define EPS 1e-5 #define XTC_MAGIC 1995 #define MYMIN(a,b) ((a) < (b) ? (a) : (b)) #define MYMAX(a,b) ((a) > (b) ? (a) : (b)) int xdropen(XDR *, const char *, const char *); int xdrclose(XDR *); void xdrfreebuf(); int xdr3dfcoord(XDR *, float *, int *, float *); /* ---------------------------------------------------------------------- */ DumpXTC::DumpXTC(LAMMPS *lmp, int narg, char **arg) : Dump(lmp, narg, arg) { if (narg != 5) error->all("Illegal dump xtc command"); if (binary || compressed || multifile || multiproc) error->all("Invalid dump xtc filename"); size_one = 3; sort_flag = 1; sortcol = 0; format_default = NULL; flush_flag = 0; unwrap_flag = 0; precision = 1000.0; // allocate global array for atom coords - if (igroup == 0) natoms = static_cast<int> (atom->natoms); - else natoms = static_cast<int> (group->count(igroup)); - if (natoms <= 0) error->all("Invalid natoms for dump xtc"); + bigint n = group->count(igroup); + if (n > MAXSMALLINT/3/sizeof(float)) + error->all("Too many atoms for dump xtc"); + natoms = static_cast<int> (n); coords = (float *) memory->smalloc(3*natoms*sizeof(float),"dump:coords"); // sfactor = conversion of coords to XTC units // GROMACS standard is nanometers, not Angstroms sfactor = 0.1; if (strcmp(update->unit_style,"lj") == 0) sfactor = 1.0; openfile(); nevery_save = 0; ntotal = 0; } /* ---------------------------------------------------------------------- */ DumpXTC::~DumpXTC() { memory->sfree(coords); if (me == 0) { xdrclose(&xd); xdrfreebuf(); } } /* ---------------------------------------------------------------------- */ void DumpXTC::init_style() { if (sort_flag == 0 || sortcol != 0) error->all("Dump xtc requires sorting by atom ID"); // check that flush_flag is not set since dump::write() will use it if (flush_flag) error->all("Cannot set dump_modify flush for dump xtc"); // check that dump frequency has not changed and is not a variable int idump; for (idump = 0; idump < output->ndump; idump++) if (strcmp(id,output->dump[idump]->id) == 0) break; if (output->every_dump[idump] == 0) error->all("Cannot use variable every setting for dump xtc"); if (nevery_save == 0) nevery_save = output->every_dump[idump]; else if (nevery_save != output->every_dump[idump]) error->all("Cannot change dump_modify every for dump xtc"); } /* ---------------------------------------------------------------------- */ void DumpXTC::openfile() { // XTC maintains it's own XDR file ptr // set fp to NULL so parent dump class will not use it fp = NULL; if (me == 0) if (xdropen(&xd,filename,"w") == 0) error->one("Cannot open dump file"); } /* ---------------------------------------------------------------------- */ -void DumpXTC::write_header(int n) +void DumpXTC::write_header(bigint nbig) { + if (nbig > MAXSMALLINT) error->all("Too many atoms for dump xtc"); + int n = nbig; + if (update->ntimestep > MAXSMALLINT) + error->all("Too big a timestep for dump xtc"); + int ntimestep = update->ntimestep; + // all procs realloc coords if total count grew if (n != natoms) { natoms = n; memory->sfree(coords); coords = (float *) memory->smalloc(3*natoms*sizeof(float),"dump:coords"); } // only proc 0 writes header if (me != 0) return; int tmp = XTC_MAGIC; xdr_int(&xd,&tmp); xdr_int(&xd,&n); - xdr_int(&xd,&update->ntimestep); - float time_value = update->ntimestep * update->dt; + xdr_int(&xd,&ntimestep); + float time_value = ntimestep * update->dt; xdr_float(&xd,&time_value); // cell basis vectors if (domain->triclinic) { float zero = 0.0; float xdim = sfactor * (domain->boxhi[0] - domain->boxlo[0]); float ydim = sfactor * (domain->boxhi[1] - domain->boxlo[1]); float zdim = sfactor * (domain->boxhi[2] - domain->boxlo[2]); float xy = sfactor * domain->xy; float xz = sfactor * domain->xz; float yz = sfactor * domain->yz; xdr_float(&xd,&xdim); xdr_float(&xd,&zero); xdr_float(&xd,&zero); xdr_float(&xd,&xy ); xdr_float(&xd,&ydim); xdr_float(&xd,&zero); xdr_float(&xd,&xz ); xdr_float(&xd,&yz ); xdr_float(&xd,&zdim); } else { float zero = 0.0; float xdim = sfactor * (domain->boxhi[0] - domain->boxlo[0]); float ydim = sfactor * (domain->boxhi[1] - domain->boxlo[1]); float zdim = sfactor * (domain->boxhi[2] - domain->boxlo[2]); xdr_float(&xd,&xdim); xdr_float(&xd,&zero); xdr_float(&xd,&zero); xdr_float(&xd,&zero); xdr_float(&xd,&ydim); xdr_float(&xd,&zero); xdr_float(&xd,&zero); xdr_float(&xd,&zero); xdr_float(&xd,&zdim); } } /* ---------------------------------------------------------------------- */ int DumpXTC::count() { if (igroup == 0) return atom->nlocal; int *mask = atom->mask; int nlocal = atom->nlocal; int m = 0; for (int i = 0; i < nlocal; i++) if (mask[i] & groupbit) m++; return m; } /* ---------------------------------------------------------------------- */ void DumpXTC::pack(int *ids) { int m,n; int *tag = atom->tag; double **x = atom->x; int *image = atom->image; int *mask = atom->mask; int nlocal = atom->nlocal; m = n = 0; if (unwrap_flag == 1) { double xprd = domain->xprd; double yprd = domain->yprd; double zprd = domain->zprd; double xy = domain->xy; double xz = domain->xz; double yz = domain->yz; for (int i = 0; i < nlocal; i++) if (mask[i] & groupbit) { int ix = (image[i] & 1023) - 512; int iy = (image[i] >> 10 & 1023) - 512; int iz = (image[i] >> 20) - 512; if (domain->triclinic) { buf[m++] = sfactor * (x[i][0] + ix * xprd + iy * xy + iz * xz); buf[m++] = sfactor * (x[i][1] + iy * yprd + iz * yz); buf[m++] = sfactor * (x[i][2] + iz * zprd); } else { buf[m++] = sfactor * (x[i][0] + ix * xprd); buf[m++] = sfactor * (x[i][1] + iy * yprd); buf[m++] = sfactor * (x[i][2] + iz * zprd); } ids[n++] = tag[i]; } } else { for (int i = 0; i < nlocal; i++) if (mask[i] & groupbit) { buf[m++] = sfactor*x[i][0]; buf[m++] = sfactor*x[i][1]; buf[m++] = sfactor*x[i][2]; ids[n++] = tag[i]; } } } /* ---------------------------------------------------------------------- */ void DumpXTC::write_data(int n, double *mybuf) { int j; // copy buf atom coords into global array int m = 0; int k = 3*ntotal; for (int i = 0; i < n; i++) { coords[k++] = mybuf[m++]; coords[k++] = mybuf[m++]; coords[k++] = mybuf[m++]; ntotal++; } // if last chunk of atoms in this snapshot, write global arrays to file if (ntotal == natoms) { write_frame(); ntotal = 0; } } /* ---------------------------------------------------------------------- */ int DumpXTC::modify_param(int narg, char **arg) { if (strcmp(arg[0],"unwrap") == 0) { if (narg < 2) error->all("Illegal dump_modify command"); if (strcmp(arg[1],"yes") == 0) unwrap_flag = 1; else if (strcmp(arg[1],"no") == 0) unwrap_flag = 0; else error->all("Illegal dump_modify command"); return 2; } else if (strcmp(arg[0],"precision") == 0) { if (narg < 2) error->all("Illegal dump_modify command"); precision = atof(arg[1]); if ((fabs(precision-10.0) > EPS) && (fabs(precision-100.0) > EPS) && (fabs(precision-1000.0) > EPS) && (fabs(precision-10000.0) > EPS) && (fabs(precision-100000.0) > EPS) && (fabs(precision-1000000.0) > EPS)) error->all("Illegal dump_modify command"); return 2; } return 0; } /* ---------------------------------------------------------------------- return # of bytes of allocated memory in buf and global coords array ------------------------------------------------------------------------- */ double DumpXTC::memory_usage() { double bytes = Dump::memory_usage(); bytes += 3*natoms * sizeof(float); return bytes; } /* ---------------------------------------------------------------------- */ void DumpXTC::write_frame() { xdr3dfcoord(&xd,coords,&natoms,&precision); } // ---------------------------------------------------------------------- // C functions that create GROMOS-compatible XDR files // open-source // (c) 1995 Frans van Hoesel, hoesel@chem.rug.nl // ---------------------------------------------------------------------- /*____________________________________________________________________________ | | Below are the routines to be used by C programmers. Use the 'normal' | xdr routines to write integers, floats, etc (see man xdr) | | int xdropen(XDR *xdrs, const char *filename, const char *type) | This will open the file with the given filename and the | given mode. You should pass it an allocated XDR struct | in xdrs, to be used in all other calls to xdr routines. | Mode is 'w' to create, or update an file, and for all | other values of mode the file is opened for reading. | You need to call xdrclose to flush the output and close | the file. | | Note that you should not use xdrstdio_create, which | comes with the standard xdr library. | | int xdrclose(XDR *xdrs) | Flush the data to the file, and close the file; | You should not use xdr_destroy (which comes standard | with the xdr libraries). | | int xdr3dfcoord(XDR *xdrs, float *fp, int *size, float *precision) | This is \fInot\fR a standard xdr routine. I named it this | way, because it invites people to use the other xdr | routines. | | (c) 1995 Frans van Hoesel, hoesel@chem.rug.nl */ #define MAXID 20 static FILE *xdrfiles[MAXID]; static XDR *xdridptr[MAXID]; static char xdrmodes[MAXID]; static int *ip = NULL; static int *buf = NULL; /*___________________________________________________________________________ | | what follows are the C routines for opening, closing xdr streams | and the routine to read/write compressed coordinates together | with some routines to assist in this task (those are marked | static and cannot be called from user programs) */ #define MAXABS INT_MAX-2 #ifndef SQR #define SQR(x) ((x)*(x)) #endif static int magicints[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 10, 12, 16, 20, 25, 32, 40, 50, 64, 80, 101, 128, 161, 203, 256, 322, 406, 512, 645, 812, 1024, 1290, 1625, 2048, 2580, 3250, 4096, 5060, 6501, 8192, 10321, 13003, 16384, 20642, 26007, 32768, 41285, 52015, 65536, 82570, 104031, 131072, 165140, 208063, 262144, 330280, 416127, 524287, 660561, 832255, 1048576, 1321122, 1664510, 2097152, 2642245, 3329021, 4194304, 5284491, 6658042, 8388607, 10568983, 13316085, 16777216 }; #define FIRSTIDX 9 /* note that magicints[FIRSTIDX-1] == 0 */ #define LASTIDX (sizeof(magicints) / sizeof(*magicints)) /*__________________________________________________________________________ | | xdropen - open xdr file | | This versions differs from xdrstdio_create, because I need to know | the state of the file (read or write) so I can use xdr3dfcoord | in eigther read or write mode, and the file descriptor | so I can close the file (something xdr_destroy doesn't do). | */ int xdropen(XDR *xdrs, const char *filename, const char *type) { static int init_done = 0; enum xdr_op lmode; int xdrid; if (init_done == 0) { for (xdrid = 1; xdrid < MAXID; xdrid++) { xdridptr[xdrid] = NULL; } init_done = 1; } xdrid = 1; while (xdrid < MAXID && xdridptr[xdrid] != NULL) { xdrid++; } if (xdrid == MAXID) { return 0; } if (*type == 'w' || *type == 'W') { type = (char *) "w+"; lmode = XDR_ENCODE; } else { type = (char *) "r"; lmode = XDR_DECODE; } xdrfiles[xdrid] = fopen(filename, type); if (xdrfiles[xdrid] == NULL) { xdrs = NULL; return 0; } xdrmodes[xdrid] = *type; /* next test isn't usefull in the case of C language * but is used for the Fortran interface * (C users are expected to pass the address of an already allocated * XDR staructure) */ if (xdrs == NULL) { xdridptr[xdrid] = (XDR *) malloc(sizeof(XDR)); xdrstdio_create(xdridptr[xdrid], xdrfiles[xdrid], lmode); } else { xdridptr[xdrid] = xdrs; xdrstdio_create(xdrs, xdrfiles[xdrid], lmode); } return xdrid; } /*_________________________________________________________________________ | | xdrclose - close a xdr file | | This will flush the xdr buffers, and destroy the xdr stream. | It also closes the associated file descriptor (this is *not* | done by xdr_destroy). | */ int xdrclose(XDR *xdrs) { int xdrid; if (xdrs == NULL) { fprintf(stderr, "xdrclose: passed a NULL pointer\n"); exit(1); } for (xdrid = 1; xdrid < MAXID; xdrid++) { if (xdridptr[xdrid] == xdrs) { xdr_destroy(xdrs); fclose(xdrfiles[xdrid]); xdridptr[xdrid] = NULL; return 1; } } fprintf(stderr, "xdrclose: no such open xdr file\n"); exit(1); return 1; } /*_________________________________________________________________________ | | xdrfreebuf - free the buffers used by xdr3dfcoord | */ void xdrfreebuf() { if (ip) free(ip); if (buf) free(buf); ip = NULL; buf = NULL; } /*____________________________________________________________________________ | | sendbits - encode num into buf using the specified number of bits | | This routines appends the value of num to the bits already present in | the array buf. You need to give it the number of bits to use and you | better make sure that this number of bits is enough to hold the value | Also num must be positive. | */ static void sendbits(int buf[], int num_of_bits, int num) { unsigned int cnt, lastbyte; int lastbits; unsigned char * cbuf; cbuf = ((unsigned char *)buf) + 3 * sizeof(*buf); cnt = (unsigned int) buf[0]; lastbits = buf[1]; lastbyte =(unsigned int) buf[2]; while (num_of_bits >= 8) { lastbyte = (lastbyte << 8) | ((num >> (num_of_bits -8)) /* & 0xff*/); cbuf[cnt++] = lastbyte >> lastbits; num_of_bits -= 8; } if (num_of_bits > 0) { lastbyte = (lastbyte << num_of_bits) | num; lastbits += num_of_bits; if (lastbits >= 8) { lastbits -= 8; cbuf[cnt++] = lastbyte >> lastbits; } } buf[0] = cnt; buf[1] = lastbits; buf[2] = lastbyte; if (lastbits>0) { cbuf[cnt] = lastbyte << (8 - lastbits); } } /*_________________________________________________________________________ | | sizeofint - calculate bitsize of an integer | | return the number of bits needed to store an integer with given max size | */ static int sizeofint(const int size) { unsigned int num = 1; int num_of_bits = 0; while (size >= num && num_of_bits < 32) { num_of_bits++; num <<= 1; } return num_of_bits; } /*___________________________________________________________________________ | | sizeofints - calculate 'bitsize' of compressed ints | | given the number of small unsigned integers and the maximum value | return the number of bits needed to read or write them with the | routines receiveints and sendints. You need this parameter when | calling these routines. Note that for many calls I can use | the variable 'smallidx' which is exactly the number of bits, and | So I don't need to call 'sizeofints for those calls. */ static int sizeofints( const int num_of_ints, unsigned int sizes[]) { int i, num; unsigned int num_of_bytes, num_of_bits, bytes[32], bytecnt, tmp; num_of_bytes = 1; bytes[0] = 1; num_of_bits = 0; for (i=0; i < num_of_ints; i++) { tmp = 0; for (bytecnt = 0; bytecnt < num_of_bytes; bytecnt++) { tmp = bytes[bytecnt] * sizes[i] + tmp; bytes[bytecnt] = tmp & 0xff; tmp >>= 8; } while (tmp != 0) { bytes[bytecnt++] = tmp & 0xff; tmp >>= 8; } num_of_bytes = bytecnt; } num = 1; num_of_bytes--; while (bytes[num_of_bytes] >= num) { num_of_bits++; num *= 2; } return num_of_bits + num_of_bytes * 8; } /*____________________________________________________________________________ | | sendints - send a small set of small integers in compressed | | this routine is used internally by xdr3dfcoord, to send a set of | small integers to the buffer. | Multiplication with fixed (specified maximum ) sizes is used to get | to one big, multibyte integer. Allthough the routine could be | modified to handle sizes bigger than 16777216, or more than just | a few integers, this is not done, because the gain in compression | isn't worth the effort. Note that overflowing the multiplication | or the byte buffer (32 bytes) is unchecked and causes bad results. | */ static void sendints(int buf[], const int num_of_ints, const int num_of_bits, unsigned int sizes[], unsigned int nums[]) { int i; unsigned int bytes[32], num_of_bytes, bytecnt, tmp; tmp = nums[0]; num_of_bytes = 0; do { bytes[num_of_bytes++] = tmp & 0xff; tmp >>= 8; } while (tmp != 0); for (i = 1; i < num_of_ints; i++) { if (nums[i] >= sizes[i]) { fprintf(stderr,"major breakdown in sendints num %d doesn't " "match size %d\n", nums[i], sizes[i]); exit(1); } /* use one step multiply */ tmp = nums[i]; for (bytecnt = 0; bytecnt < num_of_bytes; bytecnt++) { tmp = bytes[bytecnt] * sizes[i] + tmp; bytes[bytecnt] = tmp & 0xff; tmp >>= 8; } while (tmp != 0) { bytes[bytecnt++] = tmp & 0xff; tmp >>= 8; } num_of_bytes = bytecnt; } if (num_of_bits >= num_of_bytes * 8) { for (i = 0; i < num_of_bytes; i++) { sendbits(buf, 8, bytes[i]); } sendbits(buf, num_of_bits - num_of_bytes * 8, 0); } else { for (i = 0; i < num_of_bytes-1; i++) { sendbits(buf, 8, bytes[i]); } sendbits(buf, num_of_bits- (num_of_bytes -1) * 8, bytes[i]); } } /*___________________________________________________________________________ | | receivebits - decode number from buf using specified number of bits | | extract the number of bits from the array buf and construct an integer | from it. Return that value. | */ static int receivebits(int buf[], int num_of_bits) { int cnt, num; unsigned int lastbits, lastbyte; unsigned char * cbuf; int mask = (1 << num_of_bits) -1; cbuf = ((unsigned char *)buf) + 3 * sizeof(*buf); cnt = buf[0]; lastbits = (unsigned int) buf[1]; lastbyte = (unsigned int) buf[2]; num = 0; while (num_of_bits >= 8) { lastbyte = ( lastbyte << 8 ) | cbuf[cnt++]; num |= (lastbyte >> lastbits) << (num_of_bits - 8); num_of_bits -=8; } if (num_of_bits > 0) { if (lastbits < num_of_bits) { lastbits += 8; lastbyte = (lastbyte << 8) | cbuf[cnt++]; } lastbits -= num_of_bits; num |= (lastbyte >> lastbits) & ((1 << num_of_bits) -1); } num &= mask; buf[0] = cnt; buf[1] = lastbits; buf[2] = lastbyte; return num; } /*____________________________________________________________________________ | | receiveints - decode 'small' integers from the buf array | | this routine is the inverse from sendints() and decodes the small integers | written to buf by calculating the remainder and doing divisions with | the given sizes[]. You need to specify the total number of bits to be | used from buf in num_of_bits. | */ static void receiveints(int buf[], const int num_of_ints, int num_of_bits, unsigned int sizes[], int nums[]) { int bytes[32]; int i, j, num_of_bytes, p, num; bytes[1] = bytes[2] = bytes[3] = 0; num_of_bytes = 0; while (num_of_bits > 8) { bytes[num_of_bytes++] = receivebits(buf, 8); num_of_bits -= 8; } if (num_of_bits > 0) { bytes[num_of_bytes++] = receivebits(buf, num_of_bits); } for (i = num_of_ints-1; i > 0; i--) { num = 0; for (j = num_of_bytes-1; j >=0; j--) { num = (num << 8) | bytes[j]; p = num / sizes[i]; bytes[j] = p; num = num - p * sizes[i]; } nums[i] = num; } nums[0] = bytes[0] | (bytes[1] << 8) | (bytes[2] << 16) | (bytes[3] << 24); } /*____________________________________________________________________________ | | xdr3dfcoord - read or write compressed 3d coordinates to xdr file. | | this routine reads or writes (depending on how you opened the file with | xdropen() ) a large number of 3d coordinates (stored in *fp). | The number of coordinates triplets to write is given by *size. On | read this number may be zero, in which case it reads as many as were written | or it may specify the number if triplets to read (which should match the | number written). | Compression is achieved by first converting all floating numbers to integer | using multiplication by *precision and rounding to the nearest integer. | Then the minimum and maximum value are calculated to determine the range. | The limited range of integers so found, is used to compress the coordinates. | In addition the differences between succesive coordinates is calculated. | If the difference happens to be 'small' then only the difference is saved, | compressing the data even more. The notion of 'small' is changed dynamically | and is enlarged or reduced whenever needed or possible. | Extra compression is achieved in the case of GROMOS and coordinates of | water molecules. GROMOS first writes out the Oxygen position, followed by | the two hydrogens. In order to make the differences smaller (and thereby | compression the data better) the order is changed into first one hydrogen | then the oxygen, followed by the other hydrogen. This is rather special, but | it shouldn't harm in the general case. | */ int xdr3dfcoord(XDR *xdrs, float *fp, int *size, float *precision) { static int oldsize; int minint[3], maxint[3], mindiff, *lip, diff; int lint1, lint2, lint3, oldlint1, oldlint2, oldlint3, smallidx; int minidx, maxidx; unsigned sizeint[3], sizesmall[3], bitsizeint[3], size3, *luip; int flag, k; int small, smaller, larger, i, is_small, is_smaller, run, prevrun; float *lfp, lf; int tmp, *thiscoord, prevcoord[3]; unsigned int tmpcoord[30]; int bufsize, xdrid, lsize; unsigned int bitsize; float inv_precision; int errval = 1; /* find out if xdrs is opened for reading or for writing */ xdrid = 0; while (xdridptr[xdrid] != xdrs) { xdrid++; if (xdrid >= MAXID) { fprintf(stderr, "xdr error. no open xdr stream\n"); exit (1); } } if (xdrmodes[xdrid] == 'w') { /* xdrs is open for writing */ if (xdr_int(xdrs, size) == 0) return 0; size3 = *size * 3; /* when the number of coordinates is small, don't try to compress; just * write them as floats using xdr_vector */ if (*size <= 9 ) { return (xdr_vector(xdrs, (char *) fp, size3, sizeof(*fp), (xdrproc_t)xdr_float)); } xdr_float(xdrs, precision); if (ip == NULL) { ip = (int *) malloc(size3 * sizeof(*ip)); if (ip == NULL) { fprintf(stderr,"malloc failed\n"); exit(1); } bufsize = (int) (size3 * 1.2); buf = (int *) malloc(bufsize * sizeof(*buf)); if (buf == NULL) { fprintf(stderr,"malloc failed\n"); exit(1); } oldsize = *size; } else if (*size > oldsize) { ip = (int *) realloc(ip, size3 * sizeof(*ip)); if (ip == NULL) { fprintf(stderr,"malloc failed\n"); exit(1); } bufsize = (int) (size3 * 1.2); buf = (int *) realloc(buf, bufsize * sizeof(*buf)); if (buf == NULL) { fprintf(stderr,"malloc failed\n"); exit(1); } oldsize = *size; } /* buf[0-2] are special and do not contain actual data */ buf[0] = buf[1] = buf[2] = 0; minint[0] = minint[1] = minint[2] = INT_MAX; maxint[0] = maxint[1] = maxint[2] = INT_MIN; prevrun = -1; lfp = fp; lip = ip; mindiff = INT_MAX; oldlint1 = oldlint2 = oldlint3 = 0; while(lfp < fp + size3 ) { /* find nearest integer */ if (*lfp >= 0.0) lf = *lfp * *precision + 0.5; else lf = *lfp * *precision - 0.5; if (fabs(lf) > MAXABS) { /* scaling would cause overflow */ errval = 0; } lint1 = (int) lf; if (lint1 < minint[0]) minint[0] = lint1; if (lint1 > maxint[0]) maxint[0] = lint1; *lip++ = lint1; lfp++; if (*lfp >= 0.0) lf = *lfp * *precision + 0.5; else lf = *lfp * *precision - 0.5; if (fabs(lf) > MAXABS) { /* scaling would cause overflow */ errval = 0; } lint2 = (int) lf; if (lint2 < minint[1]) minint[1] = lint2; if (lint2 > maxint[1]) maxint[1] = lint2; *lip++ = lint2; lfp++; if (*lfp >= 0.0) lf = *lfp * *precision + 0.5; else lf = *lfp * *precision - 0.5; if (fabs(lf) > MAXABS) { /* scaling would cause overflow */ errval = 0; } lint3 = (int) lf; if (lint3 < minint[2]) minint[2] = lint3; if (lint3 > maxint[2]) maxint[2] = lint3; *lip++ = lint3; lfp++; diff = abs(oldlint1-lint1)+abs(oldlint2-lint2)+abs(oldlint3-lint3); if (diff < mindiff && lfp > fp + 3) mindiff = diff; oldlint1 = lint1; oldlint2 = lint2; oldlint3 = lint3; } xdr_int(xdrs, &(minint[0])); xdr_int(xdrs, &(minint[1])); xdr_int(xdrs, &(minint[2])); xdr_int(xdrs, &(maxint[0])); xdr_int(xdrs, &(maxint[1])); xdr_int(xdrs, &(maxint[2])); if ((float)maxint[0] - (float)minint[0] >= MAXABS || (float)maxint[1] - (float)minint[1] >= MAXABS || (float)maxint[2] - (float)minint[2] >= MAXABS) { /* turning value in unsigned by subtracting minint * would cause overflow */ errval = 0; } sizeint[0] = maxint[0] - minint[0]+1; sizeint[1] = maxint[1] - minint[1]+1; sizeint[2] = maxint[2] - minint[2]+1; /* check if one of the sizes is to big to be multiplied */ if ((sizeint[0] | sizeint[1] | sizeint[2] ) > 0xffffff) { bitsizeint[0] = sizeofint(sizeint[0]); bitsizeint[1] = sizeofint(sizeint[1]); bitsizeint[2] = sizeofint(sizeint[2]); bitsize = 0; /* flag the use of large sizes */ } else { bitsize = sizeofints(3, sizeint); } lip = ip; luip = (unsigned int *) ip; smallidx = FIRSTIDX; while (smallidx < LASTIDX && magicints[smallidx] < mindiff) { smallidx++; } xdr_int(xdrs, &smallidx); maxidx = MYMIN(LASTIDX, smallidx + 8) ; minidx = maxidx - 8; /* often this equal smallidx */ smaller = magicints[MYMAX(FIRSTIDX, smallidx-1)] / 2; small = magicints[smallidx] / 2; sizesmall[0] = sizesmall[1] = sizesmall[2] = magicints[smallidx]; larger = magicints[maxidx] / 2; i = 0; while (i < *size) { is_small = 0; thiscoord = (int *)(luip) + i * 3; if (smallidx < maxidx && i >= 1 && abs(thiscoord[0] - prevcoord[0]) < larger && abs(thiscoord[1] - prevcoord[1]) < larger && abs(thiscoord[2] - prevcoord[2]) < larger) { is_smaller = 1; } else if (smallidx > minidx) { is_smaller = -1; } else { is_smaller = 0; } if (i + 1 < *size) { if (abs(thiscoord[0] - thiscoord[3]) < small && abs(thiscoord[1] - thiscoord[4]) < small && abs(thiscoord[2] - thiscoord[5]) < small) { /* interchange first with second atom for better * compression of water molecules */ tmp = thiscoord[0]; thiscoord[0] = thiscoord[3]; thiscoord[3] = tmp; tmp = thiscoord[1]; thiscoord[1] = thiscoord[4]; thiscoord[4] = tmp; tmp = thiscoord[2]; thiscoord[2] = thiscoord[5]; thiscoord[5] = tmp; is_small = 1; } } tmpcoord[0] = thiscoord[0] - minint[0]; tmpcoord[1] = thiscoord[1] - minint[1]; tmpcoord[2] = thiscoord[2] - minint[2]; if (bitsize == 0) { sendbits(buf, bitsizeint[0], tmpcoord[0]); sendbits(buf, bitsizeint[1], tmpcoord[1]); sendbits(buf, bitsizeint[2], tmpcoord[2]); } else { sendints(buf, 3, bitsize, sizeint, tmpcoord); } prevcoord[0] = thiscoord[0]; prevcoord[1] = thiscoord[1]; prevcoord[2] = thiscoord[2]; thiscoord = thiscoord + 3; i++; run = 0; if (is_small == 0 && is_smaller == -1) is_smaller = 0; while (is_small && run < 8*3) { if (is_smaller == -1 && (SQR(thiscoord[0] - prevcoord[0]) + SQR(thiscoord[1] - prevcoord[1]) + SQR(thiscoord[2] - prevcoord[2]) >= smaller * smaller)) { is_smaller = 0; } tmpcoord[run++] = thiscoord[0] - prevcoord[0] + small; tmpcoord[run++] = thiscoord[1] - prevcoord[1] + small; tmpcoord[run++] = thiscoord[2] - prevcoord[2] + small; prevcoord[0] = thiscoord[0]; prevcoord[1] = thiscoord[1]; prevcoord[2] = thiscoord[2]; i++; thiscoord = thiscoord + 3; is_small = 0; if (i < *size && abs(thiscoord[0] - prevcoord[0]) < small && abs(thiscoord[1] - prevcoord[1]) < small && abs(thiscoord[2] - prevcoord[2]) < small) { is_small = 1; } } if (run != prevrun || is_smaller != 0) { prevrun = run; sendbits(buf, 1, 1); /* flag the change in run-length */ sendbits(buf, 5, run+is_smaller+1); } else { sendbits(buf, 1, 0); /* flag the fact that runlength did not change */ } for (k=0; k < run; k+=3) { sendints(buf, 3, smallidx, sizesmall, &tmpcoord[k]); } if (is_smaller != 0) { smallidx += is_smaller; if (is_smaller < 0) { small = smaller; smaller = magicints[smallidx-1] / 2; } else { smaller = small; small = magicints[smallidx] / 2; } sizesmall[0] = sizesmall[1] = sizesmall[2] = magicints[smallidx]; } } if (buf[1] != 0) buf[0]++;; xdr_int(xdrs, &(buf[0])); /* buf[0] holds the length in bytes */ return errval * (xdr_opaque(xdrs, (caddr_t)&(buf[3]), (u_int)buf[0])); } else { /* xdrs is open for reading */ if (xdr_int(xdrs, &lsize) == 0) return 0; if (*size != 0 && lsize != *size) { fprintf(stderr, "wrong number of coordinates in xdr3dfcoor; " "%d arg vs %d in file", *size, lsize); } *size = lsize; size3 = *size * 3; if (*size <= 9) { return (xdr_vector(xdrs, (char *) fp, size3, sizeof(*fp), (xdrproc_t)xdr_float)); } xdr_float(xdrs, precision); if (ip == NULL) { ip = (int *) malloc(size3 * sizeof(*ip)); if (ip == NULL) { fprintf(stderr,"malloc failed\n"); exit(1); } bufsize = (int) (size3 * 1.2); buf = (int *) malloc(bufsize * sizeof(*buf)); if (buf == NULL) { fprintf(stderr,"malloc failed\n"); exit(1); } oldsize = *size; } else if (*size > oldsize) { ip = (int *)realloc(ip, size3 * sizeof(*ip)); if (ip == NULL) { fprintf(stderr,"malloc failed\n"); exit(1); } bufsize = (int) (size3 * 1.2); buf = (int *)realloc(buf, bufsize * sizeof(*buf)); if (buf == NULL) { fprintf(stderr,"malloc failed\n"); exit(1); } oldsize = *size; } buf[0] = buf[1] = buf[2] = 0; xdr_int(xdrs, &(minint[0])); xdr_int(xdrs, &(minint[1])); xdr_int(xdrs, &(minint[2])); xdr_int(xdrs, &(maxint[0])); xdr_int(xdrs, &(maxint[1])); xdr_int(xdrs, &(maxint[2])); sizeint[0] = maxint[0] - minint[0]+1; sizeint[1] = maxint[1] - minint[1]+1; sizeint[2] = maxint[2] - minint[2]+1; /* check if one of the sizes is to big to be multiplied */ if ((sizeint[0] | sizeint[1] | sizeint[2] ) > 0xffffff) { bitsizeint[0] = sizeofint(sizeint[0]); bitsizeint[1] = sizeofint(sizeint[1]); bitsizeint[2] = sizeofint(sizeint[2]); bitsize = 0; /* flag the use of large sizes */ } else { bitsize = sizeofints(3, sizeint); } xdr_int(xdrs, &smallidx); maxidx = MYMIN(LASTIDX, smallidx + 8) ; minidx = maxidx - 8; /* often this equal smallidx */ smaller = magicints[MYMAX(FIRSTIDX, smallidx-1)] / 2; small = magicints[smallidx] / 2; sizesmall[0] = sizesmall[1] = sizesmall[2] = magicints[smallidx] ; larger = magicints[maxidx]; /* buf[0] holds the length in bytes */ if (xdr_int(xdrs, &(buf[0])) == 0) return 0; if (xdr_opaque(xdrs, (caddr_t)&(buf[3]), (u_int)buf[0]) == 0) return 0; buf[0] = buf[1] = buf[2] = 0; lfp = fp; inv_precision = 1.0 / * precision; run = 0; i = 0; lip = ip; while ( i < lsize ) { thiscoord = (int *)(lip) + i * 3; if (bitsize == 0) { thiscoord[0] = receivebits(buf, bitsizeint[0]); thiscoord[1] = receivebits(buf, bitsizeint[1]); thiscoord[2] = receivebits(buf, bitsizeint[2]); } else { receiveints(buf, 3, bitsize, sizeint, thiscoord); } i++; thiscoord[0] += minint[0]; thiscoord[1] += minint[1]; thiscoord[2] += minint[2]; prevcoord[0] = thiscoord[0]; prevcoord[1] = thiscoord[1]; prevcoord[2] = thiscoord[2]; flag = receivebits(buf, 1); is_smaller = 0; if (flag == 1) { run = receivebits(buf, 5); is_smaller = run % 3; run -= is_smaller; is_smaller--; } if (run > 0) { thiscoord += 3; for (k = 0; k < run; k+=3) { receiveints(buf, 3, smallidx, sizesmall, thiscoord); i++; thiscoord[0] += prevcoord[0] - small; thiscoord[1] += prevcoord[1] - small; thiscoord[2] += prevcoord[2] - small; if (k == 0) { /* interchange first with second atom for better * compression of water molecules */ tmp = thiscoord[0]; thiscoord[0] = prevcoord[0]; prevcoord[0] = tmp; tmp = thiscoord[1]; thiscoord[1] = prevcoord[1]; prevcoord[1] = tmp; tmp = thiscoord[2]; thiscoord[2] = prevcoord[2]; prevcoord[2] = tmp; *lfp++ = prevcoord[0] * inv_precision; *lfp++ = prevcoord[1] * inv_precision; *lfp++ = prevcoord[2] * inv_precision; } else { prevcoord[0] = thiscoord[0]; prevcoord[1] = thiscoord[1]; prevcoord[2] = thiscoord[2]; } *lfp++ = thiscoord[0] * inv_precision; *lfp++ = thiscoord[1] * inv_precision; *lfp++ = thiscoord[2] * inv_precision; } } else { *lfp++ = thiscoord[0] * inv_precision; *lfp++ = thiscoord[1] * inv_precision; *lfp++ = thiscoord[2] * inv_precision; } smallidx += is_smaller; if (is_smaller < 0) { small = smaller; if (smallidx > FIRSTIDX) { smaller = magicints[smallidx - 1] /2; } else { smaller = 0; } } else if (is_smaller > 0) { smaller = small; small = magicints[smallidx] / 2; } sizesmall[0] = sizesmall[1] = sizesmall[2] = magicints[smallidx] ; } } return 1; } diff --git a/src/XTC/dump_xtc.h b/src/XTC/dump_xtc.h index ebc928cc1..e1e2ca025 100644 --- a/src/XTC/dump_xtc.h +++ b/src/XTC/dump_xtc.h @@ -1,63 +1,63 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ #ifdef DUMP_CLASS DumpStyle(xtc,DumpXTC) #else #ifndef LMP_DUMP_XTC_H #define LMP_DUMP_XTC_H #include "dump.h" #ifdef LAMMPS_XDR #include "xdr_compat.h" #else #include "rpc/rpc.h" #include "rpc/xdr.h" #endif namespace LAMMPS_NS { class DumpXTC : public Dump { public: DumpXTC(class LAMMPS *, int, char**); ~DumpXTC(); private: int natoms,ntotal; int nevery_save; int unwrap_flag; // 1 if atom coords are unwrapped, 0 if no float precision; // user-adjustable precision setting float *coords; double sfactor; XDR xd; void init_style(); int modify_param(int, char **); void openfile(); - void write_header(int); + void write_header(bigint); int count(); void pack(int *); void write_data(int, double *); double memory_usage(); void write_frame(); }; } #endif #endif diff --git a/src/atom.h b/src/atom.h index 0cb05c7eb..563bc9b1c 100644 --- a/src/atom.h +++ b/src/atom.h @@ -1,223 +1,223 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ #ifndef LMP_ATOM_H #define LMP_ATOM_H #include "pointers.h" #include "lmptype.h" namespace LAMMPS_NS { class Atom : protected Pointers { public: char *atom_style; class AtomVec *avec; // atom counts bigint natoms; // total # of atoms in system, could be 0 int nlocal,nghost; // # of owned and ghost atoms on this proc int nmax; // max # of owned+ghost in arrays on this proc int tag_enable; // 0/1 if atom ID tags are defined int molecular; // 0 = atomic, 1 = molecular system bigint nbonds,nangles,ndihedrals,nimpropers; int ntypes,nbondtypes,nangletypes,ndihedraltypes,nimpropertypes; int bond_per_atom,angle_per_atom,dihedral_per_atom,improper_per_atom; int extra_bond_per_atom; int firstgroup; // store atoms in this group first, -1 if unset int nfirst; // # of atoms in first group on this proc char *firstgroupname; // group-ID to store first, NULL if unset // per-atom arrays // customize by adding new array int *tag,*type,*mask,*image; double **x,**v,**f; int *molecule; double *q,**mu; double **quat,**omega,**angmom,**torque; double *radius,*density,*rmass,*vfrac,*s0; double **x0; int *spin; double *eradius,*ervel,*erforce; int **nspecial; // 0,1,2 = cummulative # of 1-2,1-3,1-4 neighs int **special; // IDs of 1-2,1-3,1-4 neighs of each atom int maxspecial; // special[nlocal][maxspecial] int *num_bond; int **bond_type; int **bond_atom; int *num_angle; int **angle_type; int **angle_atom1,**angle_atom2,**angle_atom3; int *num_dihedral; int **dihedral_type; int **dihedral_atom1,**dihedral_atom2,**dihedral_atom3,**dihedral_atom4; int *num_improper; int **improper_type; int **improper_atom1,**improper_atom2,**improper_atom3,**improper_atom4; // per-atom array existence flags // these can be checked before array is allocated // customize by adding new flag int molecule_flag; int q_flag,mu_flag; int quat_flag,omega_flag,angmom_flag,torque_flag; int radius_flag,density_flag,rmass_flag,vfrac_flag; int spin_flag,eradius_flag,ervel_flag,erforce_flag; // extra peratom info in restart file destined for fix & diag double **extra; // per-type arrays double *mass,**shape,*dipole; int *mass_setflag,*shape_setflag,*dipole_setflag; // callback ptrs for atom arrays managed by fix classes int nextra_grow,nextra_restart; // # of callbacks of each type int *extra_grow,*extra_restart; // index of fix to callback to int nextra_grow_max,nextra_restart_max; // size of callback lists int nextra_store; int map_style; // default or user-specified style of map // 0 = none, 1 = array, 2 = hash // spatial sorting of atoms int sortfreq; // sort atoms every this many steps, 0 = off - int nextsort; // next timestep to sort on + bigint nextsort; // next timestep to sort on // functions Atom(class LAMMPS *); ~Atom(); void settings(class Atom *); void create_avec(const char *, int, char **); class AtomVec *new_avec(const char *, int, char **); void init(); void setup(); int style_match(const char *); void modify_params(int, char **); void tag_extend(); int tag_consecutive(); int parse_data(const char *); int count_words(const char *); void data_atoms(int, char *); void data_vels(int, char *); void data_bonds(int, char *); void data_angles(int, char *); void data_dihedrals(int, char *); void data_impropers(int, char *); void allocate_type_arrays(); void set_mass(const char *); void set_mass(int, double); void set_mass(int, char **); void set_mass(double *); void check_mass(); void set_shape(const char *); void set_shape(int, char **); void set_shape(double **); void check_shape(); void set_dipole(const char *); void set_dipole(int, char **); void set_dipole(double *); void check_dipole(); void first_reorder(); void sort(); void add_callback(int); void delete_callback(const char *, int); void update_callback(int); void *extract(char *); double memory_usage(); int memcheck(const char *); // functions for global to local ID mapping // map lookup function inlined for efficiency inline int map(int global) { if (map_style == 1) return map_array[global]; else return map_find_hash(global); }; void map_init(); void map_clear(); void map_set(); void map_one(int, int); void map_delete(); int map_find_hash(int); private: // global to local ID mapping int map_tag_max; int *map_array; struct HashElem { int global; // key to search on = global ID int local; // value associated with key = local index int next; // next entry in this bucket, -1 if last }; int map_nhash; // # of entries hash table can hold int map_nused; // # of actual entries in hash table int map_free; // ptr to 1st unused entry in hash table int map_nbucket; // # of hash buckets int *map_bucket; // ptr to 1st entry in each bucket HashElem *map_hash; // hash table int *primes; // table of prime #s for hashing int nprimes; // # of primes // spatial sorting of atoms int nbins; // # of sorting bins int nbinx,nbiny,nbinz; // bins in each dimension int maxbin; // max # of bins int maxnext; // max size of next,permute int *binhead; // 1st atom in each bin int *next; // next atom in bin int *permute; // permutation vector double userbinsize; // requested sort bin size double bininvx,bininvy,bininvz; // inverse actual bin sizes double bboxlo[3],bboxhi[3]; // bounding box of my sub-domain int memlength; // allocated size of memstr char *memstr; // string of array names already counted void setup_sort_bins(); }; } #endif diff --git a/src/atom_vec_atomic.cpp b/src/atom_vec_atomic.cpp index 665f66f04..13dd6b4a9 100644 --- a/src/atom_vec_atomic.cpp +++ b/src/atom_vec_atomic.cpp @@ -1,591 +1,594 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ #include "stdlib.h" #include "atom_vec_atomic.h" +#include "lmptype.h" #include "atom.h" #include "domain.h" #include "modify.h" #include "fix.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; #define DELTA 10000 /* ---------------------------------------------------------------------- */ AtomVecAtomic::AtomVecAtomic(LAMMPS *lmp, int narg, char **arg) : AtomVec(lmp, narg, arg) { molecular = 0; mass_type = 1; comm_x_only = comm_f_only = 1; size_forward = 3; size_reverse = 3; size_border = 6; size_velocity = 3; size_data_atom = 5; size_data_vel = 4; xcol_data = 3; } /* ---------------------------------------------------------------------- grow atom arrays n = 0 grows arrays by DELTA n > 0 allocates arrays to size n ------------------------------------------------------------------------- */ void AtomVecAtomic::grow(int n) { if (n == 0) nmax += DELTA; else nmax = n; atom->nmax = nmax; + if (nmax < 0 || nmax > MAXSMALLINT) + error->one("Per-processor system is too big"); tag = atom->tag = (int *) memory->srealloc(atom->tag,nmax*sizeof(int),"atom:tag"); type = atom->type = (int *) memory->srealloc(atom->type,nmax*sizeof(int),"atom:type"); mask = atom->mask = (int *) memory->srealloc(atom->mask,nmax*sizeof(int),"atom:mask"); image = atom->image = (int *) memory->srealloc(atom->image,nmax*sizeof(int),"atom:image"); x = atom->x = memory->grow_2d_double_array(atom->x,nmax,3,"atom:x"); v = atom->v = memory->grow_2d_double_array(atom->v,nmax,3,"atom:v"); f = atom->f = memory->grow_2d_double_array(atom->f,nmax,3,"atom:f"); if (atom->nextra_grow) for (int iextra = 0; iextra < atom->nextra_grow; iextra++) modify->fix[atom->extra_grow[iextra]]->grow_arrays(nmax); } /* ---------------------------------------------------------------------- reset local array ptrs ------------------------------------------------------------------------- */ void AtomVecAtomic::grow_reset() { tag = atom->tag; type = atom->type; mask = atom->mask; image = atom->image; x = atom->x; v = atom->v; f = atom->f; } /* ---------------------------------------------------------------------- */ void AtomVecAtomic::copy(int i, int j) { tag[j] = tag[i]; type[j] = type[i]; mask[j] = mask[i]; image[j] = image[i]; x[j][0] = x[i][0]; x[j][1] = x[i][1]; x[j][2] = x[i][2]; v[j][0] = v[i][0]; v[j][1] = v[i][1]; v[j][2] = v[i][2]; if (atom->nextra_grow) for (int iextra = 0; iextra < atom->nextra_grow; iextra++) modify->fix[atom->extra_grow[iextra]]->copy_arrays(i,j); } /* ---------------------------------------------------------------------- */ int AtomVecAtomic::pack_comm(int n, int *list, double *buf, int pbc_flag, int *pbc) { int i,j,m; double dx,dy,dz; m = 0; if (pbc_flag == 0) { for (i = 0; i < n; i++) { j = list[i]; buf[m++] = x[j][0]; buf[m++] = x[j][1]; buf[m++] = x[j][2]; } } else { if (domain->triclinic == 0) { dx = pbc[0]*domain->xprd; dy = pbc[1]*domain->yprd; dz = pbc[2]*domain->zprd; } else { dx = pbc[0]*domain->xprd + pbc[5]*domain->xy + pbc[4]*domain->xz; dy = pbc[1]*domain->yprd + pbc[3]*domain->yz; dz = pbc[2]*domain->zprd; } for (i = 0; i < n; i++) { j = list[i]; buf[m++] = x[j][0] + dx; buf[m++] = x[j][1] + dy; buf[m++] = x[j][2] + dz; } } return m; } /* ---------------------------------------------------------------------- */ int AtomVecAtomic::pack_comm_vel(int n, int *list, double *buf, int pbc_flag, int *pbc) { int i,j,m; double dx,dy,dz; m = 0; if (pbc_flag == 0) { for (i = 0; i < n; i++) { j = list[i]; buf[m++] = x[j][0]; buf[m++] = x[j][1]; buf[m++] = x[j][2]; buf[m++] = v[j][0]; buf[m++] = v[j][1]; buf[m++] = v[j][2]; } } else { if (domain->triclinic == 0) { dx = pbc[0]*domain->xprd; dy = pbc[1]*domain->yprd; dz = pbc[2]*domain->zprd; } else { dx = pbc[0]*domain->xprd + pbc[5]*domain->xy + pbc[4]*domain->xz; dy = pbc[1]*domain->yprd + pbc[3]*domain->yz; dz = pbc[2]*domain->zprd; } 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]; } } return m; } /* ---------------------------------------------------------------------- */ void AtomVecAtomic::unpack_comm(int n, int first, double *buf) { int i,m,last; m = 0; last = first + n; for (i = first; i < last; i++) { x[i][0] = buf[m++]; x[i][1] = buf[m++]; x[i][2] = buf[m++]; } } /* ---------------------------------------------------------------------- */ void AtomVecAtomic::unpack_comm_vel(int n, int first, double *buf) { int i,m,last; m = 0; last = first + n; for (i = first; i < last; i++) { x[i][0] = buf[m++]; x[i][1] = buf[m++]; x[i][2] = buf[m++]; v[i][0] = buf[m++]; v[i][1] = buf[m++]; v[i][2] = buf[m++]; } } /* ---------------------------------------------------------------------- */ int AtomVecAtomic::pack_reverse(int n, int first, double *buf) { int i,m,last; m = 0; last = first + n; for (i = first; i < last; i++) { buf[m++] = f[i][0]; buf[m++] = f[i][1]; buf[m++] = f[i][2]; } return m; } /* ---------------------------------------------------------------------- */ void AtomVecAtomic::unpack_reverse(int n, int *list, double *buf) { int i,j,m; m = 0; for (i = 0; i < n; i++) { j = list[i]; f[j][0] += buf[m++]; f[j][1] += buf[m++]; f[j][2] += buf[m++]; } } /* ---------------------------------------------------------------------- */ int AtomVecAtomic::pack_border(int n, int *list, double *buf, int pbc_flag, int *pbc) { int i,j,m; double dx,dy,dz; m = 0; if (pbc_flag == 0) { for (i = 0; i < n; i++) { j = list[i]; buf[m++] = x[j][0]; buf[m++] = x[j][1]; buf[m++] = x[j][2]; buf[m++] = tag[j]; buf[m++] = type[j]; buf[m++] = mask[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]; } } return m; } /* ---------------------------------------------------------------------- */ int AtomVecAtomic::pack_border_vel(int n, int *list, double *buf, int pbc_flag, int *pbc) { int i,j,m; double dx,dy,dz; 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++] = v[j][0]; buf[m++] = v[j][1]; buf[m++] = v[j][2]; } } else { if (domain->triclinic == 0) { dx = pbc[0]*domain->xprd; dy = pbc[1]*domain->yprd; dz = pbc[2]*domain->zprd; } else { dx = pbc[0]; dy = pbc[1]; dz = pbc[2]; } 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++] = v[j][0]; buf[m++] = v[j][1]; buf[m++] = v[j][2]; } } return m; } /* ---------------------------------------------------------------------- */ void AtomVecAtomic::unpack_border(int n, int first, double *buf) { int i,m,last; m = 0; last = first + n; for (i = first; i < last; i++) { if (i == nmax) grow(0); x[i][0] = buf[m++]; x[i][1] = buf[m++]; x[i][2] = buf[m++]; tag[i] = static_cast<int> (buf[m++]); type[i] = static_cast<int> (buf[m++]); mask[i] = static_cast<int> (buf[m++]); } } /* ---------------------------------------------------------------------- */ void AtomVecAtomic::unpack_border_vel(int n, int first, double *buf) { int i,m,last; m = 0; last = first + n; for (i = first; i < last; i++) { if (i == nmax) grow(0); x[i][0] = buf[m++]; x[i][1] = buf[m++]; x[i][2] = buf[m++]; tag[i] = static_cast<int> (buf[m++]); type[i] = static_cast<int> (buf[m++]); mask[i] = static_cast<int> (buf[m++]); v[i][0] = buf[m++]; v[i][1] = buf[m++]; v[i][2] = buf[m++]; } } /* ---------------------------------------------------------------------- pack data for atom I for sending to another proc xyz must be 1st 3 values, so comm::exchange() can test on them ------------------------------------------------------------------------- */ int AtomVecAtomic::pack_exchange(int i, double *buf) { int m = 1; buf[m++] = x[i][0]; buf[m++] = x[i][1]; buf[m++] = x[i][2]; buf[m++] = v[i][0]; buf[m++] = v[i][1]; buf[m++] = v[i][2]; buf[m++] = tag[i]; buf[m++] = type[i]; buf[m++] = mask[i]; buf[m++] = image[i]; if (atom->nextra_grow) for (int iextra = 0; iextra < atom->nextra_grow; iextra++) m += modify->fix[atom->extra_grow[iextra]]->pack_exchange(i,&buf[m]); buf[0] = m; return m; } /* ---------------------------------------------------------------------- */ int AtomVecAtomic::unpack_exchange(double *buf) { int nlocal = atom->nlocal; if (nlocal == nmax) grow(0); int m = 1; x[nlocal][0] = buf[m++]; x[nlocal][1] = buf[m++]; x[nlocal][2] = buf[m++]; v[nlocal][0] = buf[m++]; v[nlocal][1] = buf[m++]; v[nlocal][2] = buf[m++]; tag[nlocal] = static_cast<int> (buf[m++]); type[nlocal] = static_cast<int> (buf[m++]); mask[nlocal] = static_cast<int> (buf[m++]); image[nlocal] = static_cast<int> (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 AtomVecAtomic::size_restart() { int i; int nlocal = atom->nlocal; int n = 11 * nlocal; if (atom->nextra_restart) for (int iextra = 0; iextra < atom->nextra_restart; iextra++) for (i = 0; i < nlocal; i++) n += modify->fix[atom->extra_restart[iextra]]->size_restart(i); return n; } /* ---------------------------------------------------------------------- pack atom I's data for restart file including extra quantities xyz must be 1st 3 values, so that read_restart can test on them molecular types may be negative, but write as positive ------------------------------------------------------------------------- */ int AtomVecAtomic::pack_restart(int i, double *buf) { int m = 1; buf[m++] = x[i][0]; buf[m++] = x[i][1]; buf[m++] = x[i][2]; buf[m++] = tag[i]; buf[m++] = type[i]; buf[m++] = mask[i]; buf[m++] = image[i]; buf[m++] = v[i][0]; buf[m++] = v[i][1]; buf[m++] = v[i][2]; if (atom->nextra_restart) for (int iextra = 0; iextra < atom->nextra_restart; iextra++) m += modify->fix[atom->extra_restart[iextra]]->pack_restart(i,&buf[m]); buf[0] = m; return m; } /* ---------------------------------------------------------------------- unpack data for one atom from restart file including extra quantities ------------------------------------------------------------------------- */ int AtomVecAtomic::unpack_restart(double *buf) { int nlocal = atom->nlocal; if (nlocal == nmax) { grow(0); if (atom->nextra_store) atom->extra = memory->grow_2d_double_array(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] = static_cast<int> (buf[m++]); v[nlocal][0] = buf[m++]; v[nlocal][1] = buf[m++]; v[nlocal][2] = buf[m++]; double **extra = atom->extra; if (atom->nextra_store) { int size = static_cast<int> (buf[0]) - m; for (int i = 0; i < size; i++) extra[nlocal][i] = buf[m++]; } atom->nlocal++; return m; } /* ---------------------------------------------------------------------- create one atom of itype at coord set other values to defaults ------------------------------------------------------------------------- */ void AtomVecAtomic::create_atom(int itype, double *coord) { int nlocal = atom->nlocal; if (nlocal == nmax) grow(0); tag[nlocal] = 0; type[nlocal] = itype; x[nlocal][0] = coord[0]; x[nlocal][1] = coord[1]; x[nlocal][2] = coord[2]; mask[nlocal] = 1; image[nlocal] = (512 << 20) | (512 << 10) | 512; v[nlocal][0] = 0.0; v[nlocal][1] = 0.0; v[nlocal][2] = 0.0; atom->nlocal++; } /* ---------------------------------------------------------------------- unpack one line from Atoms section of data file initialize other atom quantities ------------------------------------------------------------------------- */ void AtomVecAtomic::data_atom(double *coord, int imagetmp, char **values) { int nlocal = atom->nlocal; if (nlocal == nmax) grow(0); tag[nlocal] = atoi(values[0]); if (tag[nlocal] <= 0) error->one("Invalid atom ID in Atoms section of data file"); type[nlocal] = atoi(values[1]); if (type[nlocal] <= 0 || type[nlocal] > atom->ntypes) error->one("Invalid atom type in Atoms section of data file"); x[nlocal][0] = coord[0]; x[nlocal][1] = coord[1]; x[nlocal][2] = coord[2]; image[nlocal] = imagetmp; mask[nlocal] = 1; v[nlocal][0] = 0.0; v[nlocal][1] = 0.0; v[nlocal][2] = 0.0; atom->nlocal++; } /* ---------------------------------------------------------------------- return # of bytes of allocated memory ------------------------------------------------------------------------- */ double AtomVecAtomic::memory_usage() { double bytes = 0.0; if (atom->memcheck("tag")) bytes += nmax * sizeof(int); if (atom->memcheck("type")) bytes += nmax * sizeof(int); if (atom->memcheck("mask")) bytes += nmax * sizeof(int); if (atom->memcheck("image")) bytes += nmax * sizeof(int); if (atom->memcheck("x")) bytes += nmax*3 * sizeof(double); if (atom->memcheck("v")) bytes += nmax*3 * sizeof(double); if (atom->memcheck("f")) bytes += nmax*3 * sizeof(double); return bytes; } diff --git a/src/atom_vec_charge.cpp b/src/atom_vec_charge.cpp index 76b69b4bd..69a918562 100644 --- a/src/atom_vec_charge.cpp +++ b/src/atom_vec_charge.cpp @@ -1,647 +1,650 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ #include "stdlib.h" #include "atom_vec_charge.h" +#include "lmptype.h" #include "atom.h" #include "domain.h" #include "modify.h" #include "fix.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; #define DELTA 10000 /* ---------------------------------------------------------------------- */ AtomVecCharge::AtomVecCharge(LAMMPS *lmp, int narg, char **arg) : AtomVec(lmp, narg, arg) { molecular = 0; mass_type = 1; comm_x_only = comm_f_only = 1; size_forward = 3; size_reverse = 3; size_border = 7; size_velocity = 3; size_data_atom = 6; size_data_vel = 4; xcol_data = 4; atom->q_flag = 1; } /* ---------------------------------------------------------------------- grow atom arrays n = 0 grows arrays by DELTA n > 0 allocates arrays to size n ------------------------------------------------------------------------- */ void AtomVecCharge::grow(int n) { if (n == 0) nmax += DELTA; else nmax = n; atom->nmax = nmax; + if (nmax < 0 || nmax > MAXSMALLINT) + error->one("Per-processor system is too big"); tag = atom->tag = (int *) memory->srealloc(atom->tag,nmax*sizeof(int),"atom:tag"); type = atom->type = (int *) memory->srealloc(atom->type,nmax*sizeof(int),"atom:type"); mask = atom->mask = (int *) memory->srealloc(atom->mask,nmax*sizeof(int),"atom:mask"); image = atom->image = (int *) memory->srealloc(atom->image,nmax*sizeof(int),"atom:image"); x = atom->x = memory->grow_2d_double_array(atom->x,nmax,3,"atom:x"); v = atom->v = memory->grow_2d_double_array(atom->v,nmax,3,"atom:v"); f = atom->f = memory->grow_2d_double_array(atom->f,nmax,3,"atom:f"); q = atom->q = (double *) memory->srealloc(atom->q,nmax*sizeof(double),"atom:q"); if (atom->nextra_grow) for (int iextra = 0; iextra < atom->nextra_grow; iextra++) modify->fix[atom->extra_grow[iextra]]->grow_arrays(nmax); } /* ---------------------------------------------------------------------- reset local array ptrs ------------------------------------------------------------------------- */ void AtomVecCharge::grow_reset() { tag = atom->tag; type = atom->type; mask = atom->mask; image = atom->image; x = atom->x; v = atom->v; f = atom->f; q = atom->q; } /* ---------------------------------------------------------------------- */ void AtomVecCharge::copy(int i, int j) { tag[j] = tag[i]; type[j] = type[i]; mask[j] = mask[i]; image[j] = image[i]; x[j][0] = x[i][0]; x[j][1] = x[i][1]; x[j][2] = x[i][2]; v[j][0] = v[i][0]; v[j][1] = v[i][1]; v[j][2] = v[i][2]; q[j] = q[i]; if (atom->nextra_grow) for (int iextra = 0; iextra < atom->nextra_grow; iextra++) modify->fix[atom->extra_grow[iextra]]->copy_arrays(i,j); } /* ---------------------------------------------------------------------- */ int AtomVecCharge::pack_comm(int n, int *list, double *buf, int pbc_flag, int *pbc) { int i,j,m; double dx,dy,dz; m = 0; if (pbc_flag == 0) { for (i = 0; i < n; i++) { j = list[i]; buf[m++] = x[j][0]; buf[m++] = x[j][1]; buf[m++] = x[j][2]; } } else { if (domain->triclinic == 0) { dx = pbc[0]*domain->xprd; dy = pbc[1]*domain->yprd; dz = pbc[2]*domain->zprd; } else { dx = pbc[0]*domain->xprd + pbc[5]*domain->xy + pbc[4]*domain->xz; dy = pbc[1]*domain->yprd + pbc[3]*domain->yz; dz = pbc[2]*domain->zprd; } for (i = 0; i < n; i++) { j = list[i]; buf[m++] = x[j][0] + dx; buf[m++] = x[j][1] + dy; buf[m++] = x[j][2] + dz; } } return m; } /* ---------------------------------------------------------------------- */ int AtomVecCharge::pack_comm_vel(int n, int *list, double *buf, int pbc_flag, int *pbc) { int i,j,m; double dx,dy,dz; m = 0; if (pbc_flag == 0) { for (i = 0; i < n; i++) { j = list[i]; buf[m++] = x[j][0]; buf[m++] = x[j][1]; buf[m++] = x[j][2]; buf[m++] = v[j][0]; buf[m++] = v[j][1]; buf[m++] = v[j][2]; } } else { if (domain->triclinic == 0) { dx = pbc[0]*domain->xprd; dy = pbc[1]*domain->yprd; dz = pbc[2]*domain->zprd; } else { dx = pbc[0]*domain->xprd + pbc[5]*domain->xy + pbc[4]*domain->xz; dy = pbc[1]*domain->yprd + pbc[3]*domain->yz; dz = pbc[2]*domain->zprd; } 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]; } } return m; } /* ---------------------------------------------------------------------- */ void AtomVecCharge::unpack_comm(int n, int first, double *buf) { int i,m,last; m = 0; last = first + n; for (i = first; i < last; i++) { x[i][0] = buf[m++]; x[i][1] = buf[m++]; x[i][2] = buf[m++]; } } /* ---------------------------------------------------------------------- */ void AtomVecCharge::unpack_comm_vel(int n, int first, double *buf) { int i,m,last; m = 0; last = first + n; for (i = first; i < last; i++) { x[i][0] = buf[m++]; x[i][1] = buf[m++]; x[i][2] = buf[m++]; v[i][0] = buf[m++]; v[i][1] = buf[m++]; v[i][2] = buf[m++]; } } /* ---------------------------------------------------------------------- */ int AtomVecCharge::pack_reverse(int n, int first, double *buf) { int i,m,last; m = 0; last = first + n; for (i = first; i < last; i++) { buf[m++] = f[i][0]; buf[m++] = f[i][1]; buf[m++] = f[i][2]; } return m; } /* ---------------------------------------------------------------------- */ void AtomVecCharge::unpack_reverse(int n, int *list, double *buf) { int i,j,m; m = 0; for (i = 0; i < n; i++) { j = list[i]; f[j][0] += buf[m++]; f[j][1] += buf[m++]; f[j][2] += buf[m++]; } } /* ---------------------------------------------------------------------- */ int AtomVecCharge::pack_border(int n, int *list, double *buf, int pbc_flag, int *pbc) { int i,j,m; double dx,dy,dz; m = 0; if (pbc_flag == 0) { for (i = 0; i < n; i++) { j = list[i]; buf[m++] = x[j][0]; buf[m++] = x[j][1]; buf[m++] = x[j][2]; buf[m++] = tag[j]; buf[m++] = type[j]; buf[m++] = mask[j]; buf[m++] = q[j]; } } else { if (domain->triclinic == 0) { dx = pbc[0]*domain->xprd; dy = pbc[1]*domain->yprd; dz = pbc[2]*domain->zprd; } else { dx = pbc[0]; dy = pbc[1]; dz = pbc[2]; } for (i = 0; i < n; i++) { j = list[i]; buf[m++] = x[j][0] + dx; buf[m++] = x[j][1] + dy; buf[m++] = x[j][2] + dz; buf[m++] = tag[j]; buf[m++] = type[j]; buf[m++] = mask[j]; buf[m++] = q[j]; } } return m; } /* ---------------------------------------------------------------------- */ int AtomVecCharge::pack_border_vel(int n, int *list, double *buf, int pbc_flag, int *pbc) { int i,j,m; double dx,dy,dz; 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++] = q[j]; buf[m++] = v[j][0]; buf[m++] = v[j][1]; buf[m++] = v[j][2]; } } else { if (domain->triclinic == 0) { dx = pbc[0]*domain->xprd; dy = pbc[1]*domain->yprd; dz = pbc[2]*domain->zprd; } else { dx = pbc[0]; dy = pbc[1]; dz = pbc[2]; } 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++] = q[j]; buf[m++] = v[j][0]; buf[m++] = v[j][1]; buf[m++] = v[j][2]; } } return m; } /* ---------------------------------------------------------------------- */ int AtomVecCharge::pack_border_one(int i, double *buf) { buf[0] = q[i]; return 1; } /* ---------------------------------------------------------------------- */ void AtomVecCharge::unpack_border(int n, int first, double *buf) { int i,m,last; m = 0; last = first + n; for (i = first; i < last; i++) { if (i == nmax) grow(0); x[i][0] = buf[m++]; x[i][1] = buf[m++]; x[i][2] = buf[m++]; tag[i] = static_cast<int> (buf[m++]); type[i] = static_cast<int> (buf[m++]); mask[i] = static_cast<int> (buf[m++]); q[i] = buf[m++]; } } /* ---------------------------------------------------------------------- */ void AtomVecCharge::unpack_border_vel(int n, int first, double *buf) { int i,m,last; m = 0; last = first + n; for (i = first; i < last; i++) { if (i == nmax) grow(0); x[i][0] = buf[m++]; x[i][1] = buf[m++]; x[i][2] = buf[m++]; tag[i] = static_cast<int> (buf[m++]); type[i] = static_cast<int> (buf[m++]); mask[i] = static_cast<int> (buf[m++]); q[i] = buf[m++]; v[i][0] = buf[m++]; v[i][1] = buf[m++]; v[i][2] = buf[m++]; } } /* ---------------------------------------------------------------------- */ int AtomVecCharge::unpack_border_one(int i, double *buf) { q[i] = buf[0]; return 1; } /* ---------------------------------------------------------------------- pack data for atom I for sending to another proc xyz must be 1st 3 values, so comm::exchange() can test on them ------------------------------------------------------------------------- */ int AtomVecCharge::pack_exchange(int i, double *buf) { int m = 1; buf[m++] = x[i][0]; buf[m++] = x[i][1]; buf[m++] = x[i][2]; buf[m++] = v[i][0]; buf[m++] = v[i][1]; buf[m++] = v[i][2]; buf[m++] = tag[i]; buf[m++] = type[i]; buf[m++] = mask[i]; buf[m++] = image[i]; buf[m++] = q[i]; if (atom->nextra_grow) for (int iextra = 0; iextra < atom->nextra_grow; iextra++) m += modify->fix[atom->extra_grow[iextra]]->pack_exchange(i,&buf[m]); buf[0] = m; return m; } /* ---------------------------------------------------------------------- */ int AtomVecCharge::unpack_exchange(double *buf) { int nlocal = atom->nlocal; if (nlocal == nmax) grow(0); int m = 1; x[nlocal][0] = buf[m++]; x[nlocal][1] = buf[m++]; x[nlocal][2] = buf[m++]; v[nlocal][0] = buf[m++]; v[nlocal][1] = buf[m++]; v[nlocal][2] = buf[m++]; tag[nlocal] = static_cast<int> (buf[m++]); type[nlocal] = static_cast<int> (buf[m++]); mask[nlocal] = static_cast<int> (buf[m++]); image[nlocal] = static_cast<int> (buf[m++]); q[nlocal] = buf[m++]; if (atom->nextra_grow) for (int iextra = 0; iextra < atom->nextra_grow; iextra++) m += modify->fix[atom->extra_grow[iextra]]-> unpack_exchange(nlocal,&buf[m]); atom->nlocal++; return m; } /* ---------------------------------------------------------------------- size of restart data for all atoms owned by this proc include extra data stored by fixes ------------------------------------------------------------------------- */ int AtomVecCharge::size_restart() { int i; int nlocal = atom->nlocal; int n = 12 * nlocal; if (atom->nextra_restart) for (int iextra = 0; iextra < atom->nextra_restart; iextra++) for (i = 0; i < nlocal; i++) n += modify->fix[atom->extra_restart[iextra]]->size_restart(i); return n; } /* ---------------------------------------------------------------------- pack atom I's data for restart file including extra quantities xyz must be 1st 3 values, so that read_restart can test on them molecular types may be negative, but write as positive ------------------------------------------------------------------------- */ int AtomVecCharge::pack_restart(int i, double *buf) { int m = 1; buf[m++] = x[i][0]; buf[m++] = x[i][1]; buf[m++] = x[i][2]; buf[m++] = tag[i]; buf[m++] = type[i]; buf[m++] = mask[i]; buf[m++] = image[i]; buf[m++] = v[i][0]; buf[m++] = v[i][1]; buf[m++] = v[i][2]; buf[m++] = q[i]; if (atom->nextra_restart) for (int iextra = 0; iextra < atom->nextra_restart; iextra++) m += modify->fix[atom->extra_restart[iextra]]->pack_restart(i,&buf[m]); buf[0] = m; return m; } /* ---------------------------------------------------------------------- unpack data for one atom from restart file including extra quantities ------------------------------------------------------------------------- */ int AtomVecCharge::unpack_restart(double *buf) { int nlocal = atom->nlocal; if (nlocal == nmax) { grow(0); if (atom->nextra_store) atom->extra = memory->grow_2d_double_array(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] = static_cast<int> (buf[m++]); v[nlocal][0] = buf[m++]; v[nlocal][1] = buf[m++]; v[nlocal][2] = buf[m++]; q[nlocal] = buf[m++]; double **extra = atom->extra; if (atom->nextra_store) { int size = static_cast<int> (buf[0]) - m; for (int i = 0; i < size; i++) extra[nlocal][i] = buf[m++]; } atom->nlocal++; return m; } /* ---------------------------------------------------------------------- create one atom of itype at coord set other values to defaults ------------------------------------------------------------------------- */ void AtomVecCharge::create_atom(int itype, double *coord) { int nlocal = atom->nlocal; if (nlocal == nmax) grow(0); tag[nlocal] = 0; type[nlocal] = itype; x[nlocal][0] = coord[0]; x[nlocal][1] = coord[1]; x[nlocal][2] = coord[2]; mask[nlocal] = 1; image[nlocal] = (512 << 20) | (512 << 10) | 512; v[nlocal][0] = 0.0; v[nlocal][1] = 0.0; v[nlocal][2] = 0.0; q[nlocal] = 0.0; atom->nlocal++; } /* ---------------------------------------------------------------------- unpack one line from Atoms section of data file initialize other atom quantities ------------------------------------------------------------------------- */ void AtomVecCharge::data_atom(double *coord, int imagetmp, char **values) { int nlocal = atom->nlocal; if (nlocal == nmax) grow(0); tag[nlocal] = atoi(values[0]); if (tag[nlocal] <= 0) error->one("Invalid atom ID in Atoms section of data file"); type[nlocal] = atoi(values[1]); if (type[nlocal] <= 0 || type[nlocal] > atom->ntypes) error->one("Invalid atom type in Atoms section of data file"); q[nlocal] = atof(values[2]); x[nlocal][0] = coord[0]; x[nlocal][1] = coord[1]; x[nlocal][2] = coord[2]; image[nlocal] = imagetmp; mask[nlocal] = 1; v[nlocal][0] = 0.0; v[nlocal][1] = 0.0; v[nlocal][2] = 0.0; atom->nlocal++; } /* ---------------------------------------------------------------------- unpack hybrid quantities from one line in Atoms section of data file initialize other atom quantities for this sub-style ------------------------------------------------------------------------- */ int AtomVecCharge::data_atom_hybrid(int nlocal, char **values) { q[nlocal] = atof(values[0]); return 1; } /* ---------------------------------------------------------------------- return # of bytes of allocated memory ------------------------------------------------------------------------- */ double AtomVecCharge::memory_usage() { double bytes = 0.0; if (atom->memcheck("tag")) bytes += nmax * sizeof(int); if (atom->memcheck("type")) bytes += nmax * sizeof(int); if (atom->memcheck("mask")) bytes += nmax * sizeof(int); if (atom->memcheck("image")) bytes += nmax * sizeof(int); if (atom->memcheck("x")) bytes += nmax*3 * sizeof(double); if (atom->memcheck("v")) bytes += nmax*3 * sizeof(double); if (atom->memcheck("f")) bytes += nmax*3 * sizeof(double); if (atom->memcheck("q")) bytes += nmax * sizeof(double); return bytes; } diff --git a/src/atom_vec_hybrid.cpp b/src/atom_vec_hybrid.cpp index 02bc5df28..8be54a102 100644 --- a/src/atom_vec_hybrid.cpp +++ b/src/atom_vec_hybrid.cpp @@ -1,770 +1,773 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ #include "stdlib.h" #include "string.h" #include "atom_vec_hybrid.h" +#include "lmptype.h" #include "atom.h" #include "domain.h" #include "modify.h" #include "fix.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; #define MIN(A,B) ((A) < (B)) ? (A) : (B) #define MAX(A,B) ((A) > (B)) ? (A) : (B) #define DELTA 10000 /* ---------------------------------------------------------------------- */ AtomVecHybrid::AtomVecHybrid(LAMMPS *lmp, int narg, char **arg) : AtomVec(lmp, narg, arg) { int i,k; if (narg < 1) error->all("Illegal atom_style command"); // create sub-styles nstyles = narg; styles = new AtomVec*[nstyles]; keywords = new char*[nstyles]; for (i = 0; i < narg; i++) { for (k = 0; k < i; k++) if (strcmp(arg[i],keywords[k]) == 0) error->all("Atom style hybrid cannot use same atom style twice"); if (strcmp(arg[i],"hybrid") == 0) error->all("Atom style hybrid cannot have hybrid as an argument"); styles[i] = atom->new_avec(arg[i],0,NULL); keywords[i] = new char[strlen(arg[i])+1]; strcpy(keywords[i],arg[i]); } // hybrid settings are MAX or MIN of sub-style settings // hybrid sizes are minimial values plus extra values for each sub-style molecular = 0; comm_x_only = comm_f_only = 1; size_forward = 3; size_reverse = 3; size_border = 6; size_data_atom = 5; size_data_vel = 4; xcol_data = 3; for (k = 0; k < nstyles; k++) { molecular = MAX(molecular,styles[k]->molecular); bonds_allow = MAX(bonds_allow,styles[k]->bonds_allow); angles_allow = MAX(angles_allow,styles[k]->angles_allow); dihedrals_allow = MAX(dihedrals_allow,styles[k]->dihedrals_allow); impropers_allow = MAX(impropers_allow,styles[k]->impropers_allow); mass_type = MAX(mass_type,styles[k]->mass_type); shape_type = MAX(shape_type,styles[k]->shape_type); dipole_type = MAX(dipole_type,styles[k]->dipole_type); comm_x_only = MIN(comm_x_only,styles[k]->comm_x_only); comm_f_only = MIN(comm_f_only,styles[k]->comm_f_only); size_forward += styles[k]->size_forward - 3; size_reverse += styles[k]->size_reverse - 3; size_border += styles[k]->size_border - 6; size_data_atom += styles[k]->size_data_atom - 5; size_data_vel += styles[k]->size_data_vel - 4; } size_velocity = 3; if (atom->omega_flag) size_velocity += 3; if (atom->angmom_flag) size_velocity += 3; } /* ---------------------------------------------------------------------- */ AtomVecHybrid::~AtomVecHybrid() { for (int k = 0; k < nstyles; k++) delete styles[k]; delete [] styles; for (int k = 0; k < nstyles; k++) delete [] keywords[k]; delete [] keywords; } /* ---------------------------------------------------------------------- grow atom arrays n = 0 grows arrays by DELTA n > 0 allocates arrays to size n ------------------------------------------------------------------------- */ void AtomVecHybrid::grow(int n) { if (n == 0) nmax += DELTA; else nmax = n; atom->nmax = nmax; + if (nmax < 0 || nmax > MAXSMALLINT) + error->one("Per-processor system is too big"); // sub-styles perform all reallocation // turn off nextra_grow so hybrid can do that once below int tmp = atom->nextra_grow; atom->nextra_grow = 0; for (int k = 0; k < nstyles; k++) styles[k]->grow(nmax); atom->nextra_grow = tmp; // insure hybrid local ptrs and sub-style ptrs are up to date // for sub-styles, do this in case // multiple sub-style reallocs of same array occurred grow_reset(); if (atom->nextra_grow) for (int iextra = 0; iextra < atom->nextra_grow; iextra++) modify->fix[atom->extra_grow[iextra]]->grow_arrays(nmax); } /* ---------------------------------------------------------------------- reset local array ptrs ------------------------------------------------------------------------- */ void AtomVecHybrid::grow_reset() { tag = atom->tag; type = atom->type; mask = atom->mask; image = atom->image; x = atom->x; v = atom->v; f = atom->f; omega = atom->omega; angmom = atom->angmom; for (int k = 0; k < nstyles; k++) styles[k]->grow_reset(); } /* ---------------------------------------------------------------------- copy array values for all sub-styles ------------------------------------------------------------------------- */ void AtomVecHybrid::copy(int i, int j) { int tmp = atom->nextra_grow; atom->nextra_grow = 0; for (int k = 0; k < nstyles; k++) styles[k]->copy(i,j); atom->nextra_grow = tmp; if (atom->nextra_grow) for (int iextra = 0; iextra < atom->nextra_grow; iextra++) modify->fix[atom->extra_grow[iextra]]->copy_arrays(i,j); } /* ---------------------------------------------------------------------- */ int AtomVecHybrid::pack_comm(int n, int *list, double *buf, int pbc_flag, int *pbc) { int i,j,k,m; double dx,dy,dz; m = 0; if (pbc_flag == 0) { for (i = 0; i < n; i++) { j = list[i]; buf[m++] = x[j][0]; buf[m++] = x[j][1]; buf[m++] = x[j][2]; for (k = 0; k < nstyles; k++) m += styles[k]->pack_comm_one(j,&buf[m]); } } else { if (domain->triclinic == 0) { dx = pbc[0]*domain->xprd; dy = pbc[1]*domain->yprd; dz = pbc[2]*domain->zprd; } else { dx = pbc[0]*domain->xprd + pbc[5]*domain->xy + pbc[4]*domain->xz; dy = pbc[1]*domain->yprd + pbc[3]*domain->yz; dz = pbc[2]*domain->zprd; } for (i = 0; i < n; i++) { j = list[i]; buf[m++] = x[j][0] + dx; buf[m++] = x[j][1] + dy; buf[m++] = x[j][2] + dz; for (k = 0; k < nstyles; k++) m += styles[k]->pack_comm_one(j,&buf[m]); } } return m; } /* ---------------------------------------------------------------------- */ int AtomVecHybrid::pack_comm_vel(int n, int *list, double *buf, int pbc_flag, int *pbc) { int i,j,k,m; double dx,dy,dz; int omega_flag = atom->omega_flag; int angmom_flag = atom->angmom_flag; m = 0; if (pbc_flag == 0) { for (i = 0; i < n; i++) { j = list[i]; buf[m++] = x[j][0]; buf[m++] = x[j][1]; buf[m++] = x[j][2]; buf[m++] = v[j][0]; buf[m++] = v[j][1]; buf[m++] = v[j][2]; if (omega_flag) { buf[m++] = omega[j][0]; buf[m++] = omega[j][1]; buf[m++] = omega[j][2]; } if (angmom_flag) { buf[m++] = angmom[j][0]; buf[m++] = angmom[j][1]; buf[m++] = angmom[j][2]; } for (k = 0; k < nstyles; k++) m += styles[k]->pack_comm_one(j,&buf[m]); } } else { if (domain->triclinic == 0) { dx = pbc[0]*domain->xprd; dy = pbc[1]*domain->yprd; dz = pbc[2]*domain->zprd; } else { dx = pbc[0]*domain->xprd + pbc[5]*domain->xy + pbc[4]*domain->xz; dy = pbc[1]*domain->yprd + pbc[3]*domain->yz; dz = pbc[2]*domain->zprd; } for (i = 0; i < n; i++) { j = list[i]; buf[m++] = x[j][0] + dx; buf[m++] = x[j][1] + dy; buf[m++] = x[j][2] + dz; buf[m++] = v[j][0]; buf[m++] = v[j][1]; buf[m++] = v[j][2]; if (omega_flag) { buf[m++] = omega[j][0]; buf[m++] = omega[j][1]; buf[m++] = omega[j][2]; } if (angmom_flag) { buf[m++] = angmom[j][0]; buf[m++] = angmom[j][1]; buf[m++] = angmom[j][2]; } for (k = 0; k < nstyles; k++) m += styles[k]->pack_comm_one(j,&buf[m]); } } return m; } /* ---------------------------------------------------------------------- */ void AtomVecHybrid::unpack_comm(int n, int first, double *buf) { int i,k,last; int 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++]; for (k = 0; k < nstyles; k++) m += styles[k]->unpack_comm_one(i,&buf[m]); } } /* ---------------------------------------------------------------------- */ void AtomVecHybrid::unpack_comm_vel(int n, int first, double *buf) { int i,k,last; int omega_flag = atom->omega_flag; int angmom_flag = atom->angmom_flag; int m = 0; last = first + n; for (i = first; i < last; i++) { x[i][0] = buf[m++]; x[i][1] = buf[m++]; x[i][2] = buf[m++]; v[i][0] = buf[m++]; v[i][1] = buf[m++]; v[i][2] = buf[m++]; if (omega_flag) { omega[i][0] = buf[m++]; omega[i][1] = buf[m++]; omega[i][2] = buf[m++]; } if (angmom_flag) { angmom[i][0] = buf[m++]; angmom[i][1] = buf[m++]; angmom[i][2] = buf[m++]; } for (k = 0; k < nstyles; k++) m += styles[k]->unpack_comm_one(i,&buf[m]); } } /* ---------------------------------------------------------------------- */ int AtomVecHybrid::pack_reverse(int n, int first, double *buf) { int i,k,last; int 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]; for (k = 0; k < nstyles; k++) m += styles[k]->pack_reverse_one(i,&buf[m]); } return m; } /* ---------------------------------------------------------------------- */ void AtomVecHybrid::unpack_reverse(int n, int *list, double *buf) { int i,j,k,m; m = 0; for (i = 0; i < n; i++) { j = list[i]; f[j][0] += buf[m++]; f[j][1] += buf[m++]; f[j][2] += buf[m++]; for (k = 0; k < nstyles; k++) m += styles[k]->unpack_reverse_one(j,&buf[m]); } } /* ---------------------------------------------------------------------- */ int AtomVecHybrid::pack_border(int n, int *list, double *buf, int pbc_flag, int *pbc) { int i,j,k,m; double dx,dy,dz; m = 0; if (pbc_flag == 0) { for (i = 0; i < n; i++) { j = list[i]; buf[m++] = x[j][0]; buf[m++] = x[j][1]; buf[m++] = x[j][2]; buf[m++] = tag[j]; buf[m++] = type[j]; buf[m++] = mask[j]; for (k = 0; k < nstyles; k++) m += styles[k]->pack_border_one(j,&buf[m]); } } else { if (domain->triclinic == 0) { dx = pbc[0]*domain->xprd; dy = pbc[1]*domain->yprd; dz = pbc[2]*domain->zprd; } else { dx = pbc[0]; dy = pbc[1]; dz = pbc[2]; } for (i = 0; i < n; i++) { j = list[i]; buf[m++] = x[j][0] + dx; buf[m++] = x[j][1] + dy; buf[m++] = x[j][2] + dz; buf[m++] = tag[j]; buf[m++] = type[j]; buf[m++] = mask[j]; for (k = 0; k < nstyles; k++) m += styles[k]->pack_border_one(j,&buf[m]); } } return m; } /* ---------------------------------------------------------------------- */ int AtomVecHybrid::pack_border_vel(int n, int *list, double *buf, int pbc_flag, int *pbc) { int i,j,k,m; double dx,dy,dz; int omega_flag = atom->omega_flag; int angmom_flag = atom->angmom_flag; m = 0; if (pbc_flag == 0) { for (i = 0; i < n; i++) { j = list[i]; buf[m++] = x[j][0]; buf[m++] = x[j][1]; buf[m++] = x[j][2]; buf[m++] = tag[j]; buf[m++] = type[j]; buf[m++] = mask[j]; buf[m++] = v[j][0]; buf[m++] = v[j][1]; buf[m++] = v[j][2]; if (omega_flag) { buf[m++] = omega[j][0]; buf[m++] = omega[j][1]; buf[m++] = omega[j][2]; } if (angmom_flag) { buf[m++] = angmom[j][0]; buf[m++] = angmom[j][1]; buf[m++] = angmom[j][2]; } for (k = 0; k < nstyles; k++) m += styles[k]->pack_border_one(j,&buf[m]); } } else { if (domain->triclinic == 0) { dx = pbc[0]*domain->xprd; dy = pbc[1]*domain->yprd; dz = pbc[2]*domain->zprd; } else { dx = pbc[0]; dy = pbc[1]; dz = pbc[2]; } for (i = 0; i < n; i++) { j = list[i]; buf[m++] = x[j][0] + dx; buf[m++] = x[j][1] + dy; buf[m++] = x[j][2] + dz; buf[m++] = tag[j]; buf[m++] = type[j]; buf[m++] = mask[j]; buf[m++] = v[j][0]; buf[m++] = v[j][1]; buf[m++] = v[j][2]; if (omega_flag) { buf[m++] = omega[j][0]; buf[m++] = omega[j][1]; buf[m++] = omega[j][2]; } if (angmom_flag) { buf[m++] = angmom[j][0]; buf[m++] = angmom[j][1]; buf[m++] = angmom[j][2]; } for (k = 0; k < nstyles; k++) m += styles[k]->pack_border_one(j,&buf[m]); } } return m; } /* ---------------------------------------------------------------------- */ void AtomVecHybrid::unpack_border(int n, int first, double *buf) { int i,k,m,last; m = 0; last = first + n; for (i = first; i < last; i++) { if (i == nmax) grow(0); x[i][0] = buf[m++]; x[i][1] = buf[m++]; x[i][2] = buf[m++]; tag[i] = static_cast<int> (buf[m++]); type[i] = static_cast<int> (buf[m++]); mask[i] = static_cast<int> (buf[m++]); for (k = 0; k < nstyles; k++) m += styles[k]->unpack_border_one(i,&buf[m]); } } /* ---------------------------------------------------------------------- */ void AtomVecHybrid::unpack_border_vel(int n, int first, double *buf) { int i,k,m,last; int omega_flag = atom->omega_flag; int angmom_flag = atom->angmom_flag; m = 0; last = first + n; for (i = first; i < last; i++) { if (i == nmax) grow(0); x[i][0] = buf[m++]; x[i][1] = buf[m++]; x[i][2] = buf[m++]; tag[i] = static_cast<int> (buf[m++]); type[i] = static_cast<int> (buf[m++]); mask[i] = static_cast<int> (buf[m++]); v[i][0] = buf[m++]; v[i][1] = buf[m++]; v[i][2] = buf[m++]; if (omega_flag) { omega[i][0] = buf[m++]; omega[i][1] = buf[m++]; omega[i][2] = buf[m++]; } if (angmom_flag) { angmom[i][0] = buf[m++]; angmom[i][1] = buf[m++]; angmom[i][2] = buf[m++]; } for (k = 0; k < nstyles; k++) m += styles[k]->unpack_border_one(i,&buf[m]); } } /* ---------------------------------------------------------------------- pack data for atom I for sending to another proc pack each sub-style one after the other ------------------------------------------------------------------------- */ int AtomVecHybrid::pack_exchange(int i, double *buf) { int k; int tmp = atom->nextra_grow; atom->nextra_grow = 0; int m = 0; for (k = 0; k < nstyles; k++) m += styles[k]->pack_exchange(i,&buf[m]); atom->nextra_grow = tmp; if (atom->nextra_grow) for (int iextra = 0; iextra < atom->nextra_grow; iextra++) m += modify->fix[atom->extra_grow[iextra]]->pack_exchange(i,&buf[m]); buf[0] = m; return m; } /* ---------------------------------------------------------------------- unpack data for single atom received from another proc unpack each sub-style one after the other grow() occurs here so arrays for all sub-styles are grown ------------------------------------------------------------------------- */ int AtomVecHybrid::unpack_exchange(double *buf) { int nlocal = atom->nlocal; if (nlocal == nmax) grow(0); int tmp = atom->nextra_grow; atom->nextra_grow = 0; int m = 0; for (int k = 0; k < nstyles; k++) { m += styles[k]->unpack_exchange(&buf[m]); atom->nlocal--; } atom->nextra_grow = tmp; if (atom->nextra_grow) for (int iextra = 0; iextra < atom->nextra_grow; iextra++) m += modify->fix[atom->extra_grow[iextra]]-> unpack_exchange(nlocal,&buf[m]); atom->nlocal++; return m; } /* ---------------------------------------------------------------------- size of restart data for all atoms owned by this proc include extra data stored by fixes ------------------------------------------------------------------------- */ int AtomVecHybrid::size_restart() { int tmp = atom->nextra_restart; atom->nextra_restart = 0; int n = 0; for (int k = 0; k < nstyles; k++) n += styles[k]->size_restart(); atom->nextra_restart = tmp; int nlocal = atom->nlocal; if (atom->nextra_restart) for (int iextra = 0; iextra < atom->nextra_restart; iextra++) for (int i = 0; i < nlocal; i++) n += modify->fix[atom->extra_restart[iextra]]->size_restart(i); return n; } /* ---------------------------------------------------------------------- pack atom I's data for restart file including extra quantities xyz must be 1st 3 values, so that read_restart can test on them pack each sub-style one after the other ------------------------------------------------------------------------- */ int AtomVecHybrid::pack_restart(int i, double *buf) { int tmp = atom->nextra_restart; atom->nextra_restart = 0; int m = 0; for (int k = 0; k < nstyles; k++) m += styles[k]->pack_restart(i,&buf[m]); atom->nextra_restart = tmp; if (atom->nextra_restart) for (int iextra = 0; iextra < atom->nextra_restart; iextra++) m += modify->fix[atom->extra_restart[iextra]]->pack_restart(i,&buf[m]); buf[0] = m; return m; } /* ---------------------------------------------------------------------- unpack data for one atom from restart file including extra quantities unpack each sub-style one after the other grow() occurs here so arrays for all sub-styles are grown ------------------------------------------------------------------------- */ int AtomVecHybrid::unpack_restart(double *buf) { int nlocal = atom->nlocal; if (nlocal == nmax) { grow(0); if (atom->nextra_store) atom->extra = memory->grow_2d_double_array(atom->extra,nmax, atom->nextra_store, "atom:extra"); } int tmp = atom->nextra_store; atom->nextra_store = 0; int m = 0; for (int k = 0; k < nstyles; k++) { m += styles[k]->unpack_restart(&buf[m]); atom->nlocal--; } atom->nextra_store = tmp; double **extra = atom->extra; if (atom->nextra_store) { int size = static_cast<int> (buf[0]) - m; for (int i = 0; i < size; i++) extra[nlocal][i] = buf[m++]; } atom->nlocal++; return m; } /* ---------------------------------------------------------------------- create one atom of itype at coord create each sub-style one after the other grow() occurs here so arrays for all sub-styles are grown ------------------------------------------------------------------------- */ void AtomVecHybrid::create_atom(int itype, double *coord) { int nlocal = atom->nlocal; if (nlocal == nmax) grow(0); for (int k = 0; k < nstyles; k++) { styles[k]->create_atom(itype,coord); atom->nlocal--; } atom->nlocal++; } /* ---------------------------------------------------------------------- unpack one line from Atoms section of data file grow() occurs here so arrays for all sub-styles are grown ------------------------------------------------------------------------- */ void AtomVecHybrid::data_atom(double *coord, int imagetmp, char **values) { int nlocal = atom->nlocal; if (nlocal == nmax) grow(0); tag[nlocal] = atoi(values[0]); if (tag[nlocal] <= 0) error->one("Invalid atom ID in Atoms section of data file"); type[nlocal] = atoi(values[1]); if (type[nlocal] <= 0 || type[nlocal] > atom->ntypes) error->one("Invalid atom type in Atoms section of data file"); x[nlocal][0] = coord[0]; x[nlocal][1] = coord[1]; x[nlocal][2] = coord[2]; image[nlocal] = imagetmp; mask[nlocal] = 1; v[nlocal][0] = 0.0; v[nlocal][1] = 0.0; v[nlocal][2] = 0.0; if (atom->omega_flag) { omega[nlocal][0] = 0.0; omega[nlocal][1] = 0.0; omega[nlocal][2] = 0.0; } if (atom->angmom_flag) { angmom[nlocal][0] = 0.0; angmom[nlocal][1] = 0.0; angmom[nlocal][2] = 0.0; } // each sub-style parses sub-style specific values int m = 5; for (int k = 0; k < nstyles; k++) m += styles[k]->data_atom_hybrid(nlocal,&values[m]); atom->nlocal++; } /* ---------------------------------------------------------------------- unpack one line from Velocities section of data file ------------------------------------------------------------------------- */ void AtomVecHybrid::data_vel(int m, char **values) { v[m][0] = atof(values[0]); v[m][1] = atof(values[1]); v[m][2] = atof(values[2]); // each sub-style parses sub-style specific values int n = 3; for (int k = 0; k < nstyles; k++) n += styles[k]->data_vel_hybrid(m,&values[n]); } /* ---------------------------------------------------------------------- return # of bytes of allocated memory ------------------------------------------------------------------------- */ double AtomVecHybrid::memory_usage() { double bytes = 0.0; for (int k = 0; k < nstyles; k++) bytes += styles[k]->memory_usage(); return bytes; } diff --git a/src/compute.cpp b/src/compute.cpp index 81cedcd17..27e7ff564 100644 --- a/src/compute.cpp +++ b/src/compute.cpp @@ -1,295 +1,296 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ #include "mpi.h" #include "stdlib.h" #include "string.h" #include "ctype.h" #include "compute.h" +#include "lmptype.h" #include "atom.h" #include "domain.h" #include "comm.h" #include "group.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; #define DELTA 4 #define BIG 2000000000 #define MIN(A,B) ((A) < (B)) ? (A) : (B) #define MAX(A,B) ((A) > (B)) ? (A) : (B) /* ---------------------------------------------------------------------- */ Compute::Compute(LAMMPS *lmp, int narg, char **arg) : Pointers(lmp) { if (narg < 3) error->all("Illegal compute command"); // compute ID, group, and style // ID must be all alphanumeric chars or underscores int n = strlen(arg[0]) + 1; id = new char[n]; strcpy(id,arg[0]); for (int i = 0; i < n-1; i++) if (!isalnum(id[i]) && id[i] != '_') error->all("Compute ID must be alphanumeric or underscore characters"); igroup = group->find(arg[1]); if (igroup == -1) error->all("Could not find compute group ID"); groupbit = group->bitmask[igroup]; n = strlen(arg[2]) + 1; style = new char[n]; strcpy(style,arg[2]); // set child class defaults scalar_flag = vector_flag = array_flag = 0; peratom_flag = local_flag = 0; tempflag = pressflag = peflag = 0; pressatomflag = peatomflag = 0; tempbias = 0; timeflag = 0; comm_forward = comm_reverse = 0; invoked_scalar = invoked_vector = invoked_array = -1; invoked_peratom = invoked_local = -1; // set modify defaults extra_dof = domain->dimension; dynamic = 0; // setup list of timesteps ntime = maxtime = 0; tlist = NULL; // setup map for molecule IDs molmap = NULL; } /* ---------------------------------------------------------------------- */ Compute::~Compute() { delete [] id; delete [] style; memory->sfree(tlist); memory->sfree(molmap); } /* ---------------------------------------------------------------------- */ void Compute::modify_params(int narg, char **arg) { if (narg == 0) error->all("Illegal compute_modify command"); int iarg = 0; while (iarg < narg) { if (strcmp(arg[iarg],"extra") == 0) { if (iarg+2 > narg) error->all("Illegal compute_modify command"); extra_dof = atoi(arg[iarg+1]); iarg += 2; } else if (strcmp(arg[iarg],"dynamic") == 0) { if (iarg+2 > narg) error->all("Illegal compute_modify command"); if (strcmp(arg[iarg+1],"no") == 0) dynamic = 0; else if (strcmp(arg[iarg+1],"yes") == 0) dynamic = 1; else error->all("Illegal compute_modify command"); iarg += 2; } else if (strcmp(arg[iarg],"thermo") == 0) { if (iarg+2 > narg) error->all("Illegal compute_modify command"); if (strcmp(arg[iarg+1],"no") == 0) thermoflag = 0; else if (strcmp(arg[iarg+1],"yes") == 0) thermoflag = 1; else error->all("Illegal compute_modify command"); iarg += 2; } else error->all("Illegal compute_modify command"); } } /* ---------------------------------------------------------------------- reset extra_dof to its default value ------------------------------------------------------------------------- */ void Compute::reset_extra_dof() { extra_dof = domain->dimension; } /* ---------------------------------------------------------------------- */ void Compute::reset_extra_compute_fix(char *) { error->all("Compute does not allow an extra compute or fix to be reset"); } /* ---------------------------------------------------------------------- add ntimestep to list of timesteps the compute will be called on do not add if already in list search from top downward, since list of times is in decreasing order ------------------------------------------------------------------------- */ -void Compute::addstep(int ntimestep) +void Compute::addstep(bigint ntimestep) { // i = location in list to insert ntimestep int i; for (i = ntime-1; i >= 0; i--) { if (ntimestep == tlist[i]) return; if (ntimestep < tlist[i]) break; } i++; // extend list as needed if (ntime == maxtime) { maxtime += DELTA; - tlist = (int *) - memory->srealloc(tlist,maxtime*sizeof(int),"compute:tlist"); + tlist = (bigint *) + memory->srealloc(tlist,maxtime*sizeof(bigint),"compute:tlist"); } // move remainder of list upward and insert ntimestep for (int j = ntime-1; j >= i; j--) tlist[j+1] = tlist[j]; tlist[i] = ntimestep; ntime++; } /* ---------------------------------------------------------------------- return 1/0 if ntimestep is or is not in list of calling timesteps if value(s) on top of list are less than ntimestep, delete them search from top downward, since list of times is in decreasing order ------------------------------------------------------------------------- */ -int Compute::matchstep(int ntimestep) +int Compute::matchstep(bigint ntimestep) { for (int i = ntime-1; i >= 0; i--) { if (ntimestep < tlist[i]) return 0; if (ntimestep == tlist[i]) return 1; if (ntimestep > tlist[i]) ntime--; } return 0; } /* ---------------------------------------------------------------------- clean out list of timesteps to call the compute on ------------------------------------------------------------------------- */ void Compute::clearstep() { ntime = 0; } /* ---------------------------------------------------------------------- identify molecule IDs with atoms in group warn if any atom in group has molecule ID = 0 warn if any molecule has only some atoms in group return Ncount = # of molecules with atoms in group set molmap to NULL if molecule IDs include all in range from 1 to Ncount else: molecule IDs range from idlo to idhi set molmap to vector of length idhi-idlo+1 molmap[id-idlo] = index from 0 to Ncount-1 return idlo and idhi ------------------------------------------------------------------------- */ int Compute::molecules_in_group(int &idlo, int &idhi) { int i; memory->sfree(molmap); molmap = NULL; // find lo/hi molecule ID for any atom in group // warn if atom in group has ID = 0 int *molecule = atom->molecule; int *mask = atom->mask; int nlocal = atom->nlocal; int lo = BIG; int hi = -BIG; int flag = 0; for (i = 0; i < nlocal; i++) if (mask[i] & groupbit) { if (molecule[i] == 0) { flag = 1; continue; } lo = MIN(lo,molecule[i]); hi = MAX(hi,molecule[i]); } int flagall; MPI_Allreduce(&flag,&flagall,1,MPI_INT,MPI_SUM,world); if (flagall && comm->me == 0) error->warning("Atom with molecule ID = 0 included in " "compute molecule group"); MPI_Allreduce(&lo,&idlo,1,MPI_INT,MPI_MIN,world); MPI_Allreduce(&hi,&idhi,1,MPI_INT,MPI_MAX,world); if (idlo == BIG) return 0; // molmap = vector of length nlen // set to 1 for IDs that appear in group across all procs, else 0 int nlen = idhi-idlo+1; molmap = (int *) memory->smalloc(nlen*sizeof(int),"compute:molmap"); for (i = 0; i < nlen; i++) molmap[i] = 0; for (i = 0; i < nlocal; i++) if (mask[i] & groupbit) molmap[molecule[i]-idlo] = 1; int *molmapall = (int *) memory->smalloc(nlen*sizeof(int),"compute:molmapall"); MPI_Allreduce(molmap,molmapall,nlen,MPI_INT,MPI_MAX,world); // nmolecules = # of non-zero IDs in molmap // molmap[i] = index of molecule, skipping molecules not in group with -1 int nmolecules = 0; for (i = 0; i < nlen; i++) if (molmapall[i]) molmap[i] = nmolecules++; else molmap[i] = -1; memory->sfree(molmapall); // warn if any molecule has some atoms in group and some not in group flag = 0; for (i = 0; i < nlocal; i++) { if (mask[i] & groupbit) continue; if (molecule[i] == 0) continue; if (molecule[i] < idlo || molecule[i] > idhi) continue; if (molmap[molecule[i]-idlo] >= 0) flag = 1; } MPI_Allreduce(&flag,&flagall,1,MPI_INT,MPI_SUM,world); if (flagall && comm->me == 0) error->warning("One or more compute molecules has atoms not in group"); // if molmap simply stores 1 to Nmolecules, then free it if (nmolecules < nlen) return nmolecules; if (idlo > 1) return nmolecules; memory->sfree(molmap); molmap = NULL; return nmolecules; } diff --git a/src/compute.h b/src/compute.h index f13f2fa9a..cb7c3152f 100644 --- a/src/compute.h +++ b/src/compute.h @@ -1,128 +1,129 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain 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_COMPUTE_H #define LMP_COMPUTE_H #include "pointers.h" +#include "lmptype.h" namespace LAMMPS_NS { class Compute : protected Pointers { public: char *id,*style; int igroup,groupbit; double scalar; // computed global scalar double *vector; // computed global vector double **array; // computed global array double *vector_atom; // computed per-atom vector double **array_atom; // computed per-atom array double *vector_local; // computed local vector double **array_local; // computed local array int scalar_flag; // 0/1 if compute_scalar() function exists int vector_flag; // 0/1 if compute_vector() function exists int array_flag; // 0/1 if compute_array() function exists int size_vector; // length of global vector int size_array_rows; // rows in global array int size_array_cols; // columns in global array int peratom_flag; // 0/1 if compute_peratom() function exists int size_peratom_cols; // 0 = vector, N = columns in peratom array int local_flag; // 0/1 if compute_local() function exists int size_local_rows; // rows in local vector or array int size_local_cols; // 0 = vector, N = columns in local array int extscalar; // 0/1 if global scalar is intensive/extensive int extvector; // 0/1/-1 if global vector is all int/ext/extlist int *extlist; // list of 0/1 int/ext for each vec component int extarray; // 0/1 if global array is all intensive/extensive int tempflag; // 1 if Compute can be used as temperature // must have both compute_scalar, compute_vector int pressflag; // 1 if Compute can be used as pressure (uses virial) // must have both compute_scalar, compute_vector int pressatomflag; // 1 if Compute calculates per-atom virial int peflag; // 1 if Compute calculates PE (uses Force energies) int peatomflag; // 1 if Compute calculates per-atom PE int tempbias; // 0/1 if Compute temp includes self/extra bias int timeflag; // 1 if Compute stores list of timesteps it's called on int ntime; // # of entries in time list int maxtime; // max # of entries time list can hold - int *tlist; // time list of steps the Compute is called on + bigint *tlist; // list of timesteps the Compute is called on - int invoked_flag; // non-zero if invoked or accessed this step, 0 if not - int invoked_scalar; // last timestep on which compute_scalar() was invoked - int invoked_vector; // ditto for compute_vector() - int invoked_array; // ditto for compute_array() - int invoked_peratom; // ditto for compute_peratom() - int invoked_local; // ditto for compute_local() + int invoked_flag; // non-zero if invoked or accessed this step, 0 if not + bigint invoked_scalar; // last timestep on which compute_scalar() was invoked + bigint invoked_vector; // ditto for compute_vector() + bigint invoked_array; // ditto for compute_array() + bigint invoked_peratom; // ditto for compute_peratom() + bigint invoked_local; // ditto for compute_local() double dof; // degrees-of-freedom for temperature int comm_forward; // size of forward communication (0 if none) int comm_reverse; // size of reverse communication (0 if none) Compute(class LAMMPS *, int, char **); virtual ~Compute(); void modify_params(int, char **); void reset_extra_dof(); virtual void init() = 0; virtual void init_list(int, class NeighList *) {} virtual double compute_scalar() {return 0.0;} virtual void compute_vector() {} virtual void compute_array() {} virtual void compute_peratom() {} virtual void compute_local() {} virtual int pack_comm(int, int *, double *, int, int *) {return 0;} virtual void unpack_comm(int, int, double *) {} virtual int pack_reverse_comm(int, int, double *) {return 0;} virtual void unpack_reverse_comm(int, int *, double *) {} virtual int dof_remove(int) {return 0;} virtual void remove_bias(int, double *) {} virtual void remove_bias_all() {} virtual void restore_bias(int, double *) {} virtual void restore_bias_all() {} virtual void reset_extra_compute_fix(char *); - void addstep(int); - int matchstep(int); + void addstep(bigint); + int matchstep(bigint); void clearstep(); virtual double memory_usage() {return 0.0;} protected: int extra_dof; // extra DOF for temperature computes int dynamic; // recount atoms for temperature computes int thermoflag; // 1 if include fix PE for PE computes double vbias[3]; // stored velocity bias for one atom double **vbiasall; // stored velocity bias for all atoms int maxbias; // size of vbiasall array int *molmap; // convert molecule ID to local index int molecules_in_group(int &, int &); }; } #endif diff --git a/src/compute_reduce.cpp b/src/compute_reduce.cpp index db9c3b6a6..da1ff6bcb 100644 --- a/src/compute_reduce.cpp +++ b/src/compute_reduce.cpp @@ -1,656 +1,656 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain 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 "compute_reduce.h" #include "lmptype.h" #include "atom.h" #include "update.h" #include "domain.h" #include "modify.h" #include "fix.h" #include "force.h" #include "comm.h" #include "group.h" #include "input.h" #include "variable.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; enum{SUM,MINN,MAXX,AVE}; enum{X,V,F,COMPUTE,FIX,VARIABLE}; enum{PERATOM,LOCAL}; #define INVOKED_VECTOR 2 #define INVOKED_ARRAY 4 #define INVOKED_PERATOM 8 #define INVOKED_LOCAL 16 #define MIN(A,B) ((A) < (B)) ? (A) : (B) #define MAX(A,B) ((A) > (B)) ? (A) : (B) #define BIG 1.0e20 /* ---------------------------------------------------------------------- */ ComputeReduce::ComputeReduce(LAMMPS *lmp, int narg, char **arg) : Compute(lmp, narg, arg) { int iarg; if (strcmp(style,"reduce") == 0) { if (narg < 5) error->all("Illegal compute reduce command"); idregion = NULL; iarg = 3; } else if (strcmp(style,"reduce/region") == 0) { if (narg < 6) error->all("Illegal compute reduce/region command"); iregion = domain->find_region(arg[3]); if (iregion == -1) error->all("Region ID for compute reduce/region does not exist"); int n = strlen(arg[3]) + 1; idregion = new char[n]; strcpy(idregion,arg[3]); iarg = 4; } if (strcmp(arg[iarg],"sum") == 0) mode = SUM; else if (strcmp(arg[iarg],"min") == 0) mode = MINN; else if (strcmp(arg[iarg],"max") == 0) mode = MAXX; else if (strcmp(arg[iarg],"ave") == 0) mode = AVE; else error->all("Illegal compute reduce command"); iarg++; MPI_Comm_rank(world,&me); // parse remaining values until one isn't recognized which = new int[narg-4]; argindex = new int[narg-4]; flavor = new int[narg-4]; ids = new char*[narg-4]; value2index = new int[narg-4]; nvalues = 0; while (iarg < narg) { ids[nvalues] = NULL; if (strcmp(arg[iarg],"x") == 0) { which[nvalues] = X; argindex[nvalues++] = 0; } else if (strcmp(arg[iarg],"y") == 0) { which[nvalues] = X; argindex[nvalues++] = 1; } else if (strcmp(arg[iarg],"z") == 0) { which[nvalues] = X; argindex[nvalues++] = 2; } else if (strcmp(arg[iarg],"vx") == 0) { which[nvalues] = V; argindex[nvalues++] = 0; } else if (strcmp(arg[iarg],"vy") == 0) { which[nvalues] = V; argindex[nvalues++] = 1; } else if (strcmp(arg[iarg],"vz") == 0) { which[nvalues] = V; argindex[nvalues++] = 2; } else if (strcmp(arg[iarg],"fx") == 0) { which[nvalues] = F; argindex[nvalues++] = 0; } else if (strcmp(arg[iarg],"fy") == 0) { which[nvalues] = F; argindex[nvalues++] = 1; } else if (strcmp(arg[iarg],"fz") == 0) { which[nvalues] = F; argindex[nvalues++] = 2; } else if (strncmp(arg[iarg],"c_",2) == 0 || strncmp(arg[iarg],"f_",2) == 0 || strncmp(arg[iarg],"v_",2) == 0) { if (arg[iarg][0] == 'c') which[nvalues] = COMPUTE; else if (arg[iarg][0] == 'f') which[nvalues] = FIX; else if (arg[iarg][0] == 'v') which[nvalues] = VARIABLE; int n = strlen(arg[iarg]); char *suffix = new char[n]; strcpy(suffix,&arg[iarg][2]); char *ptr = strchr(suffix,'['); if (ptr) { if (suffix[strlen(suffix)-1] != ']') error->all("Illegal compute reduce command"); argindex[nvalues] = atoi(ptr+1); *ptr = '\0'; } else argindex[nvalues] = 0; n = strlen(suffix) + 1; ids[nvalues] = new char[n]; strcpy(ids[nvalues],suffix); nvalues++; delete [] suffix; } else break; iarg++; } // optional args replace = new int[nvalues]; for (int i = 0; i < nvalues; i++) replace[i] = -1; while (iarg < narg) { if (strcmp(arg[iarg],"replace") == 0) { if (iarg+3 > narg) error->all("Illegal compute reduce command"); if (mode != MINN && mode != MAXX) error->all("Compute reduce replace requires min or max mode"); int col1 = atoi(arg[iarg+1]) - 1; int col2 = atoi(arg[iarg+2]) - 1; if (col1 < 0 || col1 >= nvalues || col2 < 0 || col2 >= nvalues) error->all("Illegal compute reduce command"); if (col1 == col2) error->all("Illegal compute reduce command"); if (replace[col1] >= 0 || replace[col2] >= 0) error->all("Invalid replace values in compute reduce"); replace[col1] = col2; iarg += 3; } else error->all("Illegal compute reduce command"); } // delete replace if not set int flag = 0; for (int i = 0; i < nvalues; i++) if (replace[i] >= 0) flag = 1; if (!flag) { delete [] replace; replace = NULL; } // setup and error check for (int i = 0; i < nvalues; i++) { if (which[i] == X || which[i] == V || which[i] == F) flavor[i] = PERATOM; else if (which[i] == COMPUTE) { int icompute = modify->find_compute(ids[i]); if (icompute < 0) error->all("Compute ID for compute reduce does not exist"); if (modify->compute[icompute]->peratom_flag) { flavor[i] = PERATOM; if (argindex[i] == 0 && modify->compute[icompute]->size_peratom_cols != 0) error->all("Compute reduce compute does not " "calculate a per-atom vector"); if (argindex[i] && modify->compute[icompute]->size_peratom_cols == 0) error->all("Compute reduce compute does not " "calculate a per-atom array"); if (argindex[i] && argindex[i] > modify->compute[icompute]->size_peratom_cols) error->all("Compute reduce compute array is accessed out-of-range"); } else if (modify->compute[icompute]->local_flag) { flavor[i] = LOCAL; if (argindex[i] == 0 && modify->compute[icompute]->size_local_cols != 0) error->all("Compute reduce compute does not " "calculate a local vector"); if (argindex[i] && modify->compute[icompute]->size_local_cols == 0) error->all("Compute reduce compute does not " "calculate a local array"); if (argindex[i] && argindex[i] > modify->compute[icompute]->size_local_cols) error->all("Compute reduce compute array is accessed out-of-range"); } else error->all("Compute reduce compute calculates global values"); } else if (which[i] == FIX) { int ifix = modify->find_fix(ids[i]); if (ifix < 0) error->all("Fix ID for compute reduce does not exist"); if (modify->fix[ifix]->peratom_flag) { flavor[i] = PERATOM; if (argindex[i] == 0 && modify->fix[ifix]->size_peratom_cols != 0) error->all("Compute reduce fix does not " "calculate a per-atom vector"); if (argindex[i] && modify->fix[ifix]->size_peratom_cols == 0) error->all("Compute reduce fix does not " "calculate a per-atom array"); if (argindex[i] && argindex[i] > modify->fix[ifix]->size_peratom_cols) error->all("Compute reduce fix array is accessed out-of-range"); } else if (modify->fix[ifix]->local_flag) { flavor[i] = LOCAL; if (argindex[i] == 0 && modify->fix[ifix]->size_local_cols != 0) error->all("Compute reduce fix does not " "calculate a local vector"); if (argindex[i] && modify->fix[ifix]->size_local_cols == 0) error->all("Compute reduce fix does not " "calculate a local array"); if (argindex[i] && argindex[i] > modify->fix[ifix]->size_local_cols) error->all("Compute reduce fix array is accessed out-of-range"); } else error->all("Compute reduce fix calculates global values"); } else if (which[i] == VARIABLE) { int ivariable = input->variable->find(ids[i]); if (ivariable < 0) error->all("Variable name for compute reduce does not exist"); if (input->variable->atomstyle(ivariable) == 0) error->all("Compute reduce variable is not atom-style variable"); flavor[i] = PERATOM; } } // this compute produces either a scalar or vector if (nvalues == 1) { scalar_flag = 1; if (mode == SUM) extscalar = 1; else extscalar = 0; vector = onevec = NULL; indices = owner = NULL; } else { vector_flag = 1; size_vector = nvalues; if (mode == SUM) extvector = 1; else extvector = 0; vector = new double[size_vector]; onevec = new double[size_vector]; indices = new int[size_vector]; owner = new int[size_vector]; } maxatom = 0; varatom = NULL; } /* ---------------------------------------------------------------------- */ ComputeReduce::~ComputeReduce() { delete [] which; delete [] argindex; delete [] flavor; for (int m = 0; m < nvalues; m++) delete [] ids[m]; delete [] ids; delete [] value2index; delete [] replace; delete [] idregion; delete [] vector; delete [] onevec; delete [] indices; delete [] owner; memory->sfree(varatom); } /* ---------------------------------------------------------------------- */ void ComputeReduce::init() { // set indices and check validity of all computes,fixes,variables for (int m = 0; m < nvalues; m++) { if (which[m] == COMPUTE) { int icompute = modify->find_compute(ids[m]); if (icompute < 0) error->all("Compute ID for compute reduce does not exist"); value2index[m] = icompute; } else if (which[m] == FIX) { int ifix = modify->find_fix(ids[m]); if (ifix < 0) error->all("Fix ID for compute reduce does not exist"); value2index[m] = ifix; } else if (which[m] == VARIABLE) { int ivariable = input->variable->find(ids[m]); if (ivariable < 0) error->all("Variable name for compute reduce does not exist"); value2index[m] = ivariable; } else value2index[m] = -1; } // set index and check validity of region if (idregion) { iregion = domain->find_region(idregion); if (iregion == -1) error->all("Region ID for compute reduce/region does not exist"); } } /* ---------------------------------------------------------------------- */ double ComputeReduce::compute_scalar() { invoked_scalar = update->ntimestep; double one = compute_one(0,-1); if (mode == SUM) { MPI_Allreduce(&one,&scalar,1,MPI_DOUBLE,MPI_SUM,world); } else if (mode == MINN) { MPI_Allreduce(&one,&scalar,1,MPI_DOUBLE,MPI_MIN,world); } else if (mode == MAXX) { MPI_Allreduce(&one,&scalar,1,MPI_DOUBLE,MPI_MAX,world); } else if (mode == AVE) { MPI_Allreduce(&one,&scalar,1,MPI_DOUBLE,MPI_SUM,world); scalar /= count(0); } return scalar; } /* ---------------------------------------------------------------------- */ void ComputeReduce::compute_vector() { invoked_vector = update->ntimestep; for (int m = 0; m < nvalues; m++) if (!replace || replace[m] < 0) { onevec[m] = compute_one(m,-1); indices[m] = index; } if (mode == SUM) { for (int m = 0; m < nvalues; m++) MPI_Allreduce(&onevec[m],&vector[m],1,MPI_DOUBLE,MPI_SUM,world); } else if (mode == MINN) { if (!replace) { for (int m = 0; m < nvalues; m++) MPI_Allreduce(&onevec[m],&vector[m],1,MPI_DOUBLE,MPI_MIN,world); } else { for (int m = 0; m < nvalues; m++) if (replace[m] < 0) { pairme.value = onevec[m]; pairme.proc = me; MPI_Allreduce(&pairme,&pairall,1,MPI_DOUBLE_INT,MPI_MINLOC,world); vector[m] = pairall.value; owner[m] = pairall.proc; } for (int m = 0; m < nvalues; m++) if (replace[m] >= 0) { if (me == owner[replace[m]]) vector[m] = compute_one(m,indices[replace[m]]); MPI_Bcast(&vector[m],1,MPI_DOUBLE,owner[replace[m]],world); } } } else if (mode == MAXX) { if (!replace) { for (int m = 0; m < nvalues; m++) MPI_Allreduce(&onevec[m],&vector[m],1,MPI_DOUBLE,MPI_MAX,world); } else { for (int m = 0; m < nvalues; m++) if (replace[m] < 0) { pairme.value = onevec[m]; pairme.proc = me; MPI_Allreduce(&pairme,&pairall,1,MPI_DOUBLE_INT,MPI_MAXLOC,world); vector[m] = pairall.value; owner[m] = pairall.proc; } for (int m = 0; m < nvalues; m++) if (replace[m] >= 0) { if (me == owner[replace[m]]) vector[m] = compute_one(m,indices[replace[m]]); MPI_Bcast(&vector[m],1,MPI_DOUBLE,owner[replace[m]],world); } } } else if (mode == AVE) { for (int m = 0; m < nvalues; m++) { MPI_Allreduce(&onevec[m],&vector[m],1,MPI_DOUBLE,MPI_SUM,world); vector[m] /= count(m); } } } /* ---------------------------------------------------------------------- calculate reduced value for one input M and return it if flag = -1: sum/min/max/ave all values in vector for per-atom quantities, limit to atoms in group if mode = MIN or MAX, also set index to which vector value wins if flag >= 0: simply return vector[flag] ------------------------------------------------------------------------- */ double ComputeReduce::compute_one(int m, int flag) { int i; // invoke the appropriate attribute,compute,fix,variable // for flag = -1, compute scalar quantity by scanning over atom properties // only include atoms in group for atom properties and per-atom quantities index = -1; int vidx = value2index[m]; int aidx = argindex[m]; int *mask = atom->mask; int nlocal = atom->nlocal; double one; if (mode == SUM) one = 0.0; else if (mode == MINN) one = BIG; else if (mode == MAXX) one = -BIG; else if (mode == AVE) one = 0.0; if (which[m] == X) { double **x = atom->x; if (flag < 0) { for (i = 0; i < nlocal; i++) if (mask[i] & groupbit) combine(one,x[i][aidx],i); } else one = x[flag][aidx]; } else if (which[m] == V) { double **v = atom->v; if (flag < 0) { for (i = 0; i < nlocal; i++) if (mask[i] & groupbit) combine(one,v[i][aidx],i); } else one = v[flag][aidx]; } else if (which[m] == F) { double **f = atom->f; if (flag < 0) { for (i = 0; i < nlocal; i++) if (mask[i] & groupbit) combine(one,f[i][aidx],i); } else one = f[flag][aidx]; // invoke compute if not previously invoked } else if (which[m] == COMPUTE) { Compute *compute = modify->compute[vidx]; if (flavor[m] == PERATOM) { if (!(compute->invoked_flag & INVOKED_PERATOM)) { compute->compute_peratom(); compute->invoked_flag |= INVOKED_PERATOM; } if (aidx == 0) { double *comp_vec = compute->vector_atom; int n = nlocal; if (flag < 0) { for (i = 0; i < n; i++) if (mask[i] & groupbit) combine(one,comp_vec[i],i); } else one = comp_vec[flag]; } else { double **carray_atom = compute->array_atom; int n = nlocal; int aidxm1 = aidx - 1; if (flag < 0) { for (i = 0; i < n; i++) if (mask[i] & groupbit) combine(one,carray_atom[i][aidxm1],i); } else one = carray_atom[flag][aidxm1]; } } else if (flavor[m] == LOCAL) { if (!(compute->invoked_flag & INVOKED_LOCAL)) { compute->compute_local(); compute->invoked_flag |= INVOKED_LOCAL; } if (aidx == 0) { double *comp_vec = compute->vector_local; int n = compute->size_local_rows; if (flag < 0) for (i = 0; i < n; i++) combine(one,comp_vec[i],i); else one = comp_vec[flag]; } else { double **carray_local = compute->array_local; int n = compute->size_local_rows; int aidxm1 = aidx - 1; if (flag < 0) for (i = 0; i < n; i++) combine(one,carray_local[i][aidxm1],i); else one = carray_local[flag][aidxm1]; } } // access fix fields, check if fix frequency is a match } else if (which[m] == FIX) { if (update->ntimestep % modify->fix[vidx]->peratom_freq) error->all("Fix used in compute reduce not computed at compatible time"); Fix *fix = modify->fix[vidx]; if (flavor[m] == PERATOM) { if (aidx == 0) { double *fix_vector = fix->vector_atom; int n = nlocal; if (flag < 0) { for (i = 0; i < n; i++) if (mask[i] & groupbit) combine(one,fix_vector[i],i); } else one = fix_vector[flag]; } else { double **fix_array = fix->array_atom; int aidxm1 = aidx - 1; if (flag < 0) { for (i = 0; i < nlocal; i++) if (mask[i] & groupbit) combine(one,fix_array[i][aidxm1],i); } else one = fix_array[flag][aidxm1]; } } else if (flavor[m] == LOCAL) { if (aidx == 0) { double *fix_vector = fix->vector_local; int n = fix->size_local_rows; if (flag < 0) for (i = 0; i < n; i++) combine(one,fix_vector[i],i); else one = fix_vector[flag]; } else { double **fix_array = fix->array_local; int n = fix->size_local_rows; int aidxm1 = aidx - 1; if (flag < 0) for (i = 0; i < n; i++) combine(one,fix_array[i][aidxm1],i); else one = fix_array[flag][aidxm1]; } } // evaluate atom-style variable } else if (which[m] == VARIABLE) { if (nlocal > maxatom) { maxatom = atom->nmax; memory->sfree(varatom); varatom = (double *) memory->smalloc(maxatom*sizeof(double),"reduce:varatom"); } input->variable->compute_atom(vidx,igroup,varatom,1,0); if (flag < 0) { for (i = 0; i < nlocal; i++) if (mask[i] & groupbit) combine(one,varatom[i],i); } else one = varatom[flag]; } return one; } /* ---------------------------------------------------------------------- */ bigint ComputeReduce::count(int m) { int vidx = value2index[m]; int aidx = argindex[m]; if (which[m] == X || which[m] == V || which[m] == F) return group->count(igroup); else if (which[m] == COMPUTE) { Compute *compute = modify->compute[vidx]; if (flavor[m] == PERATOM) { return group->count(igroup); } else if (flavor[m] == LOCAL) { bigint ncount = compute->size_local_rows; bigint ncountall; - MPI_Allreduce(&ncount,&ncountall,1,MPI_UNSIGNED_LONG_LONG,MPI_SUM,world); + MPI_Allreduce(&ncount,&ncountall,1,MPI_LMP_BIGINT,MPI_SUM,world); return ncountall; } } else if (which[m] == FIX) { Fix *fix = modify->fix[vidx]; if (flavor[m] == PERATOM) { return group->count(igroup); } else if (flavor[m] == LOCAL) { bigint ncount = fix->size_local_rows; bigint ncountall; - MPI_Allreduce(&ncount,&ncountall,1,MPI_UNSIGNED_LONG_LONG,MPI_SUM,world); + MPI_Allreduce(&ncount,&ncountall,1,MPI_LMP_BIGINT,MPI_SUM,world); return ncountall; } } else if (which[m] == VARIABLE) return group->count(igroup); bigint dummy = 0; return dummy; } /* ---------------------------------------------------------------------- combine two values according to reduction mode for MIN/MAX, also update index with winner ------------------------------------------------------------------------- */ void ComputeReduce::combine(double &one, double two, int i) { if (mode == SUM || mode == AVE) one += two; else if (mode == MINN) { if (two < one) { one = two; index = i; } } else if (mode == MAXX) { if (two > one) { one = two; index = i; } } } /* ---------------------------------------------------------------------- memory usage of varatom ------------------------------------------------------------------------- */ double ComputeReduce::memory_usage() { double bytes = maxatom * sizeof(double); return bytes; } diff --git a/src/create_atoms.cpp b/src/create_atoms.cpp index e895c6853..60f823909 100644 --- a/src/create_atoms.cpp +++ b/src/create_atoms.cpp @@ -1,483 +1,487 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ #include "math.h" #include "stdlib.h" #include "string.h" #include "create_atoms.h" #include "lmptype.h" #include "atom.h" #include "atom_vec.h" #include "comm.h" #include "modify.h" #include "fix.h" #include "domain.h" #include "lattice.h" #include "region.h" #include "random_park.h" #include "error.h" using namespace LAMMPS_NS; #define BIG 1.0e30 #define EPSILON 1.0e-6 enum{BOX,REGION,SINGLE,RANDOM}; #define MIN(a,b) ((a) < (b) ? (a) : (b)) #define MAX(a,b) ((a) > (b) ? (a) : (b)) /* ---------------------------------------------------------------------- */ CreateAtoms::CreateAtoms(LAMMPS *lmp) : Pointers(lmp) {} /* ---------------------------------------------------------------------- */ void CreateAtoms::command(int narg, char **arg) { if (domain->box_exist == 0) error->all("Create_atoms command before simulation box is defined"); if (modify->nfix_restart_peratom) error->all("Cannot create_atoms after " "reading restart file with per-atom info"); // parse arguments if (narg < 2) error->all("Illegal create_atoms command"); itype = atoi(arg[0]); if (itype <= 0 || itype > atom->ntypes) error->all("Invalid atom type in create_atoms command"); int iarg; if (strcmp(arg[1],"box") == 0) { style = BOX; iarg = 2; } else if (strcmp(arg[1],"region") == 0) { style = REGION; if (narg < 3) error->all("Illegal create_atoms command"); nregion = domain->find_region(arg[2]); if (nregion == -1) error->all("Create_atoms region ID does not exist"); iarg = 3;; } else if (strcmp(arg[1],"single") == 0) { style = SINGLE; if (narg < 5) error->all("Illegal create_atoms command"); xone[0] = atof(arg[2]); xone[1] = atof(arg[3]); xone[2] = atof(arg[4]); iarg = 5; } else if (strcmp(arg[1],"random") == 0) { style = RANDOM; if (narg < 5) error->all("Illegal create_atoms command"); nrandom = atoi(arg[2]); seed = atoi(arg[3]); if (strcmp(arg[4],"NULL") == 0) nregion = -1; else { nregion = domain->find_region(arg[4]); if (nregion == -1) error->all("Create_atoms region ID does not exist"); } iarg = 5; } else error->all("Illegal create_atoms command"); // process optional keywords int scaleflag = 1; if (domain->lattice) { nbasis = domain->lattice->nbasis; basistype = new int[nbasis]; for (int i = 0; i < nbasis; i++) basistype[i] = itype; } while (iarg < narg) { if (strcmp(arg[iarg],"basis") == 0) { if (iarg+3 > narg) error->all("Illegal create_atoms command"); if (domain->lattice == NULL) error->all("Cannot create atoms with undefined lattice"); int ibasis = atoi(arg[iarg+1]); itype = atoi(arg[iarg+2]); if (ibasis <= 0 || ibasis > nbasis || itype <= 0 || itype > atom->ntypes) error->all("Illegal create_atoms command"); basistype[ibasis-1] = itype; iarg += 3; } else if (strcmp(arg[iarg],"units") == 0) { if (iarg+2 > narg) error->all("Illegal create_atoms command"); if (strcmp(arg[iarg+1],"box") == 0) scaleflag = 0; else if (strcmp(arg[iarg+1],"lattice") == 0) scaleflag = 1; else error->all("Illegal create_atoms command"); iarg += 2; } else error->all("Illegal create_atoms command"); } // error checks if (style == RANDOM) { if (nrandom < 0) error->all("Illegal create_atoms command"); if (seed <= 0) error->all("Illegal create_atoms command"); } // demand lattice be defined // else setup scaling for single atom // could use domain->lattice->lattice2box() to do conversion of // lattice to box, but not consistent with other uses of units=lattice // triclinic remapping occurs in add_single() if (style == BOX || style == REGION) { if (domain->lattice == NULL) error->all("Cannot create atoms with undefined lattice"); } else if (scaleflag == 1) { if (domain->lattice == NULL) error->all("Cannot create atoms with undefined lattice"); xone[0] *= domain->lattice->xlattice; xone[1] *= domain->lattice->ylattice; xone[2] *= domain->lattice->zlattice; } // add atoms bigint natoms_previous = atom->natoms; int nlocal_previous = atom->nlocal; if (style == SINGLE) add_single(); else if (style == RANDOM) add_random(); else add_lattice(); // invoke set_arrays() for fixes that need initialization of new atoms int nlocal = atom->nlocal; for (int m = 0; m < modify->nfix; m++) { Fix *fix = modify->fix[m]; if (fix->create_attribute) for (int i = nlocal_previous; i < nlocal; i++) fix->set_arrays(i); } // clean up if (domain->lattice) delete [] basistype; // new total # of atoms bigint nblocal = atom->nlocal; - MPI_Allreduce(&nblocal,&atom->natoms,1,MPI_UNSIGNED_LONG_LONG,MPI_SUM,world); + MPI_Allreduce(&nblocal,&atom->natoms,1,MPI_LMP_BIGINT,MPI_SUM,world); + if (atom->natoms < 0 || atom->natoms > MAXBIGINT) + error->all("Too many total atoms"); // print status if (comm->me == 0) { + char str[32]; + sprintf(str,"Created %s atoms\n",BIGINT_FORMAT); if (screen) - fprintf(screen,"Created %lu atoms\n",atom->natoms-natoms_previous); + fprintf(screen,str,atom->natoms-natoms_previous); if (logfile) - fprintf(logfile,"Created %lu atoms\n",atom->natoms-natoms_previous); + fprintf(logfile,str,atom->natoms-natoms_previous); } // reset simulation now that more atoms are defined // add tags for newly created atoms if possible // if global map exists, reset it // if a molecular system, set nspecial to 0 for new atoms - if (atom->natoms > MAXINT32) atom->tag_enable = 0; - if (atom->natoms <= MAXINT32) atom->tag_extend(); + if (atom->natoms > MAXTAGINT) atom->tag_enable = 0; + if (atom->natoms <= MAXTAGINT) atom->tag_extend(); if (atom->map_style) { atom->nghost = 0; atom->map_init(); atom->map_set(); } if (atom->molecular) { int **nspecial = atom->nspecial; for (int i = nlocal_previous; i < atom->nlocal; i++) { nspecial[i][0] = 0; nspecial[i][1] = 0; nspecial[i][2] = 0; } } } /* ---------------------------------------------------------------------- add single atom with coords at xone if it's in my sub-box if triclinic, xone is in lamda coords ------------------------------------------------------------------------- */ void CreateAtoms::add_single() { double *sublo,*subhi; // sub-domain bounding box, in lamda units if triclinic if (domain->triclinic == 0) { sublo = domain->sublo; subhi = domain->subhi; } else { sublo = domain->sublo_lamda; subhi = domain->subhi_lamda; } // if triclinic, convert to lamda coords (0-1) double lamda[3],*coord; if (domain->triclinic) { domain->x2lamda(xone,lamda); coord = lamda; } else coord = xone; // if atom is in my subbox, create it if (coord[0] >= sublo[0] && coord[0] < subhi[0] && coord[1] >= sublo[1] && coord[1] < subhi[1] && coord[2] >= sublo[2] && coord[2] < subhi[2]) atom->avec->create_atom(itype,xone); } /* ---------------------------------------------------------------------- add Nrandom atoms at random locations ------------------------------------------------------------------------- */ void CreateAtoms::add_random() { double xlo,ylo,zlo,xhi,yhi,zhi,zmid; double lamda[3],*coord; double *sublo,*subhi,*boxlo,*boxhi; // random number generator, same for all procs RanPark *random = new RanPark(lmp,seed); // bounding box for atom creation // in real units, even if triclinic // only limit bbox by region if its bboxflag is set (interior region) if (domain->triclinic == 0) { xlo = domain->boxlo[0]; xhi = domain->boxhi[0]; ylo = domain->boxlo[1]; yhi = domain->boxhi[1]; zlo = domain->boxlo[2]; zhi = domain->boxhi[2]; zmid = zlo + 0.5*(zhi-zlo); } else { xlo = domain->boxlo_bound[0]; xhi = domain->boxhi_bound[0]; ylo = domain->boxlo_bound[1]; yhi = domain->boxhi_bound[1]; zlo = domain->boxlo_bound[2]; zhi = domain->boxhi_bound[2]; zmid = zlo + 0.5*(zhi-zlo); } if (nregion >= 0 && domain->regions[nregion]->bboxflag) { xlo = MAX(xlo,domain->regions[nregion]->extent_xlo); xhi = MIN(xhi,domain->regions[nregion]->extent_xhi); ylo = MAX(ylo,domain->regions[nregion]->extent_ylo); yhi = MIN(yhi,domain->regions[nregion]->extent_yhi); zlo = MAX(zlo,domain->regions[nregion]->extent_zlo); zhi = MIN(zhi,domain->regions[nregion]->extent_zhi); } // sub-domain bounding box, in lamda units if triclinic if (domain->triclinic == 0) { sublo = domain->sublo; subhi = domain->subhi; } else { sublo = domain->sublo_lamda; subhi = domain->subhi_lamda; boxlo = domain->boxlo_lamda; boxhi = domain->boxhi_lamda; } // generate random positions for each new atom within bounding box // iterate until atom is within region and triclinic simulation box // if final atom position is in my subbox, create it int valid; for (int i = 0; i < nrandom; i++) { while (1) { xone[0] = xlo + random->uniform() * (xhi-xlo); xone[1] = ylo + random->uniform() * (yhi-ylo); xone[2] = zlo + random->uniform() * (zhi-zlo); if (domain->dimension == 2) xone[2] = zmid; valid = 1; if (nregion >= 0 && domain->regions[nregion]->match(xone[0],xone[1],xone[2]) == 0) valid = 0; if (domain->triclinic) { domain->x2lamda(xone,lamda); coord = lamda; if (coord[0] < boxlo[0] || coord[0] >= boxhi[0] || coord[1] < boxlo[1] || coord[1] >= boxhi[1] || coord[2] < boxlo[2] || coord[2] >= boxhi[2]) valid = 0; } else coord = xone; if (valid) break; } // if triclinic, coord is now in lamda units if (coord[0] >= sublo[0] && coord[0] < subhi[0] && coord[1] >= sublo[1] && coord[1] < subhi[1] && coord[2] >= sublo[2] && coord[2] < subhi[2]) atom->avec->create_atom(itype,xone); } // clean-up delete random; } /* ---------------------------------------------------------------------- add many atoms by looping over lattice ------------------------------------------------------------------------- */ void CreateAtoms::add_lattice() { // convert 8 corners of my subdomain from box coords to lattice coords // for orthogonal, use corner pts of my subbox // for triclinic, use bounding box of my subbox // xyz min to max = bounding box around the domain corners in lattice space int triclinic = domain->triclinic; double bboxlo[3],bboxhi[3]; if (triclinic == 0) { bboxlo[0] = domain->sublo[0]; bboxhi[0] = domain->subhi[0]; bboxlo[1] = domain->sublo[1]; bboxhi[1] = domain->subhi[1]; bboxlo[2] = domain->sublo[2]; bboxhi[2] = domain->subhi[2]; } else domain->bbox(domain->sublo_lamda,domain->subhi_lamda,bboxlo,bboxhi); double xmin,ymin,zmin,xmax,ymax,zmax; xmin = ymin = zmin = BIG; xmax = ymax = zmax = -BIG; domain->lattice->bbox(1,bboxlo[0],bboxlo[1],bboxlo[2], xmin,ymin,zmin,xmax,ymax,zmax); domain->lattice->bbox(1,bboxhi[0],bboxlo[1],bboxlo[2], xmin,ymin,zmin,xmax,ymax,zmax); domain->lattice->bbox(1,bboxlo[0],bboxhi[1],bboxlo[2], xmin,ymin,zmin,xmax,ymax,zmax); domain->lattice->bbox(1,bboxhi[0],bboxhi[1],bboxlo[2], xmin,ymin,zmin,xmax,ymax,zmax); domain->lattice->bbox(1,bboxlo[0],bboxlo[1],bboxhi[2], xmin,ymin,zmin,xmax,ymax,zmax); domain->lattice->bbox(1,bboxhi[0],bboxlo[1],bboxhi[2], xmin,ymin,zmin,xmax,ymax,zmax); domain->lattice->bbox(1,bboxlo[0],bboxhi[1],bboxhi[2], xmin,ymin,zmin,xmax,ymax,zmax); domain->lattice->bbox(1,bboxhi[0],bboxhi[1],bboxhi[2], xmin,ymin,zmin,xmax,ymax,zmax); // ilo:ihi,jlo:jhi,klo:khi = loop bounds for lattice overlap of my subbox // overlap = any part of a unit cell (face,edge,pt) in common with my subbox // in lattice space, subbox is a tilted box // but bbox of subbox is aligned with lattice axes // so ilo:khi unit cells should completely tile bounding box // decrement lo, increment hi to avoid round-off issues in lattice->bbox(), // which can lead to missing atoms in rare cases // extra decrement of lo if min < 0, since static_cast(-1.5) = -1 int ilo,ihi,jlo,jhi,klo,khi; ilo = static_cast<int> (xmin) - 1; jlo = static_cast<int> (ymin) - 1; klo = static_cast<int> (zmin) - 1; ihi = static_cast<int> (xmax) + 1; jhi = static_cast<int> (ymax) + 1; khi = static_cast<int> (zmax) + 1; if (xmin < 0.0) ilo--; if (ymin < 0.0) jlo--; if (zmin < 0.0) klo--; // set bounds for my proc // if periodic: // should create exactly 1 atom when 2 images are both "on" the boundary // either image may be slightly inside/outside true box due to round-off // if I am lo proc, decrement lower bound by EPSILON // this will insure lo image is created // if I am hi proc, decrement upper bound by 2.0*EPSILON // this will insure hi image is not created // thus insertion box is EPSILON smaller than true box // and is shifted away from true boundary // which is where atoms are likely to be generated double epsilon[3]; if (triclinic) epsilon[0] = epsilon[1] = epsilon[2] = EPSILON; else { epsilon[0] = domain->prd[0] * EPSILON; epsilon[1] = domain->prd[1] * EPSILON; epsilon[2] = domain->prd[2] * EPSILON; } double sublo[3],subhi[3]; if (triclinic == 0) { sublo[0] = domain->sublo[0]; subhi[0] = domain->subhi[0]; sublo[1] = domain->sublo[1]; subhi[1] = domain->subhi[1]; sublo[2] = domain->sublo[2]; subhi[2] = domain->subhi[2]; } else { sublo[0] = domain->sublo_lamda[0]; subhi[0] = domain->subhi_lamda[0]; sublo[1] = domain->sublo_lamda[1]; subhi[1] = domain->subhi_lamda[1]; sublo[2] = domain->sublo_lamda[2]; subhi[2] = domain->subhi_lamda[2]; } if (domain->xperiodic) { if (comm->myloc[0] == 0) sublo[0] -= epsilon[0]; if (comm->myloc[0] == comm->procgrid[0]-1) subhi[0] -= 2.0*epsilon[0]; } if (domain->yperiodic) { if (comm->myloc[1] == 0) sublo[1] -= epsilon[1]; if (comm->myloc[1] == comm->procgrid[1]-1) subhi[1] -= 2.0*epsilon[1]; } if (domain->zperiodic) { if (comm->myloc[2] == 0) sublo[2] -= epsilon[2]; if (comm->myloc[2] == comm->procgrid[2]-1) subhi[2] -= 2.0*epsilon[2]; } // iterate on 3d periodic lattice of unit cells using loop bounds // iterate on nbasis atoms in each unit cell // convert lattice coords to box coords // add atom if it meets all criteria double **basis = domain->lattice->basis; double x[3],lamda[3]; double *coord; int i,j,k,m; for (k = klo; k <= khi; k++) for (j = jlo; j <= jhi; j++) for (i = ilo; i <= ihi; i++) for (m = 0; m < nbasis; m++) { x[0] = i + basis[m][0]; x[1] = j + basis[m][1]; x[2] = k + basis[m][2]; // convert from lattice coords to box coords domain->lattice->lattice2box(x[0],x[1],x[2]); // if a region was specified, test if atom is in it if (style == REGION) if (!domain->regions[nregion]->match(x[0],x[1],x[2])) continue; // test if atom is in my subbox if (triclinic) { domain->x2lamda(x,lamda); coord = lamda; } else coord = x; if (coord[0] < sublo[0] || coord[0] >= subhi[0] || coord[1] < sublo[1] || coord[1] >= subhi[1] || coord[2] < sublo[2] || coord[2] >= subhi[2]) continue; // add the atom to my list of atoms atom->avec->create_atom(basistype[m],x); } } diff --git a/src/delete_atoms.cpp b/src/delete_atoms.cpp index 1fcf224b0..f140c5237 100644 --- a/src/delete_atoms.cpp +++ b/src/delete_atoms.cpp @@ -1,362 +1,363 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ #include "stdlib.h" #include "string.h" #include "delete_atoms.h" #include "lmptype.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" using namespace LAMMPS_NS; #define MIN(a,b) ((a) < (b) ? (a) : (b)) #define MAX(a,b) ((a) > (b) ? (a) : (b)) /* ---------------------------------------------------------------------- */ DeleteAtoms::DeleteAtoms(LAMMPS *lmp) : Pointers(lmp) {} /* ---------------------------------------------------------------------- */ void DeleteAtoms::command(int narg, char **arg) { if (domain->box_exist == 0) error->all("Delete_atoms command before simulation box is defined"); if (narg < 1) error->all("Illegal delete_atoms command"); if (atom->tag_enable == 0) error->all("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("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); dlist[i] = dlist[nlocal-1]; nlocal--; } else i++; } atom->nlocal = nlocal; memory->sfree(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_UNSIGNED_LONG_LONG,MPI_SUM,world); + 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 %lu atoms, new total = %lu\n", - ndelete,atom->natoms); - if (logfile) fprintf(logfile,"Deleted %lu atoms, new total = %lu\n", - ndelete,atom->natoms); + char str[64]; + sprintf(str,"Deleted %s atoms, new total = %s\n", + BIGINT_FORMAT,BIGINT_FORMAT); + if (screen) fprintf(screen,str,ndelete,atom->natoms); + if (logfile) fprintf(logfile,str,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("Illegal delete_atoms command"); int igroup = group->find(arg[1]); if (igroup == -1) error->all("Could not find delete_atoms group ID"); options(narg-2,&arg[2]); // allocate and initialize deletion list int nlocal = atom->nlocal; dlist = (int *) memory->smalloc(nlocal*sizeof(int),"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 ------------------------------------------------------------------------- */ void DeleteAtoms::delete_region(int narg, char **arg) { if (narg < 2) error->all("Illegal delete_atoms command"); int iregion = domain->find_region(arg[1]); if (iregion == -1) error->all("Could not find delete_atoms region ID"); options(narg-2,&arg[2]); // allocate and initialize deletion list int nlocal = atom->nlocal; dlist = (int *) memory->smalloc(nlocal*sizeof(int),"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; } /* ---------------------------------------------------------------------- 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("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("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("Delete_atoms requires a pair style be defined"); if (cut > neighbor->cutneighmax) error->all("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; dlist = (int *) memory->smalloc(nlocal*sizeof(int),"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; int nall = atom->nlocal + atom->nghost; 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; 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]; // if 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 (j >= nall) { if (special_coul[j/nall] == 0.0 && special_lj[j/nall] == 0.0) continue; j %= nall; } // 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("Illegal delete_atoms command"); int iregion = domain->find_region(arg[1]); if (iregion == -1) error->all("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; dlist = (int *) memory->smalloc(nlocal*sizeof(int),"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; int iarg = 0; while (iarg < narg) { if (strcmp(arg[iarg],"compress") == 0) { if (iarg+2 > narg) error->all("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("Illegal delete_bonds command"); iarg += 2; } else error->all("Illegal delete_bonds command"); } } diff --git a/src/delete_bonds.cpp b/src/delete_bonds.cpp index b2c80cd8f..0b1ff6dae 100644 --- a/src/delete_bonds.cpp +++ b/src/delete_bonds.cpp @@ -1,486 +1,486 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ #include "mpi.h" #include "stdlib.h" #include "string.h" #include "delete_bonds.h" #include "atom.h" #include "atom_vec.h" #include "domain.h" #include "neighbor.h" #include "comm.h" #include "force.h" #include "group.h" #include "special.h" #include "error.h" using namespace LAMMPS_NS; enum{MULTI,ATOM,BOND,ANGLE,DIHEDRAL,IMPROPER,STATS}; /* ---------------------------------------------------------------------- */ DeleteBonds::DeleteBonds(LAMMPS *lmp) : Pointers(lmp) {} /* ---------------------------------------------------------------------- */ void DeleteBonds::command(int narg, char **arg) { if (domain->box_exist == 0) error->all("Delete_bonds command before simulation box is defined"); if (atom->natoms == 0) error->all("Delete_bonds command with no atoms existing"); if (atom->molecular == 0) error->all("Cannot use delete_bonds with non-molecular system"); if (narg < 2) error->all("Illegal delete_bonds command"); // init entire system since comm->borders is done // comm::init needs neighbor::init needs pair::init needs kspace::init, etc if (comm->me == 0 && screen) fprintf(screen,"System init for delete_bonds ...\n"); lmp->init(); if (comm->me == 0 && screen) fprintf(screen,"Deleting bonds ...\n"); // identify group int igroup = group->find(arg[0]); if (igroup == -1) error->all("Cannot find delete_bonds group ID"); int groupbit = group->bitmask[igroup]; // set style and which = type value int style; if (strcmp(arg[1],"multi") == 0) style = MULTI; else if (strcmp(arg[1],"atom") == 0) style = ATOM; else if (strcmp(arg[1],"bond") == 0) style = BOND; else if (strcmp(arg[1],"angle") == 0) style = ANGLE; else if (strcmp(arg[1],"dihedral") == 0) style = DIHEDRAL; else if (strcmp(arg[1],"improper") == 0) style = IMPROPER; else if (strcmp(arg[1],"stats") == 0) style = STATS; else error->all("Illegal delete_bonds command"); int iarg = 2; int which; if (style != MULTI && style != STATS) { if (narg < 3) error->all("Illegal delete_bonds command"); which = atoi(arg[2]); iarg++; } // grab optional keywords int undo_flag = 0; int remove_flag = 0; int special_flag = 0; while (iarg < narg) { if (strcmp(arg[iarg],"undo") == 0) undo_flag = 1; else if (strcmp(arg[iarg],"remove") == 0) remove_flag = 1; else if (strcmp(arg[iarg],"special") == 0) special_flag = 1; else error->all("Illegal delete_bonds command"); iarg++; } // border swap to insure type and mask is current for off-proc atoms // enforce PBC before in case atoms are outside box if (domain->triclinic) domain->x2lamda(atom->nlocal); domain->pbc(); domain->reset_box(); comm->setup(); comm->exchange(); comm->borders(); if (domain->triclinic) domain->lamda2x(atom->nlocal+atom->nghost); // set topology interactions either off or on // criteria for an interaction to potentially be changed (set flag = 1) // all atoms in interaction must be in group // for style = MULTI, no other criteria // for style = ATOM, at least one atom is specified type // for style = BOND/ANGLE/DIHEDRAL/IMPROPER, interaction is specified type // for style = STATS only compute stats, flag is always 0 // if flag = 1 // set interaction type negative if undo_flag = 0 // set interaction type positive if undo_flag = 1 int *mask = atom->mask; int *type = atom->type; int nlocal = atom->nlocal; int i,m,n,flag; int atom1,atom2,atom3,atom4; if (atom->avec->bonds_allow) { int *num_bond = atom->num_bond; int **bond_type = atom->bond_type; for (i = 0; i < nlocal; i++) { for (m = 0; m < num_bond[i]; m++) { atom1 = atom->map(atom->bond_atom[i][m]); if (atom1 == -1) error->one("Bond atom missing in delete_bonds"); if (mask[i] & groupbit && mask[atom1] & groupbit) { flag = 0; if (style == MULTI) flag = 1; if (style == ATOM && (type[i] == which || type[atom1] == which)) flag = 1; if (style == BOND && (bond_type[i][m] == which)) flag = 1; if (flag) { if (undo_flag == 0 && bond_type[i][m] > 0) bond_type[i][m] = -bond_type[i][m]; if (undo_flag == 1 && bond_type[i][m] < 0) bond_type[i][m] = -bond_type[i][m]; } } } } } if (atom->avec->angles_allow) { int *num_angle = atom->num_angle; int **angle_type = atom->angle_type; for (i = 0; i < nlocal; i++) { for (m = 0; m < num_angle[i]; m++) { atom1 = atom->map(atom->angle_atom1[i][m]); atom2 = atom->map(atom->angle_atom2[i][m]); atom3 = atom->map(atom->angle_atom3[i][m]); if (atom1 == -1 || atom2 == -1 || atom3 == -1) error->one("Angle atom missing in delete_bonds"); if (mask[atom1] & groupbit && mask[atom2] & groupbit && mask[atom3] & groupbit) { flag = 0; if (style == MULTI) flag = 1; if (style == ATOM && (type[atom1] == which || type[atom2] == which || type[atom3] == which)) flag = 1; if (style == ANGLE && (angle_type[i][m] == which)) flag = 1; if (flag) { if (undo_flag == 0 && angle_type[i][m] > 0) angle_type[i][m] = -angle_type[i][m]; if (undo_flag == 1 && angle_type[i][m] < 0) angle_type[i][m] = -angle_type[i][m]; } } } } } if (atom->avec->dihedrals_allow) { int *num_dihedral = atom->num_dihedral; int **dihedral_type = atom->dihedral_type; for (i = 0; i < nlocal; i++) { for (m = 0; m < num_dihedral[i]; m++) { atom1 = atom->map(atom->dihedral_atom1[i][m]); atom2 = atom->map(atom->dihedral_atom2[i][m]); atom3 = atom->map(atom->dihedral_atom3[i][m]); atom4 = atom->map(atom->dihedral_atom4[i][m]); if (atom1 == -1 || atom2 == -1 || atom3 == -1 || atom4 == -1) error->one("Dihedral atom missing in delete_bonds"); if (mask[atom1] & groupbit && mask[atom2] & groupbit && mask[atom3] & groupbit && mask[atom4] & groupbit) { flag = 0; if (style == MULTI) flag = 1; if (style == ATOM && (type[atom1] == which || type[atom2] == which || type[atom3] == which || type[atom4] == which)) flag = 1; if (style == DIHEDRAL && (dihedral_type[i][m] == which)) flag = 1; if (flag) { if (undo_flag == 0 && dihedral_type[i][m] > 0) dihedral_type[i][m] = -dihedral_type[i][m]; if (undo_flag == 1 && dihedral_type[i][m] < 0) dihedral_type[i][m] = -dihedral_type[i][m]; } } } } } if (atom->avec->impropers_allow) { int *num_improper = atom->num_improper; int **improper_type = atom->improper_type; for (i = 0; i < nlocal; i++) { for (m = 0; m < num_improper[i]; m++) { atom1 = atom->map(atom->improper_atom1[i][m]); atom2 = atom->map(atom->improper_atom2[i][m]); atom3 = atom->map(atom->improper_atom3[i][m]); atom4 = atom->map(atom->improper_atom4[i][m]); if (atom1 == -1 || atom2 == -1 || atom3 == -1 || atom4 == -1) error->one("Improper atom missing in delete_bonds"); if (mask[atom1] & groupbit && mask[atom2] & groupbit && mask[atom3] & groupbit && mask[atom4] & groupbit) { flag = 0; if (style == MULTI) flag = 1; if (style == ATOM && (type[atom1] == which || type[atom2] == which || type[atom3] == which || type[atom4] == which)) flag = 1; if (style == IMPROPER && (improper_type[i][m] == which)) flag = 1; if (flag) { if (undo_flag == 0 && improper_type[i][m] > 0) improper_type[i][m] = -improper_type[i][m]; if (undo_flag == 1 && improper_type[i][m] < 0) improper_type[i][m] = -improper_type[i][m]; } } } } } // remove interactions if requested // only if all atoms in bond, angle, etc are in the delete_bonds group if (remove_flag) { if (atom->avec->bonds_allow) { for (i = 0; i < nlocal; i++) { m = 0; while (m < atom->num_bond[i]) { if (atom->bond_type[i][m] <= 0) { atom1 = atom->map(atom->bond_atom[i][m]); if (mask[i] & groupbit && mask[atom1] & groupbit) { n = atom->num_bond[i]; atom->bond_type[i][m] = atom->bond_type[i][n-1]; atom->bond_atom[i][m] = atom->bond_atom[i][n-1]; atom->num_bond[i]--; } else m++; } else m++; } } } if (atom->avec->angles_allow) { for (i = 0; i < nlocal; i++) { m = 0; while (m < atom->num_angle[i]) { if (atom->angle_type[i][m] <= 0) { atom1 = atom->map(atom->angle_atom1[i][m]); atom2 = atom->map(atom->angle_atom2[i][m]); atom3 = atom->map(atom->angle_atom3[i][m]); if (mask[atom1] & groupbit && mask[atom2] & groupbit && mask[atom3] & groupbit) { n = atom->num_angle[i]; atom->angle_type[i][m] = atom->angle_type[i][n-1]; atom->angle_atom1[i][m] = atom->angle_atom1[i][n-1]; atom->angle_atom2[i][m] = atom->angle_atom2[i][n-1]; atom->angle_atom3[i][m] = atom->angle_atom3[i][n-1]; atom->num_angle[i]--; } else m++; } else m++; } } } if (atom->avec->dihedrals_allow) { for (i = 0; i < nlocal; i++) { m = 0; while (m < atom->num_dihedral[i]) { if (atom->dihedral_type[i][m] <= 0) { atom1 = atom->map(atom->dihedral_atom1[i][m]); atom2 = atom->map(atom->dihedral_atom2[i][m]); atom3 = atom->map(atom->dihedral_atom3[i][m]); atom4 = atom->map(atom->dihedral_atom4[i][m]); if (mask[atom1] & groupbit && mask[atom2] & groupbit && mask[atom3] & groupbit && mask[atom4] & groupbit) { n = atom->num_dihedral[i]; atom->dihedral_type[i][m] = atom->dihedral_type[i][n-1]; atom->dihedral_atom1[i][m] = atom->dihedral_atom1[i][n-1]; atom->dihedral_atom2[i][m] = atom->dihedral_atom2[i][n-1]; atom->dihedral_atom3[i][m] = atom->dihedral_atom3[i][n-1]; atom->dihedral_atom4[i][m] = atom->dihedral_atom4[i][n-1]; atom->num_dihedral[i]--; } else m++; } else m++; } } } if (atom->avec->impropers_allow) { for (i = 0; i < nlocal; i++) { m = 0; while (m < atom->num_improper[i]) { if (atom->improper_type[i][m] <= 0) { atom1 = atom->map(atom->improper_atom1[i][m]); atom2 = atom->map(atom->improper_atom2[i][m]); atom3 = atom->map(atom->improper_atom3[i][m]); atom4 = atom->map(atom->improper_atom4[i][m]); if (mask[atom1] & groupbit && mask[atom2] & groupbit && mask[atom3] & groupbit && mask[atom4] & groupbit) { n = atom->num_improper[i]; atom->improper_type[i][m] = atom->improper_type[i][n-1]; atom->improper_atom1[i][m] = atom->improper_atom1[i][n-1]; atom->improper_atom2[i][m] = atom->improper_atom2[i][n-1]; atom->improper_atom3[i][m] = atom->improper_atom3[i][n-1]; atom->improper_atom4[i][m] = atom->improper_atom4[i][n-1]; atom->num_improper[i]--; } else m++; } else m++; } } } } // if interactions were removed, recompute global counts if (remove_flag) { if (atom->avec->bonds_allow) { bigint nbonds = 0; for (i = 0; i < nlocal; i++) nbonds += atom->num_bond[i]; - MPI_Allreduce(&nbonds,&atom->nbonds,1,MPI_UNSIGNED_LONG_LONG, + MPI_Allreduce(&nbonds,&atom->nbonds,1,MPI_LMP_BIGINT, MPI_SUM,world); if (force->newton_bond == 0) atom->nbonds /= 2; } if (atom->avec->angles_allow) { bigint nangles = 0; for (i = 0; i < nlocal; i++) nangles += atom->num_angle[i]; - MPI_Allreduce(&nangles,&atom->nangles,1,MPI_UNSIGNED_LONG_LONG, + MPI_Allreduce(&nangles,&atom->nangles,1,MPI_LMP_BIGINT, MPI_SUM,world); if (force->newton_bond == 0) atom->nangles /= 3; } if (atom->avec->dihedrals_allow) { bigint ndihedrals = 0; for (i = 0; i < nlocal; i++) ndihedrals += atom->num_dihedral[i]; MPI_Allreduce(&ndihedrals,&atom->ndihedrals, - 1,MPI_UNSIGNED_LONG_LONG,MPI_SUM,world); + 1,MPI_LMP_BIGINT,MPI_SUM,world); if (force->newton_bond == 0) atom->ndihedrals /= 4; } if (atom->avec->impropers_allow) { bigint nimpropers = 0; for (i = 0; i < nlocal; i++) nimpropers += atom->num_improper[i]; MPI_Allreduce(&nimpropers,&atom->nimpropers, - 1,MPI_UNSIGNED_LONG_LONG,MPI_SUM,world); + 1,MPI_LMP_BIGINT,MPI_SUM,world); if (force->newton_bond == 0) atom->nimpropers /= 4; } } // compute and print stats bigint tmp; bigint bond_on,bond_off; bigint angle_on,angle_off; bigint dihedral_on,dihedral_off; bigint improper_on,improper_off; if (atom->avec->bonds_allow) { bond_on = bond_off = 0; for (i = 0; i < nlocal; i++) for (m = 0; m < atom->num_bond[i]; m++) if (atom->bond_type[i][m] > 0) bond_on++; else bond_off++; - MPI_Allreduce(&bond_on,&tmp,1,MPI_UNSIGNED_LONG_LONG,MPI_SUM,world); + MPI_Allreduce(&bond_on,&tmp,1,MPI_LMP_BIGINT,MPI_SUM,world); bond_on = tmp; - MPI_Allreduce(&bond_off,&tmp,1,MPI_UNSIGNED_LONG_LONG,MPI_SUM,world); + MPI_Allreduce(&bond_off,&tmp,1,MPI_LMP_BIGINT,MPI_SUM,world); bond_off = tmp; if (force->newton_bond == 0) { bond_on /= 2; bond_off /= 2; } } if (atom->avec->angles_allow) { angle_on = angle_off = 0; for (i = 0; i < nlocal; i++) for (m = 0; m < atom->num_angle[i]; m++) if (atom->angle_type[i][m] > 0) angle_on++; else angle_off++; - MPI_Allreduce(&angle_on,&tmp,1,MPI_UNSIGNED_LONG_LONG,MPI_SUM,world); + MPI_Allreduce(&angle_on,&tmp,1,MPI_LMP_BIGINT,MPI_SUM,world); angle_on = tmp; - MPI_Allreduce(&angle_off,&tmp,1,MPI_UNSIGNED_LONG_LONG,MPI_SUM,world); + MPI_Allreduce(&angle_off,&tmp,1,MPI_LMP_BIGINT,MPI_SUM,world); angle_off = tmp; if (force->newton_bond == 0) { angle_on /= 3; angle_off /= 3; } } if (atom->avec->dihedrals_allow) { dihedral_on = dihedral_off = 0; for (i = 0; i < nlocal; i++) for (m = 0; m < atom->num_dihedral[i]; m++) if (atom->dihedral_type[i][m] > 0) dihedral_on++; else dihedral_off++; - MPI_Allreduce(&dihedral_on,&tmp,1,MPI_UNSIGNED_LONG_LONG,MPI_SUM,world); + MPI_Allreduce(&dihedral_on,&tmp,1,MPI_LMP_BIGINT,MPI_SUM,world); dihedral_on = tmp; - MPI_Allreduce(&dihedral_off,&tmp,1,MPI_UNSIGNED_LONG_LONG,MPI_SUM,world); + MPI_Allreduce(&dihedral_off,&tmp,1,MPI_LMP_BIGINT,MPI_SUM,world); dihedral_off = tmp; if (force->newton_bond == 0) { dihedral_on /= 4; dihedral_off /= 4; } } if (atom->avec->impropers_allow) { improper_on = improper_off = 0; for (i = 0; i < nlocal; i++) for (m = 0; m < atom->num_improper[i]; m++) if (atom->improper_type[i][m] > 0) improper_on++; else improper_off++; - MPI_Allreduce(&improper_on,&tmp,1,MPI_UNSIGNED_LONG_LONG,MPI_SUM,world); + MPI_Allreduce(&improper_on,&tmp,1,MPI_LMP_BIGINT,MPI_SUM,world); improper_on = tmp; - MPI_Allreduce(&improper_off,&tmp,1,MPI_UNSIGNED_LONG_LONG,MPI_SUM,world); + MPI_Allreduce(&improper_off,&tmp,1,MPI_LMP_BIGINT,MPI_SUM,world); improper_off = tmp; if (force->newton_bond == 0) { improper_on /= 4; improper_off /= 4; } } if (comm->me == 0) { - if (screen) { - if (atom->avec->bonds_allow) - fprintf(screen," %lu total bonds, %lu turned on, %lu turned off\n", - atom->nbonds,bond_on,bond_off); - if (atom->avec->angles_allow) - fprintf(screen," %lu total angles, %lu turned on, %lu turned off\n", - atom->nangles,angle_on,angle_off); - if (atom->avec->dihedrals_allow) - fprintf(screen," %lu total dihedrals, %lu turned on, %lu turned off\n", - atom->ndihedrals,dihedral_on,dihedral_off); - if (atom->avec->impropers_allow) - fprintf(screen," %lu total impropers, %lu turned on, %lu turned off\n", - atom->nimpropers,improper_on,improper_off); + if (atom->avec->bonds_allow) { + char str[128]; + sprintf(str," %s total bonds, %s turned on, %s turned off\n", + BIGINT_FORMAT,BIGINT_FORMAT,BIGINT_FORMAT); + if (screen) fprintf(screen,str,atom->nbonds,bond_on,bond_off); + if (logfile) fprintf(logfile,str,atom->nbonds,bond_on,bond_off); + } + if (atom->avec->angles_allow) { + char str[128]; + sprintf(str," %s total angles, %s turned on, %s turned off\n", + BIGINT_FORMAT,BIGINT_FORMAT,BIGINT_FORMAT); + if (screen) fprintf(screen,str,atom->nangles,angle_on,angle_off); + if (logfile) fprintf(logfile,str,atom->nangles,angle_on,angle_off); } - if (logfile) { - if (atom->avec->bonds_allow) - fprintf(logfile," %lu total bonds, %lu turned on, %lu turned off\n", - atom->nbonds,bond_on,bond_off); - if (atom->avec->angles_allow) - fprintf(logfile," %lu total angles, %lu turned on, %lu turned off\n", - atom->nangles,angle_on,angle_off); - if (atom->avec->dihedrals_allow) - fprintf(logfile," %lu total dihedrals, %lu turned on, " - "%lu turned off\n", - atom->ndihedrals,dihedral_on,dihedral_off); - if (atom->avec->impropers_allow) - fprintf(logfile," %lu total impropers, %lu turned on, " - "%lu turned off\n", - atom->nimpropers,improper_on,improper_off); + if (atom->avec->dihedrals_allow) { + char str[128]; + sprintf(str," %s total dihedrals, %s turned on, %s turned off\n", + BIGINT_FORMAT,BIGINT_FORMAT,BIGINT_FORMAT); + if (screen) fprintf(screen,str,atom->ndihedrals,dihedral_on,dihedral_off); + if (logfile) fprintf(logfile,str, + atom->ndihedrals,dihedral_on,dihedral_off); + } + if (atom->avec->impropers_allow) { + char str[128]; + sprintf(str," %s total impropers, %s turned on, %s turned off\n", + BIGINT_FORMAT,BIGINT_FORMAT,BIGINT_FORMAT); + if (screen) fprintf(screen,str,atom->nimpropers,improper_on,improper_off); + if (logfile) fprintf(logfile,str, + atom->nimpropers,improper_on,improper_off); } } // re-compute special list if requested if (special_flag) { Special special(lmp); special.build(); } } diff --git a/src/displace_atoms.cpp b/src/displace_atoms.cpp index 4a9be6df2..1e93c919b 100644 --- a/src/displace_atoms.cpp +++ b/src/displace_atoms.cpp @@ -1,243 +1,244 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ #include "mpi.h" #include "stdlib.h" #include "string.h" #include "displace_atoms.h" #include "lmptype.h" #include "atom.h" #include "modify.h" #include "domain.h" #include "lattice.h" #include "comm.h" #include "irregular.h" #include "group.h" #include "random_park.h" #include "error.h" using namespace LAMMPS_NS; enum{MOVE,RAMP,RANDOM}; #define MIN(a,b) ((a) < (b) ? (a) : (b)) #define MAX(a,b) ((a) > (b) ? (a) : (b)) /* ---------------------------------------------------------------------- */ DisplaceAtoms::DisplaceAtoms(LAMMPS *lmp) : Pointers(lmp) {} /* ---------------------------------------------------------------------- */ void DisplaceAtoms::command(int narg, char **arg) { int i; if (domain->box_exist == 0) error->all("Displace_atoms command before simulation box is defined"); if (narg < 2) error->all("Illegal displace_atoms command"); if (modify->nfix_restart_peratom) error->all("Cannot displace_atoms after " "reading restart file with per-atom info"); if (comm->me == 0 && screen) fprintf(screen,"Displacing atoms ...\n"); // group and style int igroup = group->find(arg[0]); if (igroup == -1) error->all("Could not find displace_atoms group ID"); int groupbit = group->bitmask[igroup]; int style; if (strcmp(arg[1],"move") == 0) style = MOVE; else if (strcmp(arg[1],"ramp") == 0) style = RAMP; else if (strcmp(arg[1],"random") == 0) style = RANDOM; else error->all("Illegal displace_atoms command"); // set option defaults scaleflag = 1; // read options from end of input line if (style == MOVE) options(narg-5,&arg[5]); else if (style == RAMP) options(narg-8,&arg[8]); else if (style == RANDOM) options(narg-6,&arg[6]); // setup scaling if (scaleflag && domain->lattice == NULL) error->all("Use of displace_atoms with undefined lattice"); double xscale,yscale,zscale; if (scaleflag) { xscale = domain->lattice->xlattice; yscale = domain->lattice->ylattice; zscale = domain->lattice->zlattice; } else xscale = yscale = zscale = 1.0; // move atoms by 3-vector if (style == MOVE) { double delx = xscale*atof(arg[2]); double dely = yscale*atof(arg[3]); double delz = zscale*atof(arg[4]); double **x = atom->x; int *mask = atom->mask; int nlocal = atom->nlocal; for (i = 0; i < nlocal; i++) { if (mask[i] & groupbit) { x[i][0] += delx; x[i][1] += dely; x[i][2] += delz; } } } // move atoms in ramped fashion if (style == RAMP) { int d_dim; if (strcmp(arg[2],"x") == 0) d_dim = 0; else if (strcmp(arg[2],"y") == 0) d_dim = 1; else if (strcmp(arg[2],"z") == 0) d_dim = 2; else error->all("Illegal displace_atoms ramp command"); double d_lo,d_hi; if (d_dim == 0) { d_lo = xscale*atof(arg[3]); d_hi = xscale*atof(arg[4]); } else if (d_dim == 1) { d_lo = yscale*atof(arg[3]); d_hi = yscale*atof(arg[4]); } else if (d_dim == 2) { d_lo = zscale*atof(arg[3]); d_hi = zscale*atof(arg[4]); } int coord_dim; if (strcmp(arg[5],"x") == 0) coord_dim = 0; else if (strcmp(arg[5],"y") == 0) coord_dim = 1; else if (strcmp(arg[5],"z") == 0) coord_dim = 2; else error->all("Illegal displace_atoms ramp command"); double coord_lo,coord_hi; if (coord_dim == 0) { coord_lo = xscale*atof(arg[6]); coord_hi = xscale*atof(arg[7]); } else if (coord_dim == 1) { coord_lo = yscale*atof(arg[6]); coord_hi = yscale*atof(arg[7]); } else if (coord_dim == 2) { coord_lo = zscale*atof(arg[6]); coord_hi = zscale*atof(arg[7]); } double **x = atom->x; int *mask = atom->mask; int nlocal = atom->nlocal; double fraction,dramp; for (i = 0; i < nlocal; i++) { if (mask[i] & groupbit) { fraction = (x[i][coord_dim] - coord_lo) / (coord_hi - coord_lo); fraction = MAX(fraction,0.0); fraction = MIN(fraction,1.0); dramp = d_lo + fraction*(d_hi - d_lo); x[i][d_dim] += dramp; } } } // move atoms randomly // makes atom result independent of what proc owns it via random->reset() if (style == RANDOM) { RanPark *random = new RanPark(lmp,1); double dx = xscale*atof(arg[2]); double dy = yscale*atof(arg[3]); double dz = zscale*atof(arg[4]); int seed = atoi(arg[5]); if (seed <= 0) error->all("Illegal displace_atoms random command"); double **x = atom->x; int *mask = atom->mask; int nlocal = atom->nlocal; for (i = 0; i < nlocal; i++) { if (mask[i] & groupbit) { random->reset(seed,x[i]); x[i][0] += dx * 2.0*(random->uniform()-0.5); x[i][1] += dy * 2.0*(random->uniform()-0.5); x[i][2] += dz * 2.0*(random->uniform()-0.5); } } delete random; } // move atoms back inside simulation box and to new processors // use remap() instead of pbc() in case atoms moved a long distance // use irregular() in case atoms moved a long distance double **x = atom->x; int *image = atom->image; int nlocal = atom->nlocal; for (i = 0; i < nlocal; i++) domain->remap(x[i],image[i]); if (domain->triclinic) domain->x2lamda(atom->nlocal); domain->reset_box(); Irregular *irregular = new Irregular(lmp); irregular->migrate_atoms(); delete irregular; if (domain->triclinic) domain->lamda2x(atom->nlocal); // check if any atoms were lost bigint natoms; bigint nblocal = atom->nlocal; - MPI_Allreduce(&nblocal,&natoms,1,MPI_UNSIGNED_LONG_LONG,MPI_SUM,world); + MPI_Allreduce(&nblocal,&natoms,1,MPI_LMP_BIGINT,MPI_SUM,world); if (natoms != atom->natoms) { - char str[128]; - sprintf(str,"Lost atoms via displace_atoms: original %lu current %lu", - atom->natoms,natoms); + char fstr[64],str[128]; + sprintf(fstr,"Lost atoms via displace_atoms: original %s current %s", + BIGINT_FORMAT,BIGINT_FORMAT); + sprintf(str,fstr,atom->natoms,natoms); error->all(str); } } /* ---------------------------------------------------------------------- parse optional parameters at end of displace_atoms input line ------------------------------------------------------------------------- */ void DisplaceAtoms::options(int narg, char **arg) { if (narg < 0) error->all("Illegal displace_atoms command"); int iarg = 0; while (iarg < narg) { if (strcmp(arg[iarg],"units") == 0) { if (iarg+2 > narg) error->all("Illegal displace_atoms command"); if (strcmp(arg[iarg+1],"box") == 0) scaleflag = 0; else if (strcmp(arg[iarg+1],"lattice") == 0) scaleflag = 1; else error->all("Illegal displace_atoms command"); iarg += 2; } else error->all("Illegal displace_atoms command"); } } diff --git a/src/displace_box.cpp b/src/displace_box.cpp index 33d1a3137..e80ddbbd3 100644 --- a/src/displace_box.cpp +++ b/src/displace_box.cpp @@ -1,418 +1,419 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ #include "mpi.h" #include "math.h" #include "stdlib.h" #include "string.h" #include "displace_box.h" #include "lmptype.h" #include "atom.h" #include "modify.h" #include "domain.h" #include "lattice.h" #include "comm.h" #include "irregular.h" #include "group.h" #include "error.h" using namespace LAMMPS_NS; enum{NONE,FINAL,DELTA,SCALE,VOLUME}; enum{ONE_FROM_ONE,ONE_FROM_TWO,TWO_FROM_ONE}; enum{NO_REMAP,X_REMAP}; /* ---------------------------------------------------------------------- */ DisplaceBox::DisplaceBox(LAMMPS *lmp) : Pointers(lmp) {} /* ---------------------------------------------------------------------- */ void DisplaceBox::command(int narg, char **arg) { int i; if (domain->box_exist == 0) error->all("Displace_box command before simulation box is defined"); if (narg < 2) error->all("Illegal displace_box command"); if (modify->nfix_restart_peratom) error->all("Cannot displace_box after " "reading restart file with per-atom info"); if (comm->me == 0 && screen) fprintf(screen,"Displacing box ...\n"); // group int igroup = group->find(arg[0]); if (igroup == -1) error->all("Could not find displace_box group ID"); int groupbit = group->bitmask[igroup]; // set defaults set = new Set[6]; set[0].style = set[1].style = set[2].style = set[3].style = set[4].style = set[5].style = NONE; // parse arguments int triclinic = domain->triclinic; int index; int iarg = 1; while (iarg < narg) { if (strcmp(arg[iarg],"x") == 0 || strcmp(arg[iarg],"y") == 0 || strcmp(arg[iarg],"z") == 0) { if (strcmp(arg[iarg],"x") == 0) index = 0; else if (strcmp(arg[iarg],"y") == 0) index = 1; else if (strcmp(arg[iarg],"z") == 0) index = 2; if (iarg+2 > narg) error->all("Illegal displace_box command"); if (strcmp(arg[iarg+1],"final") == 0) { if (iarg+4 > narg) error->all("Illegal displace_box command"); set[index].style = FINAL; set[index].flo = atof(arg[iarg+2]); set[index].fhi = atof(arg[iarg+3]); iarg += 4; } else if (strcmp(arg[iarg+1],"delta") == 0) { if (iarg+4 > narg) error->all("Illegal displace_box command"); set[index].style = DELTA; set[index].dlo = atof(arg[iarg+2]); set[index].dhi = atof(arg[iarg+3]); iarg += 4; } else if (strcmp(arg[iarg+1],"scale") == 0) { if (iarg+3 > narg) error->all("Illegal displace_box command"); set[index].style = SCALE; set[index].scale = atof(arg[iarg+2]); iarg += 3; } else if (strcmp(arg[iarg+1],"volume") == 0) { set[index].style = VOLUME; iarg += 2; } else error->all("Illegal displace_box command"); } else if (strcmp(arg[iarg],"xy") == 0 || strcmp(arg[iarg],"xz") == 0 || strcmp(arg[iarg],"yz") == 0) { if (triclinic == 0) error->all("Displace_box tilt factors require triclinic box"); if (strcmp(arg[iarg],"xy") == 0) index = 5; else if (strcmp(arg[iarg],"xz") == 0) index = 4; else if (strcmp(arg[iarg],"yz") == 0) index = 3; if (iarg+2 > narg) error->all("Illegal displace_box command"); if (strcmp(arg[iarg+1],"final") == 0) { if (iarg+3 > narg) error->all("Illegal displace_box command"); set[index].style = FINAL; set[index].ftilt = atof(arg[iarg+2]); iarg += 3; } else if (strcmp(arg[iarg+1],"delta") == 0) { if (iarg+3 > narg) error->all("Illegal displace_box command"); set[index].style = DELTA; set[index].dtilt = atof(arg[iarg+2]); iarg += 3; } else error->all("Illegal displace_box command"); } else break; } // read options from end of input line options(narg-iarg,&arg[iarg]); // check periodicity if ((set[0].style && domain->xperiodic == 0) || (set[1].style && domain->yperiodic == 0) || (set[2].style && domain->zperiodic == 0)) error->all("Cannot displace_box on a non-periodic boundary"); if (set[3].style && (domain->yperiodic == 0 || domain->zperiodic == 0)) error->all("Cannot displace_box on a non-periodic boundary"); if (set[4].style && (domain->xperiodic == 0 || domain->zperiodic == 0)) error->all("Cannot displace_box on a non-periodic boundary"); if (set[5].style && (domain->xperiodic == 0 || domain->yperiodic == 0)) error->all("Cannot displace_box on a non-periodic boundary"); // apply scaling to FINAL,DELTA since they have distance units int flag = 0; for (int i = 0; i < 6; i++) if (set[i].style == FINAL || set[i].style == DELTA) flag = 1; if (flag && scaleflag && domain->lattice == NULL) error->all("Use of displace_box with undefined lattice"); double xscale,yscale,zscale; if (flag && scaleflag) { xscale = domain->lattice->xlattice; yscale = domain->lattice->ylattice; zscale = domain->lattice->zlattice; } else xscale = yscale = zscale = 1.0; // for 3,4,5 scaling is in 1st dimension, e.g. x for xz double map[6]; map[0] = xscale; map[1] = yscale; map[2] = zscale; map[3] = yscale; map[4] = xscale; map[5] = xscale; for (int i = 0; i < 3; i++) { if (set[i].style == FINAL) { set[i].flo *= map[i]; set[i].fhi *= map[i]; } else if (set[i].style == DELTA) { set[i].dlo *= map[i]; set[i].dhi *= map[i]; } } for (int i = 3; i < 6; i++) { if (set[i].style == FINAL) set[i].ftilt *= map[i]; else if (set[i].style == DELTA) set[i].dtilt *= map[i]; } // set initial/final values for box size and shape // final = initial if no setting for (int i = 0; i < 3; i++) { set[i].lo_stop = set[i].lo_start = domain->boxlo[i]; set[i].hi_stop = set[i].hi_start = domain->boxhi[i]; if (set[i].style == FINAL) { set[i].lo_stop = set[i].flo; set[i].hi_stop = set[i].fhi; } else if (set[i].style == DELTA) { set[i].lo_stop = set[i].lo_start + set[i].dlo; set[i].hi_stop = set[i].hi_start + set[i].dhi; } else if (set[i].style == SCALE) { set[i].lo_stop = 0.5*(set[i].lo_start+set[i].hi_start) - 0.5*set[i].scale*(set[i].hi_start-set[i].lo_start); set[i].hi_stop = 0.5*(set[i].lo_start+set[i].hi_start) + 0.5*set[i].scale*(set[i].hi_start-set[i].lo_start); } } for (int i = 3; i < 6; i++) { if (i == 5) set[i].tilt_start = domain->xy; else if (i == 4) set[i].tilt_start = domain->xz; else if (i == 3) set[i].tilt_start = domain->yz; set[i].tilt_stop = set[i].tilt_start; if (set[i].style == FINAL) { set[i].tilt_stop = set[i].ftilt; } else if (set[i].style == DELTA) { set[i].tilt_stop = set[i].tilt_start + set[i].dtilt; } } // for VOLUME, setup links to other dims // fixed, dynamic1,2, vol_start for (int i = 0; i < 3; i++) { set[i].vol_start = domain->xprd * domain->yprd * domain->zprd; if (set[i].style != VOLUME) continue; int other1 = (i+1) % 3; int other2 = (i+2) % 3; if (set[other1].style == NONE) { if (set[other2].style == NONE || set[other2].style == VOLUME) error->all("Fix deform volume setting is invalid"); set[i].substyle = ONE_FROM_ONE; set[i].fixed = other1; set[i].dynamic1 = other2; } else if (set[other2].style == NONE) { if (set[other1].style == NONE || set[other1].style == VOLUME) error->all("Fix deform volume setting is invalid"); set[i].substyle = ONE_FROM_ONE; set[i].fixed = other2; set[i].dynamic1 = other1; } else if (set[other1].style == VOLUME) { if (set[other2].style == NONE || set[other2].style == VOLUME) error->all("Fix deform volume setting is invalid"); set[i].substyle = TWO_FROM_ONE; set[i].fixed = other1; set[i].dynamic1 = other2; } else if (set[other2].style == VOLUME) { if (set[other1].style == NONE || set[other1].style == VOLUME) error->all("Fix deform volume setting is invalid"); set[i].substyle = TWO_FROM_ONE; set[i].fixed = other2; set[i].dynamic1 = other1; } else { set[i].substyle = ONE_FROM_TWO; set[i].dynamic2 = other1; set[i].dynamic2 = other2; } } // set new box size for VOLUME dims that are linked to other dims for (int i = 0; i < 3; i++) { if (set[i].style != VOLUME) continue; if (set[i].substyle == ONE_FROM_ONE) { set[i].lo_stop = 0.5*(set[i].lo_start+set[i].hi_start) - 0.5*(set[i].vol_start / (set[set[i].dynamic1].hi_stop - set[set[i].dynamic1].lo_stop) / (set[set[i].fixed].hi_start-set[set[i].fixed].lo_start)); set[i].hi_stop = 0.5*(set[i].lo_start+set[i].hi_start) + 0.5*(set[i].vol_start / (set[set[i].dynamic1].hi_stop - set[set[i].dynamic1].lo_stop) / (set[set[i].fixed].hi_start-set[set[i].fixed].lo_start)); } else if (set[i].substyle == ONE_FROM_TWO) { set[i].lo_stop = 0.5*(set[i].lo_start+set[i].hi_start) - 0.5*(set[i].vol_start / (set[set[i].dynamic1].hi_stop - set[set[i].dynamic1].lo_stop) / (set[set[i].dynamic2].hi_stop - set[set[i].dynamic2].lo_stop)); set[i].hi_stop = 0.5*(set[i].lo_start+set[i].hi_start) + 0.5*(set[i].vol_start / (set[set[i].dynamic1].hi_stop - set[set[i].dynamic1].lo_stop) / (set[set[i].dynamic2].hi_stop - set[set[i].dynamic2].lo_stop)); } else if (set[i].substyle == TWO_FROM_ONE) { set[i].lo_stop = 0.5*(set[i].lo_start+set[i].hi_start) - 0.5*sqrt(set[i].vol_start / (set[set[i].dynamic1].hi_stop - set[set[i].dynamic1].lo_stop) / (set[set[i].fixed].hi_start - set[set[i].fixed].lo_start) * (set[i].hi_start - set[i].lo_start)); set[i].hi_stop = 0.5*(set[i].lo_start+set[i].hi_start) + 0.5*sqrt(set[i].vol_start / (set[set[i].dynamic1].hi_stop - set[set[i].dynamic1].lo_stop) / (set[set[i].fixed].hi_start - set[set[i].fixed].lo_start) * (set[i].hi_start - set[i].lo_start)); } } // check that final tilt is not illegal value double xprd_stop = set[0].hi_stop - set[0].lo_stop; double yprd_stop = set[0].hi_stop - set[0].lo_stop; if (set[3].tilt_stop < -0.5*yprd_stop || set[3].tilt_stop > 0.5*yprd_stop || set[4].tilt_stop < -0.5*xprd_stop || set[4].tilt_stop > 0.5*xprd_stop || set[5].tilt_stop < -0.5*xprd_stop || set[5].tilt_stop > 0.5*xprd_stop) error->all("Induced tilt by displace_box is too large"); // convert atoms to lamda coords if (remapflag == X_REMAP) { double **x = atom->x; int *mask = atom->mask; int nlocal = atom->nlocal; for (i = 0; i < nlocal; i++) if (mask[i] & groupbit) domain->x2lamda(x[i],x[i]); } // reset global and local box to new size/shape domain->boxlo[0] = set[0].lo_stop; domain->boxlo[1] = set[1].lo_stop; domain->boxlo[2] = set[2].lo_stop; domain->boxhi[0] = set[0].hi_stop; domain->boxhi[1] = set[1].hi_stop; domain->boxhi[2] = set[2].hi_stop; if (triclinic) { domain->yz = set[3].tilt_stop; domain->xz = set[4].tilt_stop; domain->xy = set[5].tilt_stop; } domain->set_global_box(); domain->set_local_box(); // convert atoms back to box coords if (remapflag == X_REMAP) { double **x = atom->x; int *mask = atom->mask; int nlocal = atom->nlocal; for (i = 0; i < nlocal; i++) if (mask[i] & groupbit) domain->lamda2x(x[i],x[i]); } // move atoms back inside simulation box and to new processors // use remap() instead of pbc() // in case box moved a long distance relative to atoms // use irregular() in case box moved a long distance relative to atoms double **x = atom->x; int *image = atom->image; int nlocal = atom->nlocal; for (i = 0; i < nlocal; i++) domain->remap(x[i],image[i]); if (domain->triclinic) domain->x2lamda(atom->nlocal); domain->reset_box(); Irregular *irregular = new Irregular(lmp); irregular->migrate_atoms(); delete irregular; if (domain->triclinic) domain->lamda2x(atom->nlocal); // clean up delete [] set; // check if any atoms were lost bigint natoms; bigint nblocal = atom->nlocal; - MPI_Allreduce(&nblocal,&natoms,1,MPI_UNSIGNED_LONG_LONG,MPI_SUM,world); + MPI_Allreduce(&nblocal,&natoms,1,MPI_LMP_BIGINT,MPI_SUM,world); if (natoms != atom->natoms) { - char str[128]; - sprintf(str,"Lost atoms via displace_box: original %lu current %lu", - atom->natoms,natoms); + char fstr[64],str[128]; + sprintf(fstr,"Lost atoms via displace_box: original %s current %s", + BIGINT_FORMAT,BIGINT_FORMAT); + sprintf(str,fstr,atom->natoms,natoms); error->all(str); } } /* ---------------------------------------------------------------------- parse optional parameters at end of displace_box input line ------------------------------------------------------------------------- */ void DisplaceBox::options(int narg, char **arg) { if (narg < 0) error->all("Illegal displace_box command"); remapflag = X_REMAP; scaleflag = 1; int iarg = 0; while (iarg < narg) { if (strcmp(arg[iarg],"remap") == 0) { if (iarg+2 > narg) error->all("Illegal displace_box command"); if (strcmp(arg[iarg+1],"x") == 0) remapflag = X_REMAP; else if (strcmp(arg[iarg+1],"none") == 0) remapflag = NO_REMAP; else error->all("Illegal displace_box command"); iarg += 2; } else if (strcmp(arg[iarg],"units") == 0) { if (iarg+2 > narg) error->all("Illegal displace_box command"); if (strcmp(arg[iarg+1],"box") == 0) scaleflag = 0; else if (strcmp(arg[iarg+1],"lattice") == 0) scaleflag = 1; else error->all("Illegal displace_box command"); iarg += 2; } else error->all("Illegal displace_box command"); } } diff --git a/src/dump.cpp b/src/dump.cpp index 76708f01e..a382c7fa9 100644 --- a/src/dump.cpp +++ b/src/dump.cpp @@ -1,707 +1,713 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ #include "mpi.h" #include "stdlib.h" #include "string.h" #include "stdio.h" #include "dump.h" #include "lmptype.h" #include "atom.h" #include "irregular.h" #include "update.h" #include "domain.h" #include "group.h" #include "output.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; // allocate space for static class variable Dump *Dump::dumpptr; #define BIG 1.0e20 #define IBIG 2147483647 #define EPSILON 1.0e-6 #define MIN(A,B) ((A) < (B)) ? (A) : (B) #define MAX(A,B) ((A) > (B)) ? (A) : (B) enum{ASCEND,DESCEND}; /* ---------------------------------------------------------------------- */ Dump::Dump(LAMMPS *lmp, int narg, char **arg) : Pointers(lmp) { MPI_Comm_rank(world,&me); MPI_Comm_size(world,&nprocs); int n = strlen(arg[0]) + 1; id = new char[n]; strcpy(id,arg[0]); igroup = group->find(arg[1]); groupbit = group->bitmask[igroup]; n = strlen(arg[2]) + 1; style = new char[n]; strcpy(style,arg[2]); n = strlen(arg[4]) + 1; filename = new char[n]; strcpy(filename,arg[4]); first_flag = 0; flush_flag = 1; format = NULL; format_user = NULL; clearstep = 0; sort_flag = 0; append_flag = 0; maxbuf = maxids = maxsort = maxproc = 0; buf = bufsort = NULL; ids = idsort = index = proclist = NULL; irregular = NULL; // parse filename for special syntax // if contains '%', write one file per proc and replace % with proc-ID // if contains '*', write one file per timestep and replace * with timestep // check file suffixes // if ends in .bin = binary file // else if ends in .gz = gzipped text file // else ASCII text file fp = NULL; singlefile_opened = 0; compressed = 0; binary = 0; multifile = 0; multiproc = 0; char *ptr; if (ptr = strchr(filename,'%')) { multiproc = 1; char *extend = new char[strlen(filename) + 16]; *ptr = '\0'; sprintf(extend,"%s%d%s",filename,me,ptr+1); delete [] filename; n = strlen(extend) + 1; filename = new char[n]; strcpy(filename,extend); delete [] extend; } if (strchr(filename,'*')) multifile = 1; char *suffix = filename + strlen(filename) - strlen(".bin"); if (suffix > filename && strcmp(suffix,".bin") == 0) binary = 1; suffix = filename + strlen(filename) - strlen(".gz"); if (suffix > filename && strcmp(suffix,".gz") == 0) compressed = 1; } /* ---------------------------------------------------------------------- */ Dump::~Dump() { delete [] id; delete [] style; delete [] filename; delete [] format; delete [] format_default; delete [] format_user; memory->sfree(buf); memory->sfree(bufsort); memory->sfree(ids); memory->sfree(idsort); memory->sfree(index); memory->sfree(proclist); delete irregular; // XTC style sets fp to NULL since it closes file in its destructor if (multifile == 0 && fp != NULL) { if (compressed) { if (multiproc) pclose(fp); else if (me == 0) pclose(fp); } else { if (multiproc) fclose(fp); else if (me == 0) fclose(fp); } } } /* ---------------------------------------------------------------------- */ void Dump::init() { init_style(); if (!sort_flag) { memory->sfree(bufsort); memory->sfree(ids); memory->sfree(idsort); memory->sfree(index); memory->sfree(proclist); delete irregular; maxids = maxsort = maxproc = 0; bufsort = NULL; ids = idsort = index = proclist = NULL; irregular = NULL; } if (sort_flag) { if (sortcol == 0 && atom->tag_enable == 0) error->all("Cannot dump sort on atom IDs with no atom IDs defined"); if (sortcol && sortcol > size_one) error->all("Dump sort column is invalid"); if (nprocs > 1 && irregular == NULL) irregular = new Irregular(lmp); bigint size = group->count(igroup); - if (size > MAXINT32) error->all("Too many atoms to dump sort"); + if (size > MAXSMALLINT) error->all("Too many atoms to dump sort"); // set reorderflag = 1 if can simply reorder local atoms rather than sort // criteria: sorting by ID, atom IDs are consecutive from 1 to Natoms // min/max IDs of group match size of group // compute ntotal_reorder, nme_reorder, idlo/idhi to test against later reorderflag = 0; if (sortcol == 0 && atom->tag_consecutive()) { int *tag = atom->tag; int *mask = atom->mask; int nlocal = atom->nlocal; int min = IBIG; int max = 0; for (int i = 0; i < nlocal; i++) if (mask[i] & groupbit) { min = MIN(min,tag[i]); max = MAX(max,tag[i]); } int minall,maxall; MPI_Allreduce(&min,&minall,1,MPI_INT,MPI_MIN,world); MPI_Allreduce(&max,&maxall,1,MPI_INT,MPI_MAX,world); int isize = static_cast<int> (size); if (maxall-minall+1 == isize) { reorderflag = 1; double range = maxall-minall + EPSILON; idlo = static_cast<int> (range*me/nprocs + minall); int idhi = static_cast<int> (range*(me+1)/nprocs + minall); int lom1 = static_cast<int> ((idlo-1-minall)/range * nprocs); int lo = static_cast<int> ((idlo-minall)/range * nprocs); int him1 = static_cast<int> ((idhi-1-minall)/range * nprocs); int hi = static_cast<int> ((idhi-minall)/range * nprocs); if (me && me == lom1) idlo--; else if (me && me != lo) idlo++; if (me+1 == him1) idhi--; else if (me+1 != hi) idhi++; nme_reorder = idhi-idlo; ntotal_reorder = isize; } } } } /* ---------------------------------------------------------------------- */ void Dump::write() { // if file per timestep, open new file if (multifile) openfile(); // simulation box bounds if (domain->triclinic == 0) { boxxlo = domain->boxlo[0]; boxxhi = domain->boxhi[0]; boxylo = domain->boxlo[1]; boxyhi = domain->boxhi[1]; boxzlo = domain->boxlo[2]; boxzhi = domain->boxhi[2]; } else { boxxlo = domain->boxlo_bound[0]; boxxhi = domain->boxhi_bound[0]; boxylo = domain->boxlo_bound[1]; boxyhi = domain->boxhi_bound[1]; boxzlo = domain->boxlo_bound[2]; boxzhi = domain->boxhi_bound[2]; boxxy = domain->xy; boxxz = domain->xz; boxyz = domain->yz; } // nme = # of dump lines this proc will contribute to dump nme = count(); + bigint bnme = nme; // ntotal = total # of dump lines // nmax = max # of dump lines on any proc int nmax; if (multiproc) nmax = nme; else { - MPI_Allreduce(&nme,&ntotal,1,MPI_INT,MPI_SUM,world); + MPI_Allreduce(&bnme,&ntotal,1,MPI_LMP_BIGINT,MPI_SUM,world); MPI_Allreduce(&nme,&nmax,1,MPI_INT,MPI_MAX,world); } // write timestep header - if (multiproc) write_header(nme); + if (multiproc) write_header(bnme); else write_header(ntotal); - // this insures proc 0 can receive everyone's info + // insure proc 0 can receive everyone's info + // limit nmax*size_one to int since used as arg in MPI_Rsend() below // pack my data into buf // if sorting on IDs also request ID list from pack() // sort buf as needed if (nmax > maxbuf) { + if ((bigint) nmax * size_one > MAXSMALLINT) + error->all("Too much per-proc info for dump"); maxbuf = nmax; memory->sfree(buf); buf = (double *) memory->smalloc(maxbuf*size_one*sizeof(double),"dump:buf"); } if (sort_flag && sortcol == 0 && nmax > maxids) { maxids = nmax; memory->sfree(ids); ids = (int *) memory->smalloc(maxids*sizeof(int),"dump:ids"); } if (sort_flag && sortcol == 0) pack(ids); else pack(NULL); if (sort_flag) sort(); // multiproc = 1 = each proc writes own data to own file // multiproc = 0 = all procs write to one file thru proc 0 // proc 0 pings each proc, receives it's data, writes to file // all other procs wait for ping, send their data to proc 0 if (multiproc) write_data(nme,buf); else { int tmp,nlines; MPI_Status status; MPI_Request request; if (me == 0) { for (int iproc = 0; iproc < nprocs; iproc++) { if (iproc) { MPI_Irecv(buf,maxbuf*size_one,MPI_DOUBLE,iproc,0,world,&request); MPI_Send(&tmp,0,MPI_INT,iproc,0,world); MPI_Wait(&request,&status); MPI_Get_count(&status,MPI_DOUBLE,&nlines); nlines /= size_one; } else nlines = nme; write_data(nlines,buf); } if (flush_flag) fflush(fp); } else { MPI_Recv(&tmp,0,MPI_INT,0,0,world,&status); MPI_Rsend(buf,nme*size_one,MPI_DOUBLE,0,0,world); } } // if file per timestep, close file if (multifile) { if (compressed) { if (multiproc) pclose(fp); else if (me == 0) pclose(fp); } else { if (multiproc) fclose(fp); else if (me == 0) fclose(fp); } } } /* ---------------------------------------------------------------------- generic opening of a dump file ASCII or binary or gzipped some derived classes override this function ------------------------------------------------------------------------- */ void Dump::openfile() { // single file, already opened, so just return if (singlefile_opened) return; if (multifile == 0) singlefile_opened = 1; // if one file per timestep, replace '*' with current timestep char *filecurrent; if (multifile == 0) filecurrent = filename; else { filecurrent = new char[strlen(filename) + 16]; char *ptr = strchr(filename,'*'); *ptr = '\0'; - sprintf(filecurrent,"%s%d%s",filename,update->ntimestep,ptr+1); + char fstr[16]; + sprintf(fstr,"%%s%s%%s",BIGINT_FORMAT); + sprintf(filecurrent,fstr,filename,update->ntimestep,ptr+1); *ptr = '*'; } // open one file on proc 0 or file on every proc if (me == 0 || multiproc) { if (compressed) { #ifdef LAMMPS_GZIP char gzip[128]; sprintf(gzip,"gzip -6 > %s",filecurrent); fp = popen(gzip,"w"); #else error->one("Cannot open gzipped file"); #endif } else if (binary) { fp = fopen(filecurrent,"wb"); } else if (append_flag) { fp = fopen(filecurrent,"a"); } else { fp = fopen(filecurrent,"w"); } if (fp == NULL) error->one("Cannot open dump file"); } else fp = NULL; // delete string with timestep replaced if (multifile) delete [] filecurrent; } /* ---------------------------------------------------------------------- parallel sort of buf across all procs changes nme, reorders datums in buf, grows buf if necessary ------------------------------------------------------------------------- */ void Dump::sort() { int i,iproc; double value; // if single proc, swap ptrs to buf,ids <-> bufsort,idsort if (nprocs == 1) { if (nme > maxsort) { maxsort = nme; memory->sfree(bufsort); bufsort = (double *) memory->smalloc(maxsort*size_one*sizeof(double),"dump:bufsort"); memory->sfree(index); index = (int *) memory->smalloc(maxsort*sizeof(int),"dump:index"); if (sortcol == 0) { memory->sfree(idsort); idsort = (int *) memory->smalloc(maxsort*sizeof(int),"dump:idsort"); } } double *dptr = buf; buf = bufsort; bufsort = dptr; if (sortcol == 0) { int *iptr = ids; ids = idsort; idsort = iptr; } // if multiple procs, exchange datums between procs via irregular } else { // grow proclist if necessary if (nme > maxproc) { maxproc = nme; memory->sfree(proclist); proclist = (int *) memory->smalloc(maxproc*sizeof(int),"dump:proclist"); } // proclist[i] = which proc Ith datum will be sent to if (sortcol == 0) { int min = IBIG; int max = 0; for (i = 0; i < nme; i++) { min = MIN(min,ids[i]); max = MAX(max,ids[i]); } int minall,maxall; MPI_Allreduce(&min,&minall,1,MPI_INT,MPI_MIN,world); MPI_Allreduce(&max,&maxall,1,MPI_INT,MPI_MAX,world); double range = maxall-minall + EPSILON; for (i = 0; i < nme; i++) { iproc = static_cast<int> ((ids[i]-minall)/range * nprocs); proclist[i] = iproc; } } else { double min = BIG; double max = -BIG; for (i = 0; i < nme; i++) { value = buf[i*size_one + sortcolm1]; min = MIN(min,value); max = MAX(max,value); } double minall,maxall; MPI_Allreduce(&min,&minall,1,MPI_DOUBLE,MPI_MIN,world); MPI_Allreduce(&max,&maxall,1,MPI_DOUBLE,MPI_MAX,world); double range = maxall-minall + EPSILON*(maxall-minall); if (range == 0.0) range = EPSILON; for (i = 0; i < nme; i++) { value = buf[i*size_one + sortcolm1]; iproc = static_cast<int> ((value-minall)/range * nprocs); proclist[i] = iproc; } } // create comm plan, grow recv bufs if necessary, // exchange datums, destroy plan // if sorting on atom IDs, exchange IDs also nme = irregular->create_data(nme,proclist); if (nme > maxsort) { maxsort = nme; memory->sfree(bufsort); bufsort = (double *) memory->smalloc(maxsort*size_one*sizeof(double),"dump:bufsort"); memory->sfree(index); index = (int *) memory->smalloc(maxsort*sizeof(int),"dump:index"); if (sortcol == 0) { memory->sfree(idsort); idsort = (int *) memory->smalloc(maxsort*sizeof(int),"dump:idsort"); } } irregular->exchange_data((char *) buf,size_one*sizeof(double), (char *) bufsort); if (sortcol == 0) irregular->exchange_data((char *) ids,sizeof(int),(char *) idsort); irregular->destroy_data(); } // if reorder flag is set & total/per-proc counts match pre-computed values, // then create index directly from idsort // else quicksort of index using IDs or buf column as comparator if (reorderflag) { if (ntotal != ntotal_reorder) reorderflag = 0; int flag = 0; if (nme != nme_reorder) flag = 1; int flagall; MPI_Allreduce(&flag,&flagall,1,MPI_INT,MPI_SUM,world); if (flagall) reorderflag = 0; if (reorderflag) for (i = 0; i < nme; i++) index[idsort[i]-idlo] = i; } if (!reorderflag) { dumpptr = this; for (i = 0; i < nme; i++) index[i] = i; if (sortcol == 0) qsort(index,nme,sizeof(int),idcompare); else if (sortorder == ASCEND) qsort(index,nme,sizeof(int),bufcompare); else qsort(index,nme,sizeof(int),bufcompare_reverse); } // reset buf size and maxbuf to largest of any post-sort nme values // this insures proc 0 can receive everyone's info int nmax; if (multiproc) nmax = nme; else MPI_Allreduce(&nme,&nmax,1,MPI_INT,MPI_MAX,world); if (nmax > maxbuf) { maxbuf = nmax; memory->sfree(buf); buf = (double *) memory->smalloc(maxbuf*size_one*sizeof(double),"dump:buf"); } // copy data from bufsort to buf using index int nbytes = size_one*sizeof(double); for (i = 0; i < nme; i++) memcpy(&buf[i*size_one],&bufsort[index[i]*size_one],nbytes); } /* ---------------------------------------------------------------------- compare two atom IDs called via qsort() in sort() method is a static method so access data via dumpptr ------------------------------------------------------------------------- */ int Dump::idcompare(const void *pi, const void *pj) { int *idsort = dumpptr->idsort; int i = *((int *) pi); int j = *((int *) pj); if (idsort[i] < idsort[j]) return -1; if (idsort[i] > idsort[j]) return 1; return 0; } /* ---------------------------------------------------------------------- compare two buffer values with size_one stride called via qsort() in sort() method is a static method so access data via dumpptr sort in ASCENDing order ------------------------------------------------------------------------- */ int Dump::bufcompare(const void *pi, const void *pj) { double *bufsort = dumpptr->bufsort; int size_one = dumpptr->size_one; int sortcolm1 = dumpptr->sortcolm1; int i = *((int *) pi)*size_one + sortcolm1; int j = *((int *) pj)*size_one + sortcolm1; if (bufsort[i] < bufsort[j]) return -1; if (bufsort[i] > bufsort[j]) return 1; return 0; } /* ---------------------------------------------------------------------- compare two buffer values with size_one stride called via qsort() in sort() method is a static method so access data via dumpptr sort in DESCENDing order ------------------------------------------------------------------------- */ int Dump::bufcompare_reverse(const void *pi, const void *pj) { double *bufsort = dumpptr->bufsort; int size_one = dumpptr->size_one; int sortcolm1 = dumpptr->sortcolm1; int i = *((int *) pi)*size_one + sortcolm1; int j = *((int *) pj)*size_one + sortcolm1; if (bufsort[i] > bufsort[j]) return -1; if (bufsort[i] < bufsort[j]) return 1; return 0; } /* ---------------------------------------------------------------------- process params common to all dumps here if unknown param, call modify_param specific to the dump ------------------------------------------------------------------------- */ void Dump::modify_params(int narg, char **arg) { if (narg == 0) error->all("Illegal dump_modify command"); int iarg = 0; while (iarg < narg) { if (strcmp(arg[iarg],"append") == 0) { if (iarg+2 > narg) error->all("Illegal dump_modify command"); if (strcmp(arg[iarg+1],"yes") == 0) append_flag = 1; else if (strcmp(arg[iarg+1],"no") == 0) append_flag = 0; else error->all("Illegal dump_modify command"); iarg += 2; } else if (strcmp(arg[iarg],"every") == 0) { if (iarg+2 > narg) error->all("Illegal dump_modify command"); int idump; for (idump = 0; idump < output->ndump; idump++) if (strcmp(id,output->dump[idump]->id) == 0) break; int n; if (strstr(arg[iarg+1],"v_") == arg[iarg+1]) { delete [] output->var_dump[idump]; n = strlen(&arg[iarg+1][2]) + 1; output->var_dump[idump] = new char[n]; strcpy(output->var_dump[idump],&arg[iarg+1][2]); n = 0; } else { n = atoi(arg[iarg+1]); if (n <= 0) error->all("Illegal dump_modify command"); } output->every_dump[idump] = n; iarg += 2; } else if (strcmp(arg[iarg],"first") == 0) { if (iarg+2 > narg) error->all("Illegal dump_modify command"); if (strcmp(arg[iarg+1],"yes") == 0) first_flag = 1; else if (strcmp(arg[iarg+1],"no") == 0) first_flag = 0; else error->all("Illegal dump_modify command"); iarg += 2; } else if (strcmp(arg[iarg],"flush") == 0) { if (iarg+2 > narg) error->all("Illegal dump_modify command"); if (strcmp(arg[iarg+1],"yes") == 0) flush_flag = 1; else if (strcmp(arg[iarg+1],"no") == 0) flush_flag = 0; else error->all("Illegal dump_modify command"); iarg += 2; } else if (strcmp(arg[iarg],"format") == 0) { if (iarg+2 > narg) error->all("Illegal dump_modify command"); delete [] format_user; format_user = NULL; if (strcmp(arg[iarg+1],"none")) { int n = strlen(arg[iarg+1]) + 1; format_user = new char[n]; strcpy(format_user,arg[iarg+1]); } iarg += 2; } else if (strcmp(arg[iarg],"sort") == 0) { if (iarg+2 > narg) error->all("Illegal dump_modify command"); if (strcmp(arg[iarg+1],"off") == 0) sort_flag = 0; else if (strcmp(arg[iarg+1],"id") == 0) { sort_flag = 1; sortcol = 0; sortorder = ASCEND; } else { sort_flag = 1; sortcol = atoi(arg[iarg+1]); sortorder = ASCEND; if (sortcol == 0) error->all("Illegal dump_modify command"); if (sortcol < 0) { sortorder = DESCEND; sortcol = -sortcol; } sortcolm1 = sortcol - 1; } iarg += 2; } else { int n = modify_param(narg-iarg,&arg[iarg]); if (n == 0) error->all("Illegal dump_modify command"); iarg += n; } } } /* ---------------------------------------------------------------------- return # of bytes of allocated memory ------------------------------------------------------------------------- */ double Dump::memory_usage() { double bytes = maxbuf*size_one * sizeof(double); // buf if (sort_flag) { if (sortcol == 0) bytes += maxids * sizeof(int); // ids bytes += maxsort*size_one * sizeof(double); // bufsort if (sortcol == 0) bytes += maxsort * sizeof(int); // idsort bytes += maxsort * sizeof(int); // index bytes += maxproc * sizeof(int); // proclist if (irregular) bytes += irregular->memory_usage(); } return bytes; } diff --git a/src/dump.h b/src/dump.h index 6fea5482b..4b4aeb289 100644 --- a/src/dump.h +++ b/src/dump.h @@ -1,107 +1,108 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ #ifndef LMP_DUMP_H #define LMP_DUMP_H #include "stdio.h" #include "pointers.h" +#include "lmptype.h" namespace LAMMPS_NS { class Dump : protected Pointers { public: char *id; // user-defined name of Dump char *style; // style of Dump int igroup,groupbit; // group that Dump is performed on int first_flag; // 0 if no initial dump, 1 if yes initial dump int clearstep; // 1 if dump invokes computes, 0 if not // static variable across all Dump objects static Dump *dumpptr; // holds a ptr to Dump currently being used Dump(class LAMMPS *, int, char **); virtual ~Dump(); void init(); void write(); void modify_params(int, char **); virtual double memory_usage(); protected: int me,nprocs; // proc info char *filename; // user-specified file int compressed; // 1 if dump file is written compressed, 0 no int binary; // 1 if dump file is written binary, 0 no int multifile; // 0 = one big file, 1 = one file per timestep int multiproc; // 0 = proc 0 writes for all, 1 = one file/proc int header_flag; // 0 = item, 2 = xyz int flush_flag; // 0 if no flush, 1 if flush every dump int sort_flag; // 1 if sorted output int append_flag; // 1 if open file in append mode, 0 if not int singlefile_opened; // 1 = one big file, already opened, else 0 int sortcol; // 0 to sort on ID, 1-N on columns int sortcolm1; // sortcol - 1 int sortorder; // ASCEND or DESCEND char *format_default; // default format string char *format_user; // format string set by user char *format; // format string for the file write FILE *fp; // file to write dump to int size_one; // # of quantities for one atom int nme; // # of atoms in this dump from me double boxxlo,boxxhi; // local copies of domain values double boxylo,boxyhi; // lo/hi are bounding box for triclinic double boxzlo,boxzhi; double boxxy,boxxz,boxyz; - int ntotal; // # of per-atom lines in snapshot + bigint ntotal; // # of per-atom lines in snapshot int reorderflag; // 1 if OK to reorder instead of sort int ntotal_reorder; // # of atoms that must be in snapshot int nme_reorder; // # of atoms I must own in snapshot int idlo; // lowest ID I own when reordering int maxbuf; // size of buf double *buf; // memory for atom quantities int maxids; // size of ids int maxsort; // size of bufsort, idsort, index int maxproc; // size of proclist int *ids; // list of atom IDs, if sorting on IDs double *bufsort; int *idsort,*index,*proclist; class Irregular *irregular; virtual void init_style() = 0; virtual void openfile(); virtual int modify_param(int, char **) {return 0;} - virtual void write_header(int) = 0; + virtual void write_header(bigint) = 0; virtual int count() = 0; virtual void pack(int *) = 0; virtual void write_data(int, double *) = 0; void sort(); static int idcompare(const void *, const void *); static int bufcompare(const void *, const void *); static int bufcompare_reverse(const void *, const void *); }; } #endif diff --git a/src/dump_atom.cpp b/src/dump_atom.cpp index 930fc6e1d..11152f5b7 100644 --- a/src/dump_atom.cpp +++ b/src/dump_atom.cpp @@ -1,438 +1,438 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ #include "string.h" #include "dump_atom.h" #include "domain.h" #include "atom.h" #include "update.h" #include "group.h" #include "error.h" using namespace LAMMPS_NS; /* ---------------------------------------------------------------------- */ DumpAtom::DumpAtom(LAMMPS *lmp, int narg, char **arg) : Dump(lmp, narg, arg) { if (narg != 5) error->all("Illegal dump atom command"); scale_flag = 1; image_flag = 0; format_default = NULL; } /* ---------------------------------------------------------------------- */ void DumpAtom::init_style() { if (image_flag == 0) size_one = 5; else size_one = 8; // default format depends on image flags delete [] format; if (format_user) { int n = strlen(format_user) + 2; format = new char[n]; strcpy(format,format_user); strcat(format,"\n"); } else { char *str; if (image_flag == 0) str = (char *) "%d %d %g %g %g"; else str = (char *) "%d %d %g %g %g %d %d %d"; int n = strlen(str) + 2; format = new char[n]; strcpy(format,str); strcat(format,"\n"); } // setup column string if (scale_flag == 0 && image_flag == 0) columns = "id type x y z"; else if (scale_flag == 0 && image_flag == 1) columns = "id type x y z ix iy iz"; else if (scale_flag == 1 && image_flag == 0) columns = "id type xs ys zs"; else if (scale_flag == 1 && image_flag == 1) columns = "id type xs ys zs ix iy iz"; // setup function ptrs if (binary && domain->triclinic == 0) header_choice = &DumpAtom::header_binary; else if (binary && domain->triclinic == 1) header_choice = &DumpAtom::header_binary_triclinic; else if (!binary && domain->triclinic == 0) header_choice = &DumpAtom::header_item; else if (!binary && domain->triclinic == 1) header_choice = &DumpAtom::header_item_triclinic; if (scale_flag == 1 && image_flag == 0 && domain->triclinic == 0) pack_choice = &DumpAtom::pack_scale_noimage; else if (scale_flag == 1 && image_flag == 1 && domain->triclinic == 0) pack_choice = &DumpAtom::pack_scale_image; else if (scale_flag == 1 && image_flag == 0 && domain->triclinic == 1) pack_choice = &DumpAtom::pack_scale_noimage_triclinic; else if (scale_flag == 1 && image_flag == 1 && domain->triclinic == 1) pack_choice = &DumpAtom::pack_scale_image_triclinic; else if (scale_flag == 0 && image_flag == 0) pack_choice = &DumpAtom::pack_noscale_noimage; else if (scale_flag == 0 && image_flag == 1) pack_choice = &DumpAtom::pack_noscale_image; if (binary) write_choice = &DumpAtom::write_binary; else if (image_flag == 0) write_choice = &DumpAtom::write_noimage; else if (image_flag == 1) write_choice = &DumpAtom::write_image; // open single file, one time only if (multifile == 0) openfile(); } /* ---------------------------------------------------------------------- */ int DumpAtom::modify_param(int narg, char **arg) { if (strcmp(arg[0],"scale") == 0) { if (narg < 2) error->all("Illegal dump_modify command"); if (strcmp(arg[1],"yes") == 0) scale_flag = 1; else if (strcmp(arg[1],"no") == 0) scale_flag = 0; else error->all("Illegal dump_modify command"); return 2; } else if (strcmp(arg[0],"image") == 0) { if (narg < 2) error->all("Illegal dump_modify command"); if (strcmp(arg[1],"yes") == 0) image_flag = 1; else if (strcmp(arg[1],"no") == 0) image_flag = 0; else error->all("Illegal dump_modify command"); return 2; } return 0; } /* ---------------------------------------------------------------------- */ -void DumpAtom::write_header(int ndump) +void DumpAtom::write_header(bigint ndump) { if (multiproc) (this->*header_choice)(ndump); else if (me == 0) (this->*header_choice)(ndump); } /* ---------------------------------------------------------------------- */ int DumpAtom::count() { if (igroup == 0) return atom->nlocal; int *mask = atom->mask; int nlocal = atom->nlocal; int m = 0; for (int i = 0; i < nlocal; i++) if (mask[i] & groupbit) m++; return m; } /* ---------------------------------------------------------------------- */ void DumpAtom::pack(int *ids) { (this->*pack_choice)(ids); } /* ---------------------------------------------------------------------- */ void DumpAtom::write_data(int n, double *mybuf) { (this->*write_choice)(n,mybuf); } /* ---------------------------------------------------------------------- */ -void DumpAtom::header_binary(int ndump) +void DumpAtom::header_binary(bigint ndump) { - fwrite(&update->ntimestep,sizeof(int),1,fp); - fwrite(&ndump,sizeof(int),1,fp); + fwrite(&update->ntimestep,sizeof(bigint),1,fp); + fwrite(&ndump,sizeof(bigint),1,fp); fwrite(&domain->triclinic,sizeof(int),1,fp); fwrite(&boxxlo,sizeof(double),1,fp); fwrite(&boxxhi,sizeof(double),1,fp); fwrite(&boxylo,sizeof(double),1,fp); fwrite(&boxyhi,sizeof(double),1,fp); fwrite(&boxzlo,sizeof(double),1,fp); fwrite(&boxzhi,sizeof(double),1,fp); fwrite(&size_one,sizeof(int),1,fp); if (multiproc) { int one = 1; fwrite(&one,sizeof(int),1,fp); } else fwrite(&nprocs,sizeof(int),1,fp); } /* ---------------------------------------------------------------------- */ -void DumpAtom::header_binary_triclinic(int ndump) +void DumpAtom::header_binary_triclinic(bigint ndump) { - fwrite(&update->ntimestep,sizeof(int),1,fp); - fwrite(&ndump,sizeof(int),1,fp); + fwrite(&update->ntimestep,sizeof(bigint),1,fp); + fwrite(&ndump,sizeof(bigint),1,fp); fwrite(&domain->triclinic,sizeof(int),1,fp); fwrite(&boxxlo,sizeof(double),1,fp); fwrite(&boxxhi,sizeof(double),1,fp); fwrite(&boxylo,sizeof(double),1,fp); fwrite(&boxyhi,sizeof(double),1,fp); fwrite(&boxzlo,sizeof(double),1,fp); fwrite(&boxzhi,sizeof(double),1,fp); fwrite(&boxxy,sizeof(double),1,fp); fwrite(&boxxz,sizeof(double),1,fp); fwrite(&boxyz,sizeof(double),1,fp); fwrite(&size_one,sizeof(int),1,fp); if (multiproc) { int one = 1; fwrite(&one,sizeof(int),1,fp); } else fwrite(&nprocs,sizeof(int),1,fp); } /* ---------------------------------------------------------------------- */ -void DumpAtom::header_item(int ndump) +void DumpAtom::header_item(bigint ndump) { fprintf(fp,"ITEM: TIMESTEP\n"); - fprintf(fp,"%d\n",update->ntimestep); + fprintf(fp,BIGINT_FORMAT_NL,update->ntimestep); fprintf(fp,"ITEM: NUMBER OF ATOMS\n"); - fprintf(fp,"%d\n",ndump); + fprintf(fp,BIGINT_FORMAT_NL,ndump); fprintf(fp,"ITEM: BOX BOUNDS\n"); fprintf(fp,"%g %g\n",boxxlo,boxxhi); fprintf(fp,"%g %g\n",boxylo,boxyhi); fprintf(fp,"%g %g\n",boxzlo,boxzhi); fprintf(fp,"ITEM: ATOMS %s\n",columns); } /* ---------------------------------------------------------------------- */ -void DumpAtom::header_item_triclinic(int ndump) +void DumpAtom::header_item_triclinic(bigint ndump) { fprintf(fp,"ITEM: TIMESTEP\n"); - fprintf(fp,"%d\n",update->ntimestep); + fprintf(fp,BIGINT_FORMAT_NL,update->ntimestep); fprintf(fp,"ITEM: NUMBER OF ATOMS\n"); - fprintf(fp,"%d\n",ndump); + fprintf(fp,BIGINT_FORMAT_NL,ndump); fprintf(fp,"ITEM: BOX BOUNDS xy xz yz\n"); fprintf(fp,"%g %g %g\n",boxxlo,boxxhi,boxxy); fprintf(fp,"%g %g %g\n",boxylo,boxyhi,boxxz); fprintf(fp,"%g %g %g\n",boxzlo,boxzhi,boxyz); fprintf(fp,"ITEM: ATOMS %s\n",columns); } /* ---------------------------------------------------------------------- */ void DumpAtom::pack_scale_image(int *ids) { int m,n; int *tag = atom->tag; int *type = atom->type; int *image = atom->image; int *mask = atom->mask; double **x = atom->x; int nlocal = atom->nlocal; double invxprd = 1.0/domain->xprd; double invyprd = 1.0/domain->yprd; double invzprd = 1.0/domain->zprd; m = n = 00; for (int i = 0; i < nlocal; i++) if (mask[i] & groupbit) { buf[m++] = tag[i]; buf[m++] = type[i]; buf[m++] = (x[i][0] - boxxlo) * invxprd; buf[m++] = (x[i][1] - boxylo) * invyprd; buf[m++] = (x[i][2] - boxzlo) * invzprd; buf[m++] = (image[i] & 1023) - 512; buf[m++] = (image[i] >> 10 & 1023) - 512; buf[m++] = (image[i] >> 20) - 512; if (ids) ids[n++] = tag[i]; } } /* ---------------------------------------------------------------------- */ void DumpAtom::pack_scale_noimage(int *ids) { int m,n; int *tag = atom->tag; int *type = atom->type; int *mask = atom->mask; double **x = atom->x; int nlocal = atom->nlocal; double invxprd = 1.0/domain->xprd; double invyprd = 1.0/domain->yprd; double invzprd = 1.0/domain->zprd; m = n = 0; for (int i = 0; i < nlocal; i++) if (mask[i] & groupbit) { buf[m++] = tag[i]; buf[m++] = type[i]; buf[m++] = (x[i][0] - boxxlo) * invxprd; buf[m++] = (x[i][1] - boxylo) * invyprd; buf[m++] = (x[i][2] - boxzlo) * invzprd; if (ids) ids[n++] = tag[i]; } } /* ---------------------------------------------------------------------- */ void DumpAtom::pack_scale_image_triclinic(int *ids) { int m,n; int *tag = atom->tag; int *type = atom->type; int *image = atom->image; int *mask = atom->mask; double **x = atom->x; int nlocal = atom->nlocal; double lamda[3]; m = n = 0; for (int i = 0; i < nlocal; i++) if (mask[i] & groupbit) { buf[m++] = tag[i]; buf[m++] = type[i]; domain->x2lamda(x[i],lamda); buf[m++] = lamda[0]; buf[m++] = lamda[1]; buf[m++] = lamda[2]; buf[m++] = (image[i] & 1023) - 512; buf[m++] = (image[i] >> 10 & 1023) - 512; buf[m++] = (image[i] >> 20) - 512; if (ids) ids[n++] = tag[i]; } } /* ---------------------------------------------------------------------- */ void DumpAtom::pack_scale_noimage_triclinic(int *ids) { int m,n; int *tag = atom->tag; int *type = atom->type; int *mask = atom->mask; double **x = atom->x; int nlocal = atom->nlocal; double lamda[3]; m = n = 0; for (int i = 0; i < nlocal; i++) if (mask[i] & groupbit) { buf[m++] = tag[i]; buf[m++] = type[i]; domain->x2lamda(x[i],lamda); buf[m++] = lamda[0]; buf[m++] = lamda[1]; buf[m++] = lamda[2]; if (ids) ids[n++] = tag[i]; } } /* ---------------------------------------------------------------------- */ void DumpAtom::pack_noscale_image(int *ids) { int m,n; int *tag = atom->tag; int *type = atom->type; int *image = atom->image; int *mask = atom->mask; double **x = atom->x; int nlocal = atom->nlocal; m = n = 0; for (int i = 0; i < nlocal; i++) if (mask[i] & groupbit) { buf[m++] = tag[i]; buf[m++] = type[i]; buf[m++] = x[i][0]; buf[m++] = x[i][1]; buf[m++] = x[i][2]; buf[m++] = (image[i] & 1023) - 512; buf[m++] = (image[i] >> 10 & 1023) - 512; buf[m++] = (image[i] >> 20) - 512; if (ids) ids[n++] = tag[i]; } } /* ---------------------------------------------------------------------- */ void DumpAtom::pack_noscale_noimage(int *ids) { int m,n; int *tag = atom->tag; int *type = atom->type; int *mask = atom->mask; double **x = atom->x; int nlocal = atom->nlocal; m = n = 0; for (int i = 0; i < nlocal; i++) if (mask[i] & groupbit) { buf[m++] = tag[i]; buf[m++] = type[i]; buf[m++] = x[i][0]; buf[m++] = x[i][1]; buf[m++] = x[i][2]; if (ids) ids[n++] = tag[i]; } } /* ---------------------------------------------------------------------- */ void DumpAtom::write_binary(int n, double *mybuf) { n *= size_one; fwrite(&n,sizeof(int),1,fp); fwrite(mybuf,sizeof(double),n,fp); } /* ---------------------------------------------------------------------- */ void DumpAtom::write_image(int n, double *mybuf) { int m = 0; for (int i = 0; i < n; i++) { fprintf(fp,format, static_cast<int> (mybuf[m]), static_cast<int> (mybuf[m+1]), mybuf[m+2],mybuf[m+3],mybuf[m+4], static_cast<int> (mybuf[m+5]), static_cast<int> (mybuf[m+6]), static_cast<int> (mybuf[m+7])); m += size_one; } } /* ---------------------------------------------------------------------- */ void DumpAtom::write_noimage(int n, double *mybuf) { int m = 0; for (int i = 0; i < n; i++) { fprintf(fp,format, static_cast<int> (mybuf[m]), static_cast<int> (mybuf[m+1]), mybuf[m+2],mybuf[m+3],mybuf[m+4]); m += size_one; } } diff --git a/src/dump_atom.h b/src/dump_atom.h index 14f8e7524..0483a7d64 100644 --- a/src/dump_atom.h +++ b/src/dump_atom.h @@ -1,70 +1,70 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ #ifdef DUMP_CLASS DumpStyle(atom,DumpAtom) #else #ifndef LMP_DUMP_ATOM_H #define LMP_DUMP_ATOM_H #include "dump.h" namespace LAMMPS_NS { class DumpAtom : public Dump { public: DumpAtom(LAMMPS *, int, char**); private: int scale_flag; // 1 if atom coords are scaled, 0 if no int image_flag; // 1 if append box count to atom coords, 0 if no char *columns; // column labels void init_style(); int modify_param(int, char **); - void write_header(int); + void write_header(bigint); int count(); void pack(int *); void write_data(int, double *); - typedef void (DumpAtom::*FnPtrHeader)(int); + typedef void (DumpAtom::*FnPtrHeader)(bigint); FnPtrHeader header_choice; // ptr to write header functions - void header_binary(int); - void header_binary_triclinic(int); - void header_item(int); - void header_item_triclinic(int); + void header_binary(bigint); + void header_binary_triclinic(bigint); + void header_item(bigint); + void header_item_triclinic(bigint); typedef void (DumpAtom::*FnPtrPack)(int *); FnPtrPack pack_choice; // ptr to pack functions void pack_scale_image(int *); void pack_scale_noimage(int *); void pack_noscale_image(int *); void pack_noscale_noimage(int *); void pack_scale_image_triclinic(int *); void pack_scale_noimage_triclinic(int *); typedef void (DumpAtom::*FnPtrData)(int, double *); FnPtrData write_choice; // ptr to write data functions void write_binary(int, double *); void write_image(int, double *); void write_noimage(int, double *); }; } #endif #endif diff --git a/src/dump_cfg.cpp b/src/dump_cfg.cpp index b11a5169b..924c09eaf 100755 --- a/src/dump_cfg.cpp +++ b/src/dump_cfg.cpp @@ -1,289 +1,291 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- Contributing author: Liang Wan (Chinese Academy of Sciences) ------------------------------------------------------------------------- */ #include "stdlib.h" #include "string.h" #include "dump_cfg.h" #include "atom.h" #include "domain.h" #include "comm.h" #include "modify.h" #include "compute.h" #include "input.h" #include "fix.h" #include "variable.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; enum{INT,DOUBLE}; // same as in dump_custom.cpp /* ---------------------------------------------------------------------- */ DumpCFG::DumpCFG(LAMMPS *lmp, int narg, char **arg) : DumpCustom(lmp, narg, arg) { if (narg < 10 || strcmp(arg[5],"id") != 0 || strcmp(arg[6],"type") != 0 || strcmp(arg[7],"xs") != 0 || strcmp(arg[8],"ys") != 0 || strcmp(arg[9],"zs") != 0) error->all("Dump cfg arguments must start with 'id type xs ys zs'"); ntypes = atom->ntypes; typenames = NULL; // arrays for data rearrangement rbuf = NULL; nchosen = nlines = 0; // setup auxiliary property name strings // convert 'X_ID[m]' (X=c,f,v) to 'ID_m' if (narg > 10) auxname = new char*[narg-10]; else auxname = NULL; int i = 0; for (int iarg = 10; iarg < narg; iarg++, i++) { if (strncmp(arg[iarg],"c_",2) == 0 || strncmp(arg[iarg],"f_",2) == 0 || strncmp(arg[iarg],"v_",2) == 0) { int n = strlen(arg[iarg]); char *suffix = new char[n]; strcpy(suffix,&arg[iarg][2]); char *ptr = strchr(suffix,'['); if (ptr) { if (suffix[strlen(suffix)-1] != ']') error->all("Invalid keyword in dump cfg command"); *ptr = '\0'; *(ptr+2) = '\0'; auxname[i] = new char[strlen(suffix) + 3]; strcpy(auxname[i],suffix); strcat(auxname[i],"_"); strcat(auxname[i],ptr+1); } else { auxname[i] = new char[strlen(suffix) + 1]; strcpy(auxname[i],suffix); } delete [] suffix; } else { auxname[i] = new char[strlen(arg[iarg]) + 1]; strcpy(auxname[i],arg[iarg]); } } } /* ---------------------------------------------------------------------- */ DumpCFG::~DumpCFG() { if (typenames) { for (int i = 1; i <= ntypes; i++) delete [] typenames[i]; delete [] typenames; } if (rbuf) memory->destroy_2d_double_array(rbuf); if (auxname) { for (int i = 0; i < nfield-5; i++) delete [] auxname[i]; delete [] auxname; } } /* ---------------------------------------------------------------------- */ void DumpCFG::init_style() { if (multifile == 0) error->all("Dump in CFG format requires one snapshot per file"); if (typenames == NULL) { typenames = new char*[ntypes+1]; for (int itype = 1; itype <= ntypes; itype++) { typenames[itype] = new char[3]; strcpy(typenames[itype],"C"); } if (comm->me == 0) error->warning("All element names have been set to 'C' for dump cfg"); } // setup format strings delete [] format; char *str; if (format_user) str = format_user; else str = format_default; int n = strlen(str) + 1; format = new char[n]; strcpy(format,str); // tokenize the format string and add space at end of each format element char *ptr; for (int i = 0; i < size_one; i++) { if (i == 0) ptr = strtok(format," \0"); else ptr = strtok(NULL," \0"); delete [] vformat[i]; vformat[i] = new char[strlen(ptr) + 2]; strcpy(vformat[i],ptr); vformat[i] = strcat(vformat[i]," "); } // find current ptr for each compute,fix,variable // check that fix frequency is acceptable int icompute; for (int i = 0; i < ncompute; i++) { icompute = modify->find_compute(id_compute[i]); if (icompute < 0) error->all("Could not find dump cfg compute ID"); compute[i] = modify->compute[icompute]; } int ifix; for (int i = 0; i < nfix; i++) { ifix = modify->find_fix(id_fix[i]); if (ifix < 0) error->all("Could not find dump cfg fix ID"); fix[i] = modify->fix[ifix]; if (nevery % modify->fix[ifix]->peratom_freq) error->all("Dump cfg and fix not computed at compatible times"); } int ivariable; for (int i = 0; i < nvariable; i++) { ivariable = input->variable->find(id_variable[i]); if (ivariable < 0) error->all("Could not find dump cfg variable name"); variable[i] = ivariable; } // set index and check validity of region if (iregion >= 0) { iregion = domain->find_region(idregion); if (iregion == -1) error->all("Region ID for dump cfg does not exist"); } } /* ---------------------------------------------------------------------- */ -void DumpCFG::write_header(int n) +void DumpCFG::write_header(bigint n) { if (me == 0 || multiproc) { - fprintf(fp,"Number of particles = %d\n", n); + char str[64]; + sprintf(str,"Number of particles = %s\n",BIGINT_FORMAT); + fprintf(fp,str,n); fprintf(fp,"A = 1.0 Angstrom (basic length-scale)\n"); fprintf(fp,"H0(1,1) = %g A\n",domain->xprd); fprintf(fp,"H0(1,2) = 0 A \n"); fprintf(fp,"H0(1,3) = 0 A \n"); fprintf(fp,"H0(2,1) = %g A \n",domain->xy); fprintf(fp,"H0(2,2) = %g A\n",domain->yprd); fprintf(fp,"H0(2,3) = 0 A \n"); fprintf(fp,"H0(3,1) = %g A \n",domain->xz); fprintf(fp,"H0(3,2) = %g A \n",domain->yz); fprintf(fp,"H0(3,3) = %g A\n",domain->zprd); fprintf(fp,".NO_VELOCITY.\n"); fprintf(fp,"entry_count = %d\n",nfield-2); for (int i = 0; i < nfield-5; i++) fprintf(fp,"auxiliary[%d] = %s\n",i,auxname[i]); } // calculate total # of data lines to be written on a writing proc if (multiproc) nchosen = nmine; else MPI_Reduce(&nmine,&nchosen,1,MPI_INT,MPI_SUM,0,world); // allocate memory needed for data rearrangement on writing proc(s) if (multiproc || me == 0) { if (rbuf) memory->destroy_2d_double_array(rbuf); rbuf = memory->create_2d_double_array(nchosen,size_one,"dump:rbuf"); } } /* ---------------------------------------------------------------------- write data lines to file in a block-by-block style write head of block (mass & element name) only if has atoms of the type ------------------------------------------------------------------------- */ void DumpCFG::write_data(int n, double *mybuf) { int i,j,m,itype; int tag_i,index; double *mass = atom->mass; // transfer data from buf to rbuf // if write by proc 0, transfer chunk by chunk for (i = 0, m = 0; i < n; i++) { for (j = 0; j < size_one; j++) rbuf[nlines][j] = mybuf[m++]; nlines++; } // write data lines in rbuf to file after transfer is done if (nlines == nchosen) { for (itype = 1; itype <= ntypes; itype++) { for (i = 0; i < nchosen; i++) if (rbuf[i][1] == itype) break; if (i < nchosen) { fprintf(fp,"%g\n",mass[itype]); fprintf(fp,"%s\n",typenames[itype]); for (; i < nchosen; i++) { if (rbuf[i][1] == itype) { for (j = 2; j < size_one; j++) { if (vtype[j] == INT) fprintf(fp,vformat[j],static_cast<int> (rbuf[i][j])); else fprintf(fp,vformat[j],rbuf[i][j]); } fprintf(fp,"\n"); } } } } nlines = 0; } } /* ---------------------------------------------------------------------- */ int DumpCFG::modify_param2(int narg, char **arg) { if (strcmp(arg[0],"element") == 0) { if (narg != ntypes+1) error->all("Dump modify element names do not match atom types"); if (typenames) { for (int i = 1; i <= ntypes; i++) delete [] typenames[i]; delete [] typenames; typenames = NULL; } typenames = new char*[ntypes+1]; for (int itype = 1; itype <= ntypes; itype++) { typenames[itype] = new char[3]; if (strlen(arg[itype]) >= 3) error->all("Illegal chemical element names"); strcpy(typenames[itype],arg[itype]); } return ntypes+1; } else return 0; } diff --git a/src/dump_cfg.h b/src/dump_cfg.h index ca3cd4032..0467983f7 100755 --- a/src/dump_cfg.h +++ b/src/dump_cfg.h @@ -1,50 +1,50 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ #ifdef DUMP_CLASS DumpStyle(cfg,DumpCFG) #else #ifndef LMP_DUMP_CFG_H #define LMP_DUMP_CFG_H #include "dump_custom.h" namespace LAMMPS_NS { class DumpCFG : public DumpCustom { public: DumpCFG(class LAMMPS *, int, char **); ~DumpCFG(); private: int ntypes; // # of atom types char **typenames; // array of element names for each type char **auxname; // name strings of auxiliary properties int nchosen; // # of lines to be written on a writing proc int nlines; // # of lines transferred from buf to rbuf double **rbuf; // buf of data lines for data lines rearrangement void init_style(); - void write_header(int); + void write_header(bigint); void write_data(int, double *); int modify_param2(int, char **); }; } #endif #endif diff --git a/src/dump_custom.cpp b/src/dump_custom.cpp index c5058d89f..2ee551c1d 100644 --- a/src/dump_custom.cpp +++ b/src/dump_custom.cpp @@ -1,2295 +1,2294 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ #include "math.h" #include "stdlib.h" #include "string.h" #include "dump_custom.h" #include "atom.h" #include "force.h" #include "domain.h" #include "region.h" #include "group.h" #include "input.h" #include "variable.h" #include "update.h" #include "modify.h" #include "compute.h" #include "fix.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; // customize by adding keyword // same list as in compute_property.cpp, also customize that command enum{ID,MOL,TYPE,MASS, X,Y,Z,XS,YS,ZS,XSTRI,YSTRI,ZSTRI,XU,YU,ZU,XUTRI,YUTRI,ZUTRI,IX,IY,IZ, VX,VY,VZ,FX,FY,FZ, Q,MUX,MUY,MUZ,RADIUS,OMEGAX,OMEGAY,OMEGAZ,ANGMOMX,ANGMOMY,ANGMOMZ, QUATW,QUATI,QUATJ,QUATK,TQX,TQY,TQZ,SPIN,ERADIUS,ERVEL,ERFORCE, COMPUTE,FIX,VARIABLE}; enum{LT,LE,GT,GE,EQ,NEQ}; enum{INT,DOUBLE}; #define INVOKED_PERATOM 8 /* ---------------------------------------------------------------------- */ DumpCustom::DumpCustom(LAMMPS *lmp, int narg, char **arg) : Dump(lmp, narg, arg) { if (narg == 5) error->all("No dump custom arguments specified"); clearstep = 1; nevery = atoi(arg[3]); size_one = nfield = narg-5; pack_choice = new FnPtrPack[nfield]; vtype = new int[nfield]; iregion = -1; idregion = NULL; nthresh = 0; thresh_array = NULL; thresh_op = NULL; thresh_value = NULL; // computes, fixes, variables which the dump accesses field2index = (int *) memory->smalloc(nfield*sizeof(int),"dump:field2index"); argindex = (int *) memory->smalloc(nfield*sizeof(int),"dump:argindex"); ncompute = 0; id_compute = NULL; compute = NULL; nfix = 0; id_fix = NULL; fix = NULL; nvariable = 0; id_variable = NULL; variable = NULL; vbuf = NULL; // process attributes parse_fields(narg,arg); // atom selection arrays maxlocal = 0; choose = NULL; dchoose = NULL; // setup format strings vformat = new char*[size_one]; format_default = new char[3*size_one+1]; format_default[0] = '\0'; for (int i = 0; i < size_one; i++) { if (vtype[i] == INT) format_default = strcat(format_default,"%d "); else format_default = strcat(format_default,"%g "); vformat[i] = NULL; } // setup column string int n = 0; for (int iarg = 5; iarg < narg; iarg++) n += strlen(arg[iarg]) + 2; columns = new char[n]; columns[0] = '\0'; for (int iarg = 5; iarg < narg; iarg++) { strcat(columns,arg[iarg]); strcat(columns," "); } } /* ---------------------------------------------------------------------- */ DumpCustom::~DumpCustom() { delete [] pack_choice; delete [] vtype; memory->sfree(field2index); memory->sfree(argindex); delete [] idregion; memory->sfree(thresh_array); memory->sfree(thresh_op); memory->sfree(thresh_value); for (int i = 0; i < ncompute; i++) delete [] id_compute[i]; memory->sfree(id_compute); delete [] compute; for (int i = 0; i < nfix; i++) delete [] id_fix[i]; memory->sfree(id_fix); delete [] fix; for (int i = 0; i < nvariable; i++) delete [] id_variable[i]; memory->sfree(id_variable); delete [] variable; for (int i = 0; i < nvariable; i++) memory->sfree(vbuf[i]); delete [] vbuf; memory->sfree(choose); memory->sfree(dchoose); for (int i = 0; i < size_one; i++) delete [] vformat[i]; delete [] vformat; delete [] columns; } /* ---------------------------------------------------------------------- */ void DumpCustom::init_style() { delete [] format; char *str; if (format_user) str = format_user; else str = format_default; int n = strlen(str) + 1; format = new char[n]; strcpy(format,str); // tokenize the format string and add space at end of each format element char *ptr; for (int i = 0; i < size_one; i++) { if (i == 0) ptr = strtok(format," \0"); else ptr = strtok(NULL," \0"); delete [] vformat[i]; vformat[i] = new char[strlen(ptr) + 2]; strcpy(vformat[i],ptr); vformat[i] = strcat(vformat[i]," "); } // setup function ptrs if (binary && domain->triclinic == 0) header_choice = &DumpCustom::header_binary; else if (binary && domain->triclinic == 1) header_choice = &DumpCustom::header_binary_triclinic; else if (!binary && domain->triclinic == 0) header_choice = &DumpCustom::header_item; else if (!binary && domain->triclinic == 1) header_choice = &DumpCustom::header_item_triclinic; if (binary) write_choice = &DumpCustom::write_binary; else write_choice = &DumpCustom::write_text; // find current ptr for each compute,fix,variable // check that fix frequency is acceptable int icompute; for (int i = 0; i < ncompute; i++) { icompute = modify->find_compute(id_compute[i]); if (icompute < 0) error->all("Could not find dump custom compute ID"); compute[i] = modify->compute[icompute]; } int ifix; for (int i = 0; i < nfix; i++) { ifix = modify->find_fix(id_fix[i]); if (ifix < 0) error->all("Could not find dump custom fix ID"); fix[i] = modify->fix[ifix]; if (nevery % modify->fix[ifix]->peratom_freq) error->all("Dump custom and fix not computed at compatible times"); } int ivariable; for (int i = 0; i < nvariable; i++) { ivariable = input->variable->find(id_variable[i]); if (ivariable < 0) error->all("Could not find dump custom variable name"); variable[i] = ivariable; } // set index and check validity of region if (iregion >= 0) { iregion = domain->find_region(idregion); if (iregion == -1) error->all("Region ID for dump custom does not exist"); } // open single file, one time only if (multifile == 0) openfile(); } /* ---------------------------------------------------------------------- */ -void DumpCustom::write_header(int ndump) +void DumpCustom::write_header(bigint ndump) { if (multiproc) (this->*header_choice)(ndump); else if (me == 0) (this->*header_choice)(ndump); } /* ---------------------------------------------------------------------- */ -void DumpCustom::header_binary(int ndump) +void DumpCustom::header_binary(bigint ndump) { - fwrite(&update->ntimestep,sizeof(int),1,fp); - fwrite(&ndump,sizeof(int),1,fp); + fwrite(&update->ntimestep,sizeof(bigint),1,fp); + fwrite(&ndump,sizeof(bigint),1,fp); fwrite(&domain->triclinic,sizeof(int),1,fp); fwrite(&boxxlo,sizeof(double),1,fp); fwrite(&boxxhi,sizeof(double),1,fp); fwrite(&boxylo,sizeof(double),1,fp); fwrite(&boxyhi,sizeof(double),1,fp); fwrite(&boxzlo,sizeof(double),1,fp); fwrite(&boxzhi,sizeof(double),1,fp); fwrite(&size_one,sizeof(int),1,fp); if (multiproc) { int one = 1; fwrite(&one,sizeof(int),1,fp); } else fwrite(&nprocs,sizeof(int),1,fp); } /* ---------------------------------------------------------------------- */ -void DumpCustom::header_binary_triclinic(int ndump) +void DumpCustom::header_binary_triclinic(bigint ndump) { - fwrite(&update->ntimestep,sizeof(int),1,fp); - fwrite(&ndump,sizeof(int),1,fp); + fwrite(&update->ntimestep,sizeof(bigint),1,fp); + fwrite(&ndump,sizeof(bigint),1,fp); fwrite(&domain->triclinic,sizeof(int),1,fp); fwrite(&boxxlo,sizeof(double),1,fp); fwrite(&boxxhi,sizeof(double),1,fp); fwrite(&boxylo,sizeof(double),1,fp); fwrite(&boxyhi,sizeof(double),1,fp); fwrite(&boxzlo,sizeof(double),1,fp); fwrite(&boxzhi,sizeof(double),1,fp); fwrite(&boxxy,sizeof(double),1,fp); fwrite(&boxxz,sizeof(double),1,fp); fwrite(&boxyz,sizeof(double),1,fp); fwrite(&size_one,sizeof(int),1,fp); if (multiproc) { int one = 1; fwrite(&one,sizeof(int),1,fp); } else fwrite(&nprocs,sizeof(int),1,fp); } /* ---------------------------------------------------------------------- */ -void DumpCustom::header_item(int ndump) +void DumpCustom::header_item(bigint ndump) { fprintf(fp,"ITEM: TIMESTEP\n"); - fprintf(fp,"%d\n",update->ntimestep); + fprintf(fp,BIGINT_FORMAT_NL,update->ntimestep); fprintf(fp,"ITEM: NUMBER OF ATOMS\n"); - fprintf(fp,"%d\n",ndump); + fprintf(fp,BIGINT_FORMAT_NL,ndump); fprintf(fp,"ITEM: BOX BOUNDS\n"); fprintf(fp,"%g %g\n",boxxlo,boxxhi); fprintf(fp,"%g %g\n",boxylo,boxyhi); fprintf(fp,"%g %g\n",boxzlo,boxzhi); fprintf(fp,"ITEM: ATOMS %s\n",columns); } /* ---------------------------------------------------------------------- */ -void DumpCustom::header_item_triclinic(int ndump) +void DumpCustom::header_item_triclinic(bigint ndump) { fprintf(fp,"ITEM: TIMESTEP\n"); - fprintf(fp,"%d\n",update->ntimestep); + fprintf(fp,BIGINT_FORMAT_NL,update->ntimestep); fprintf(fp,"ITEM: NUMBER OF ATOMS\n"); - fprintf(fp,"%d\n",ndump); + fprintf(fp,BIGINT_FORMAT_NL,ndump); fprintf(fp,"ITEM: BOX BOUNDS xy xz yz\n"); fprintf(fp,"%g %g %g\n",boxxlo,boxxhi,boxxy); fprintf(fp,"%g %g %g\n",boxylo,boxyhi,boxxz); fprintf(fp,"%g %g %g\n",boxzlo,boxzhi,boxyz); fprintf(fp,"ITEM: ATOMS %s\n",columns); } /* ---------------------------------------------------------------------- */ int DumpCustom::count() { int i; // grow choose and variable vbuf arrays if needed int nlocal = atom->nlocal; if (nlocal > maxlocal) { maxlocal = atom->nmax; memory->sfree(choose); memory->sfree(dchoose); choose = (int *) memory->smalloc(maxlocal*sizeof(int),"dump:choose"); dchoose = (double *) memory->smalloc(maxlocal*sizeof(double),"dump:dchoose"); for (i = 0; i < nvariable; i++) { memory->sfree(vbuf[i]); vbuf[i] = (double *) memory->smalloc(maxlocal*sizeof(double),"dump:vbuf"); } } // invoke Computes for per-atom quantities if (ncompute) { - int ntimestep = update->ntimestep; for (i = 0; i < ncompute; i++) if (!(compute[i]->invoked_flag & INVOKED_PERATOM)) { compute[i]->compute_peratom(); compute[i]->invoked_flag |= INVOKED_PERATOM; } } // evaluate atom-style Variables for per-atom quantities if (nvariable) for (i = 0; i < nvariable; i++) input->variable->compute_atom(variable[i],igroup,vbuf[i],1,0); // choose all local atoms for output for (i = 0; i < nlocal; i++) choose[i] = 1; nmine = nlocal; // un-choose if not in group if (igroup) { int *mask = atom->mask; for (i = 0; i < nlocal; i++) if (!(mask[i] & groupbit)) { choose[i] = 0; nmine--; } } // un-choose if not in region if (iregion >= 0) { Region *region = domain->regions[iregion]; double **x = atom->x; for (i = 0; i < nlocal; i++) if (choose[i] && region->match(x[i][0],x[i][1],x[i][2]) == 0) { choose[i] = 0; nmine--; } } // un-choose if any threshhold criterion isn't met if (nthresh) { double *ptr; double value; int nstride; int nlocal = atom->nlocal; for (int ithresh = 0; ithresh < nthresh; ithresh++) { // customize by adding to if statement if (thresh_array[ithresh] == ID) { int *tag = atom->tag; for (i = 0; i < nlocal; i++) dchoose[i] = tag[i]; ptr = dchoose; nstride = 1; } else if (thresh_array[ithresh] == MOL) { if (!atom->molecule_flag) error->all("Threshhold for an atom property that isn't allocated"); int *molecule = atom->molecule; for (i = 0; i < nlocal; i++) dchoose[i] = molecule[i]; ptr = dchoose; nstride = 1; } else if (thresh_array[ithresh] == TYPE) { int *type = atom->type; for (i = 0; i < nlocal; i++) dchoose[i] = type[i]; ptr = dchoose; nstride = 1; } else if (thresh_array[ithresh] == MASS) { if (atom->rmass) { ptr = atom->rmass; nstride = 1; } else { double *mass = atom->mass; int *type = atom->type; for (i = 0; i < nlocal; i++) dchoose[i] = mass[type[i]]; ptr = dchoose; nstride = 1; } } else if (thresh_array[ithresh] == X) { ptr = &atom->x[0][0]; nstride = 3; } else if (thresh_array[ithresh] == Y) { ptr = &atom->x[0][1]; nstride = 3; } else if (thresh_array[ithresh] == Z) { ptr = &atom->x[0][2]; nstride = 3; } else if (thresh_array[ithresh] == XS) { double **x = atom->x; double boxxlo = domain->boxlo[0]; double invxprd = 1.0/domain->xprd; for (i = 0; i < nlocal; i++) dchoose[i] = (x[i][0] - boxxlo) * invxprd; ptr = dchoose; nstride = 1; } else if (thresh_array[ithresh] == YS) { double **x = atom->x; double boxylo = domain->boxlo[1]; double invyprd = 1.0/domain->yprd; for (i = 0; i < nlocal; i++) dchoose[i] = (x[i][1] - boxylo) * invyprd; ptr = dchoose; nstride = 1; } else if (thresh_array[ithresh] == ZS) { double **x = atom->x; double boxzlo = domain->boxlo[2]; double invzprd = 1.0/domain->zprd; for (i = 0; i < nlocal; i++) dchoose[i] = (x[i][2] - boxzlo) * invzprd; ptr = dchoose; nstride = 1; } else if (thresh_array[ithresh] == XSTRI) { double **x = atom->x; double *boxlo = domain->boxlo; double *h_inv = domain->h_inv; for (i = 0; i < nlocal; i++) dchoose[i] = h_inv[0]*(x[i][0]-boxlo[0]) + h_inv[5]*(x[i][1]-boxlo[1]) + h_inv[4]*(x[i][2]-boxlo[2]); ptr = dchoose; nstride = 1; } else if (thresh_array[ithresh] == YSTRI) { double **x = atom->x; double *boxlo = domain->boxlo; double *h_inv = domain->h_inv; for (i = 0; i < nlocal; i++) dchoose[i] = h_inv[1]*(x[i][1]-boxlo[1]) + h_inv[3]*(x[i][2]-boxlo[2]); ptr = dchoose; nstride = 1; } else if (thresh_array[ithresh] == ZSTRI) { double **x = atom->x; double *boxlo = domain->boxlo; double *h_inv = domain->h_inv; for (i = 0; i < nlocal; i++) dchoose[i] = h_inv[2]*(x[i][2]-boxlo[2]); ptr = dchoose; nstride = 1; } else if (thresh_array[ithresh] == XU) { double **x = atom->x; int *image = atom->image; double xprd = domain->xprd; for (i = 0; i < nlocal; i++) dchoose[i] = x[i][0] + ((image[i] & 1023) - 512) * xprd; ptr = dchoose; nstride = 1; } else if (thresh_array[ithresh] == YU) { double **x = atom->x; int *image = atom->image; double yprd = domain->yprd; for (i = 0; i < nlocal; i++) dchoose[i] = x[i][1] + ((image[i] >> 10 & 1023) - 512) * yprd; ptr = dchoose; nstride = 1; } else if (thresh_array[ithresh] == ZU) { double **x = atom->x; int *image = atom->image; double zprd = domain->zprd; for (i = 0; i < nlocal; i++) dchoose[i] = x[i][2] + ((image[i] >> 20) - 512) * zprd; ptr = dchoose; nstride = 1; } else if (thresh_array[ithresh] == XUTRI) { double **x = atom->x; int *image = atom->image; double *h = domain->h; int xbox,ybox,zbox; for (i = 0; i < nlocal; i++) { xbox = (image[i] & 1023) - 512; ybox = (image[i] >> 10 & 1023) - 512; zbox = (image[i] >> 20) - 512; dchoose[i] = x[i][0] + h[0]*xbox + h[5]*ybox + h[4]*zbox; } ptr = dchoose; nstride = 1; } else if (thresh_array[ithresh] == YUTRI) { double **x = atom->x; int *image = atom->image; double *h = domain->h; int ybox,zbox; for (i = 0; i < nlocal; i++) { ybox = (image[i] >> 10 & 1023) - 512; zbox = (image[i] >> 20) - 512; dchoose[i] = x[i][1] + h[1]*ybox + h[3]*zbox; } ptr = dchoose; nstride = 1; } else if (thresh_array[ithresh] == ZUTRI) { double **x = atom->x; int *image = atom->image; double *h = domain->h; int zbox; for (i = 0; i < nlocal; i++) { zbox = (image[i] >> 20) - 512; dchoose[i] = x[i][2] + h[2]*zbox; } ptr = dchoose; nstride = 1; } else if (thresh_array[ithresh] == IX) { int *image = atom->image; for (i = 0; i < nlocal; i++) dchoose[i] = (image[i] & 1023) - 512; ptr = dchoose; nstride = 1; } else if (thresh_array[ithresh] == IY) { int *image = atom->image; for (i = 0; i < nlocal; i++) dchoose[i] = (image[i] >> 10 & 1023) - 512; ptr = dchoose; nstride = 1; } else if (thresh_array[ithresh] == IZ) { int *image = atom->image; for (i = 0; i < nlocal; i++) dchoose[i] = (image[i] >> 20) - 512; ptr = dchoose; nstride = 1; } else if (thresh_array[ithresh] == VX) { ptr = &atom->v[0][0]; nstride = 3; } else if (thresh_array[ithresh] == VY) { ptr = &atom->v[0][1]; nstride = 3; } else if (thresh_array[ithresh] == VZ) { ptr = &atom->v[0][2]; nstride = 3; } else if (thresh_array[ithresh] == FX) { ptr = &atom->f[0][0]; nstride = 3; } else if (thresh_array[ithresh] == FY) { ptr = &atom->f[0][1]; nstride = 3; } else if (thresh_array[ithresh] == FZ) { ptr = &atom->f[0][2]; nstride = 3; } else if (thresh_array[ithresh] == Q) { if (!atom->q_flag) error->all("Threshhold for an atom property that isn't allocated"); ptr = atom->q; nstride = 1; } else if (thresh_array[ithresh] == MUX) { if (!atom->mu_flag) error->all("Threshhold for an atom property that isn't allocated"); ptr = &atom->mu[0][0]; nstride = 3; } else if (thresh_array[ithresh] == MUY) { if (!atom->mu_flag) error->all("Threshhold for an atom property that isn't allocated"); ptr = &atom->mu[0][1]; nstride = 3; } else if (thresh_array[ithresh] == MUZ) { if (!atom->mu_flag) error->all("Threshhold for an atom property that isn't allocated"); ptr = &atom->mu[0][2]; nstride = 3; } else if (thresh_array[ithresh] == RADIUS) { if (!atom->radius_flag) error->all("Threshhold for an atom property that isn't allocated"); ptr = atom->radius; nstride = 1; } else if (thresh_array[ithresh] == OMEGAX) { if (!atom->omega_flag) error->all("Threshhold for an atom property that isn't allocated"); ptr = &atom->omega[0][0]; nstride = 3; } else if (thresh_array[ithresh] == OMEGAY) { if (!atom->omega_flag) error->all("Threshhold for an atom property that isn't allocated"); ptr = &atom->omega[0][1]; nstride = 3; } else if (thresh_array[ithresh] == OMEGAZ) { if (!atom->omega_flag) error->all("Threshhold for an atom property that isn't allocated"); ptr = &atom->omega[0][2]; nstride = 3; } else if (thresh_array[ithresh] == ANGMOMX) { if (!atom->angmom_flag) error->all("Threshhold for an atom property that isn't allocated"); ptr = &atom->angmom[0][0]; nstride = 3; } else if (thresh_array[ithresh] == ANGMOMY) { if (!atom->angmom_flag) error->all("Threshhold for an atom property that isn't allocated"); ptr = &atom->angmom[0][1]; nstride = 3; } else if (thresh_array[ithresh] == ANGMOMZ) { if (!atom->angmom_flag) error->all("Threshhold for an atom property that isn't allocated"); ptr = &atom->angmom[0][2]; nstride = 3; } else if (thresh_array[ithresh] == QUATW) { if (!atom->quat_flag) error->all("Threshhold for an atom property that isn't allocated"); ptr = &atom->quat[0][0]; nstride = 4; } else if (thresh_array[ithresh] == QUATI) { if (!atom->quat_flag) error->all("Threshhold for an atom property that isn't allocated"); ptr = &atom->quat[0][1]; nstride = 4; } else if (thresh_array[ithresh] == QUATJ) { if (!atom->quat_flag) error->all("Threshhold for an atom property that isn't allocated"); ptr = &atom->quat[0][2]; nstride = 4; } else if (thresh_array[ithresh] == QUATK) { if (!atom->quat_flag) error->all("Threshhold for an atom property that isn't allocated"); ptr = &atom->quat[0][3]; nstride = 4; } else if (thresh_array[ithresh] == TQX) { if (!atom->torque_flag) error->all("Threshhold for an atom property that isn't allocated"); ptr = &atom->torque[0][0]; nstride = 3; } else if (thresh_array[ithresh] == TQY) { if (!atom->torque_flag) error->all("Threshhold for an atom property that isn't allocated"); ptr = &atom->torque[0][1]; nstride = 3; } else if (thresh_array[ithresh] == TQZ) { if (!atom->torque_flag) error->all("Threshhold for an atom property that isn't allocated"); ptr = &atom->torque[0][2]; nstride = 3; } else if (thresh_array[ithresh] == SPIN) { if (!atom->spin_flag) error->all("Threshhold for an atom property that isn't allocated"); int *spin = atom->spin; for (i = 0; i < nlocal; i++) dchoose[i] = spin[i]; ptr = dchoose; nstride = 1; } else if (thresh_array[ithresh] == ERADIUS) { if (!atom->eradius_flag) error->all("Threshhold for an atom property that isn't allocated"); ptr = atom->eradius; nstride = 1; } else if (thresh_array[ithresh] == ERVEL) { if (!atom->ervel_flag) error->all("Threshhold for an atom property that isn't allocated"); ptr = atom->ervel; nstride = 1; } else if (thresh_array[ithresh] == ERFORCE) { if (!atom->erforce_flag) error->all("Threshhold for an atom property that isn't allocated"); ptr = atom->erforce; nstride = 1; } else if (thresh_array[ithresh] == COMPUTE) { i = nfield + ithresh; if (argindex[i] == 0) { ptr = compute[field2index[i]]->vector_atom; nstride = 1; } else { ptr = &compute[field2index[i]]->array_atom[0][argindex[i]-1]; nstride = compute[field2index[i]]->size_peratom_cols; } } else if (thresh_array[ithresh] == FIX) { i = nfield + ithresh; if (argindex[i] == 0) { ptr = fix[field2index[i]]->vector_atom; nstride = 1; } else { ptr = &fix[field2index[i]]->array_atom[0][argindex[i]-1]; nstride = fix[field2index[i]]->size_peratom_cols; } } else if (thresh_array[ithresh] == VARIABLE) { i = nfield + ithresh; ptr = vbuf[field2index[i]]; nstride = 1; } // unselect atoms that don't meet threshhold criterion value = thresh_value[ithresh]; if (thresh_op[ithresh] == LT) { for (i = 0; i < nlocal; i++, ptr += nstride) if (choose[i] && *ptr >= value) { choose[i] = 0; nmine--; } } else if (thresh_op[ithresh] == LE) { for (i = 0; i < nlocal; i++, ptr += nstride) if (choose[i] && *ptr > value) { choose[i] = 0; nmine--; } } else if (thresh_op[ithresh] == GT) { for (i = 0; i < nlocal; i++, ptr += nstride) if (choose[i] && *ptr <= value) { choose[i] = 0; nmine--; } } else if (thresh_op[ithresh] == GE) { for (i = 0; i < nlocal; i++, ptr += nstride) if (choose[i] && *ptr < value) { choose[i] = 0; nmine--; } } else if (thresh_op[ithresh] == EQ) { for (i = 0; i < nlocal; i++, ptr += nstride) if (choose[i] && *ptr != value) { choose[i] = 0; nmine--; } } else if (thresh_op[ithresh] == NEQ) { for (i = 0; i < nlocal; i++, ptr += nstride) if (choose[i] && *ptr == value) { choose[i] = 0; nmine--; } } } } return nmine; } /* ---------------------------------------------------------------------- */ void DumpCustom::pack(int *ids) { for (int n = 0; n < size_one; n++) (this->*pack_choice[n])(n); if (ids) { int *tag = atom->tag; int nlocal = atom->nlocal; int n = 0; for (int i = 0; i < nlocal; i++) if (choose[i]) ids[n++] = tag[i]; } } /* ---------------------------------------------------------------------- */ void DumpCustom::write_data(int n, double *mybuf) { (this->*write_choice)(n,mybuf); } /* ---------------------------------------------------------------------- */ void DumpCustom::write_binary(int n, double *mybuf) { n *= size_one; fwrite(&n,sizeof(int),1,fp); fwrite(mybuf,sizeof(double),n,fp); } /* ---------------------------------------------------------------------- */ void DumpCustom::write_text(int n, double *mybuf) { int i,j; int m = 0; for (i = 0; i < n; i++) { for (j = 0; j < size_one; j++) { if (vtype[j] == INT) fprintf(fp,vformat[j],static_cast<int> (mybuf[m])); else fprintf(fp,vformat[j],mybuf[m]); m++; } fprintf(fp,"\n"); } } /* ---------------------------------------------------------------------- */ void DumpCustom::parse_fields(int narg, char **arg) { // customize by adding to if statement int i; for (int iarg = 5; iarg < narg; iarg++) { i = iarg-5; if (strcmp(arg[iarg],"id") == 0) { pack_choice[i] = &DumpCustom::pack_id; vtype[i] = INT; } else if (strcmp(arg[iarg],"mol") == 0) { if (!atom->molecule_flag) error->all("Dumping an atom property that isn't allocated"); pack_choice[i] = &DumpCustom::pack_molecule; vtype[i] = INT; } else if (strcmp(arg[iarg],"type") == 0) { pack_choice[i] = &DumpCustom::pack_type; vtype[i] = INT; } else if (strcmp(arg[iarg],"mass") == 0) { pack_choice[i] = &DumpCustom::pack_mass; vtype[i] = DOUBLE; } else if (strcmp(arg[iarg],"x") == 0) { pack_choice[i] = &DumpCustom::pack_x; vtype[i] = DOUBLE; } else if (strcmp(arg[iarg],"y") == 0) { pack_choice[i] = &DumpCustom::pack_y; vtype[i] = DOUBLE; } else if (strcmp(arg[iarg],"z") == 0) { pack_choice[i] = &DumpCustom::pack_z; vtype[i] = DOUBLE; } else if (strcmp(arg[iarg],"xs") == 0) { if (domain->triclinic) pack_choice[i] = &DumpCustom::pack_xs_triclinic; else pack_choice[i] = &DumpCustom::pack_xs; vtype[i] = DOUBLE; } else if (strcmp(arg[iarg],"ys") == 0) { if (domain->triclinic) pack_choice[i] = &DumpCustom::pack_ys_triclinic; else pack_choice[i] = &DumpCustom::pack_ys; vtype[i] = DOUBLE; } else if (strcmp(arg[iarg],"zs") == 0) { if (domain->triclinic) pack_choice[i] = &DumpCustom::pack_zs_triclinic; else pack_choice[i] = &DumpCustom::pack_zs; vtype[i] = DOUBLE; } else if (strcmp(arg[iarg],"xu") == 0) { if (domain->triclinic) pack_choice[i] = &DumpCustom::pack_xu_triclinic; else pack_choice[i] = &DumpCustom::pack_xu; vtype[i] = DOUBLE; } else if (strcmp(arg[iarg],"yu") == 0) { if (domain->triclinic) pack_choice[i] = &DumpCustom::pack_yu_triclinic; else pack_choice[i] = &DumpCustom::pack_yu; vtype[i] = DOUBLE; } else if (strcmp(arg[iarg],"zu") == 0) { if (domain->triclinic) pack_choice[i] = &DumpCustom::pack_zu_triclinic; else pack_choice[i] = &DumpCustom::pack_zu; vtype[i] = DOUBLE; } else if (strcmp(arg[iarg],"ix") == 0) { pack_choice[i] = &DumpCustom::pack_ix; vtype[i] = INT; } else if (strcmp(arg[iarg],"iy") == 0) { pack_choice[i] = &DumpCustom::pack_iy; vtype[i] = INT; } else if (strcmp(arg[iarg],"iz") == 0) { pack_choice[i] = &DumpCustom::pack_iz; vtype[i] = INT; } else if (strcmp(arg[iarg],"vx") == 0) { pack_choice[i] = &DumpCustom::pack_vx; vtype[i] = DOUBLE; } else if (strcmp(arg[iarg],"vy") == 0) { pack_choice[i] = &DumpCustom::pack_vy; vtype[i] = DOUBLE; } else if (strcmp(arg[iarg],"vz") == 0) { pack_choice[i] = &DumpCustom::pack_vz; vtype[i] = DOUBLE; } else if (strcmp(arg[iarg],"fx") == 0) { pack_choice[i] = &DumpCustom::pack_fx; vtype[i] = DOUBLE; } else if (strcmp(arg[iarg],"fy") == 0) { pack_choice[i] = &DumpCustom::pack_fy; vtype[i] = DOUBLE; } else if (strcmp(arg[iarg],"fz") == 0) { pack_choice[i] = &DumpCustom::pack_fz; vtype[i] = DOUBLE; } else if (strcmp(arg[iarg],"q") == 0) { if (!atom->q_flag) error->all("Dumping an atom property that isn't allocated"); pack_choice[i] = &DumpCustom::pack_q; vtype[i] = DOUBLE; } else if (strcmp(arg[iarg],"mux") == 0) { if (!atom->mu_flag) error->all("Dumping an atom property that isn't allocated"); pack_choice[i] = &DumpCustom::pack_mux; vtype[i] = DOUBLE; } else if (strcmp(arg[iarg],"muy") == 0) { if (!atom->mu_flag) error->all("Dumping an atom property that isn't allocated"); pack_choice[i] = &DumpCustom::pack_muy; vtype[i] = DOUBLE; } else if (strcmp(arg[iarg],"muz") == 0) { if (!atom->mu_flag) error->all("Dumping an atom property that isn't allocated"); pack_choice[i] = &DumpCustom::pack_muz; vtype[i] = DOUBLE; } else if (strcmp(arg[iarg],"radius") == 0) { if (!atom->radius_flag) error->all("Dumping an atom property that isn't allocated"); pack_choice[i] = &DumpCustom::pack_radius; vtype[i] = DOUBLE; } else if (strcmp(arg[iarg],"omegax") == 0) { if (!atom->omega_flag) error->all("Dumping an atom property that isn't allocated"); pack_choice[i] = &DumpCustom::pack_omegax; vtype[i] = DOUBLE; } else if (strcmp(arg[iarg],"omegay") == 0) { if (!atom->omega_flag) error->all("Dumping an atom property that isn't allocated"); pack_choice[i] = &DumpCustom::pack_omegay; vtype[i] = DOUBLE; } else if (strcmp(arg[iarg],"omegaz") == 0) { if (!atom->omega_flag) error->all("Dumping an atom property that isn't allocated"); pack_choice[i] = &DumpCustom::pack_omegaz; vtype[i] = DOUBLE; } else if (strcmp(arg[iarg],"angmomx") == 0) { if (!atom->angmom_flag) error->all("Dumping an atom property that isn't allocated"); pack_choice[i] = &DumpCustom::pack_angmomx; vtype[i] = DOUBLE; } else if (strcmp(arg[iarg],"angmomy") == 0) { if (!atom->angmom_flag) error->all("Dumping an atom property that isn't allocated"); pack_choice[i] = &DumpCustom::pack_angmomy; vtype[i] = DOUBLE; } else if (strcmp(arg[iarg],"angmomz") == 0) { if (!atom->angmom_flag) error->all("Dumping an atom property that isn't allocated"); pack_choice[i] = &DumpCustom::pack_angmomz; vtype[i] = DOUBLE; } else if (strcmp(arg[iarg],"quatw") == 0) { if (!atom->quat_flag) error->all("Dumping an atom property that isn't allocated"); pack_choice[i] = &DumpCustom::pack_quatw; vtype[i] = DOUBLE; } else if (strcmp(arg[iarg],"quati") == 0) { if (!atom->quat_flag) error->all("Dumping an atom property that isn't allocated"); pack_choice[i] = &DumpCustom::pack_quati; vtype[i] = DOUBLE; } else if (strcmp(arg[iarg],"quatj") == 0) { if (!atom->quat_flag) error->all("Dumping an atom property that isn't allocated"); pack_choice[i] = &DumpCustom::pack_quatj; vtype[i] = DOUBLE; } else if (strcmp(arg[iarg],"quatk") == 0) { if (!atom->quat_flag) error->all("Dumping an atom property that isn't allocated"); pack_choice[i] = &DumpCustom::pack_quatk; vtype[i] = DOUBLE; } else if (strcmp(arg[iarg],"tqx") == 0) { if (!atom->torque_flag) error->all("Dumping an atom property that isn't allocated"); pack_choice[i] = &DumpCustom::pack_tqx; vtype[i] = DOUBLE; } else if (strcmp(arg[iarg],"tqy") == 0) { if (!atom->torque_flag) error->all("Dumping an atom property that isn't allocated"); pack_choice[i] = &DumpCustom::pack_tqy; vtype[i] = DOUBLE; } else if (strcmp(arg[iarg],"tqz") == 0) { if (!atom->torque_flag) error->all("Dumping an atom property that isn't allocated"); pack_choice[i] = &DumpCustom::pack_tqz; vtype[i] = DOUBLE; } else if (strcmp(arg[iarg],"spin") == 0) { if (!atom->spin_flag) error->all("Dumping an atom quantity that isn't allocated"); pack_choice[i] = &DumpCustom::pack_spin; vtype[i] = INT; } else if (strcmp(arg[iarg],"eradius") == 0) { if (!atom->eradius_flag) error->all("Dumping an atom quantity that isn't allocated"); pack_choice[i] = &DumpCustom::pack_eradius; vtype[i] = DOUBLE; } else if (strcmp(arg[iarg],"ervel") == 0) { if (!atom->ervel_flag) error->all("Dumping an atom quantity that isn't allocated"); pack_choice[i] = &DumpCustom::pack_ervel; vtype[i] = DOUBLE; } else if (strcmp(arg[iarg],"erforce") == 0) { if (!atom->erforce_flag) error->all("Dumping an atom quantity that isn't allocated"); pack_choice[i] = &DumpCustom::pack_erforce; vtype[i] = DOUBLE; // compute value = c_ID // if no trailing [], then arg is set to 0, else arg is int between [] } else if (strncmp(arg[iarg],"c_",2) == 0) { pack_choice[i] = &DumpCustom::pack_compute; vtype[i] = DOUBLE; int n = strlen(arg[iarg]); char *suffix = new char[n]; strcpy(suffix,&arg[iarg][2]); char *ptr = strchr(suffix,'['); if (ptr) { if (suffix[strlen(suffix)-1] != ']') error->all("Invalid attribute in dump custom command"); argindex[i] = atoi(ptr+1); *ptr = '\0'; } else argindex[i] = 0; n = modify->find_compute(suffix); if (n < 0) error->all("Could not find dump custom compute ID"); if (modify->compute[n]->peratom_flag == 0) error->all("Dump custom compute does not compute per-atom info"); if (argindex[i] == 0 && modify->compute[n]->size_peratom_cols > 0) error->all("Dump custom compute does not calculate per-atom vector"); if (argindex[i] > 0 && modify->compute[n]->size_peratom_cols == 0) error->all("Dump custom compute does not calculate per-atom array"); if (argindex[i] > 0 && argindex[i] > modify->compute[n]->size_peratom_cols) error->all("Dump custom compute vector is accessed out-of-range"); field2index[i] = add_compute(suffix); delete [] suffix; // fix value = f_ID // if no trailing [], then arg is set to 0, else arg is between [] } else if (strncmp(arg[iarg],"f_",2) == 0) { pack_choice[i] = &DumpCustom::pack_fix; vtype[i] = DOUBLE; int n = strlen(arg[iarg]); char *suffix = new char[n]; strcpy(suffix,&arg[iarg][2]); char *ptr = strchr(suffix,'['); if (ptr) { if (suffix[strlen(suffix)-1] != ']') error->all("Invalid attribute in dump custom command"); argindex[i] = atoi(ptr+1); *ptr = '\0'; } else argindex[i] = 0; n = modify->find_fix(suffix); if (n < 0) error->all("Could not find dump custom fix ID"); if (modify->fix[n]->peratom_flag == 0) error->all("Dump custom fix does not compute per-atom info"); if (argindex[i] == 0 && modify->fix[n]->size_peratom_cols > 0) error->all("Dump custom fix does not compute per-atom vector"); if (argindex[i] > 0 && modify->fix[n]->size_peratom_cols == 0) error->all("Dump custom fix does not compute per-atom array"); if (argindex[i] > 0 && argindex[i] > modify->fix[n]->size_peratom_cols) error->all("Dump custom fix vector is accessed out-of-range"); field2index[i] = add_fix(suffix); delete [] suffix; // variable value = v_name } else if (strncmp(arg[iarg],"v_",2) == 0) { pack_choice[i] = &DumpCustom::pack_variable; vtype[i] = DOUBLE; int n = strlen(arg[iarg]); char *suffix = new char[n]; strcpy(suffix,&arg[iarg][2]); argindex[i] = 0; n = input->variable->find(suffix); if (n < 0) error->all("Could not find dump custom variable name"); if (input->variable->atomstyle(n) == 0) error->all("Dump custom variable is not atom-style variable"); field2index[i] = add_variable(suffix); delete [] suffix; } else error->all("Invalid attribute in dump custom command"); } } /* ---------------------------------------------------------------------- add Compute to list of Compute objects used by dump return index of where this Compute is in list if already in list, do not add, just return index, else add to list ------------------------------------------------------------------------- */ int DumpCustom::add_compute(char *id) { int icompute; for (icompute = 0; icompute < ncompute; icompute++) if (strcmp(id,id_compute[icompute]) == 0) break; if (icompute < ncompute) return icompute; id_compute = (char **) memory->srealloc(id_compute,(ncompute+1)*sizeof(char *),"dump:id_compute"); delete [] compute; compute = new Compute*[ncompute+1]; int n = strlen(id) + 1; id_compute[ncompute] = new char[n]; strcpy(id_compute[ncompute],id); ncompute++; return ncompute-1; } /* ---------------------------------------------------------------------- add Fix to list of Fix objects used by dump return index of where this Fix is in list if already in list, do not add, just return index, else add to list ------------------------------------------------------------------------- */ int DumpCustom::add_fix(char *id) { int ifix; for (ifix = 0; ifix < nfix; ifix++) if (strcmp(id,id_fix[ifix]) == 0) break; if (ifix < nfix) return ifix; id_fix = (char **) memory->srealloc(id_fix,(nfix+1)*sizeof(char *),"dump:id_fix"); delete [] fix; fix = new Fix*[nfix+1]; int n = strlen(id) + 1; id_fix[nfix] = new char[n]; strcpy(id_fix[nfix],id); nfix++; return nfix-1; } /* ---------------------------------------------------------------------- add Variable to list of Variables used by dump return index of where this Variable is in list if already in list, do not add, just return index, else add to list ------------------------------------------------------------------------- */ int DumpCustom::add_variable(char *id) { int ivariable; for (ivariable = 0; ivariable < nvariable; ivariable++) if (strcmp(id,id_variable[ivariable]) == 0) break; if (ivariable < nvariable) return ivariable; id_variable = (char **) memory->srealloc(id_variable,(nvariable+1)*sizeof(char *), "dump:id_variable"); delete [] variable; variable = new int[nvariable+1]; delete [] vbuf; vbuf = new double*[nvariable+1]; for (int i = 0; i <= nvariable; i++) vbuf[i] = NULL; int n = strlen(id) + 1; id_variable[nvariable] = new char[n]; strcpy(id_variable[nvariable],id); nvariable++; return nvariable-1; } /* ---------------------------------------------------------------------- */ int DumpCustom::modify_param(int narg, char **arg) { if (strcmp(arg[0],"region") == 0) { if (narg < 2) error->all("Illegal dump_modify command"); if (strcmp(arg[1],"none") == 0) iregion = -1; else { iregion = domain->find_region(arg[1]); if (iregion == -1) error->all("Dump_modify region ID does not exist"); int n = strlen(arg[1]) + 1; idregion = new char[n]; strcpy(idregion,arg[1]); } return 2; } else if (strcmp(arg[0],"thresh") == 0) { if (narg < 2) error->all("Illegal dump_modify command"); if (strcmp(arg[1],"none") == 0) { if (nthresh) { memory->sfree(thresh_array); memory->sfree(thresh_op); memory->sfree(thresh_value); thresh_array = NULL; thresh_op = NULL; thresh_value = NULL; } nthresh = 0; return 2; } if (narg < 4) error->all("Illegal dump_modify command"); // grow threshhold arrays thresh_array = (int *) memory->srealloc(thresh_array,(nthresh+1)*sizeof(int), "dump:thresh_array"); thresh_op = (int *) memory->srealloc(thresh_op,(nthresh+1)*sizeof(int), "dump:thresh_op"); thresh_value = (double *) memory->srealloc(thresh_value,(nthresh+1)*sizeof(double), "dump:thresh_value"); // set attribute type of threshhold // customize by adding to if statement if (strcmp(arg[1],"id") == 0) thresh_array[nthresh] = ID; else if (strcmp(arg[1],"mol") == 0) thresh_array[nthresh] = MOL; else if (strcmp(arg[1],"type") == 0) thresh_array[nthresh] = TYPE; else if (strcmp(arg[1],"mass") == 0) thresh_array[nthresh] = MASS; else if (strcmp(arg[1],"x") == 0) thresh_array[nthresh] = X; else if (strcmp(arg[1],"y") == 0) thresh_array[nthresh] = Y; else if (strcmp(arg[1],"z") == 0) thresh_array[nthresh] = Z; else if (strcmp(arg[1],"xs") == 0 && domain->triclinic == 0) thresh_array[nthresh] = XS; else if (strcmp(arg[1],"xs") == 0 && domain->triclinic == 1) thresh_array[nthresh] = XSTRI; else if (strcmp(arg[1],"ys") == 0 && domain->triclinic == 0) thresh_array[nthresh] = YS; else if (strcmp(arg[1],"ys") == 0 && domain->triclinic == 1) thresh_array[nthresh] = YSTRI; else if (strcmp(arg[1],"zs") == 0 && domain->triclinic == 0) thresh_array[nthresh] = ZS; else if (strcmp(arg[1],"zs") == 0 && domain->triclinic == 1) thresh_array[nthresh] = ZSTRI; else if (strcmp(arg[1],"xu") == 0 && domain->triclinic == 0) thresh_array[nthresh] = XU; else if (strcmp(arg[1],"xu") == 0 && domain->triclinic == 1) thresh_array[nthresh] = XUTRI; else if (strcmp(arg[1],"yu") == 0 && domain->triclinic == 0) thresh_array[nthresh] = YU; else if (strcmp(arg[1],"yu") == 0 && domain->triclinic == 1) thresh_array[nthresh] = YUTRI; else if (strcmp(arg[1],"zu") == 0 && domain->triclinic == 0) thresh_array[nthresh] = ZU; else if (strcmp(arg[1],"zu") == 0 && domain->triclinic == 1) thresh_array[nthresh] = ZUTRI; else if (strcmp(arg[1],"ix") == 0) thresh_array[nthresh] = IX; else if (strcmp(arg[1],"iy") == 0) thresh_array[nthresh] = IY; else if (strcmp(arg[1],"iz") == 0) thresh_array[nthresh] = IZ; else if (strcmp(arg[1],"vx") == 0) thresh_array[nthresh] = VX; else if (strcmp(arg[1],"vy") == 0) thresh_array[nthresh] = VY; else if (strcmp(arg[1],"vz") == 0) thresh_array[nthresh] = VZ; else if (strcmp(arg[1],"fx") == 0) thresh_array[nthresh] = FX; else if (strcmp(arg[1],"fy") == 0) thresh_array[nthresh] = FY; else if (strcmp(arg[1],"fz") == 0) thresh_array[nthresh] = FZ; else if (strcmp(arg[1],"q") == 0) thresh_array[nthresh] = Q; else if (strcmp(arg[1],"mux") == 0) thresh_array[nthresh] = MUX; else if (strcmp(arg[1],"muy") == 0) thresh_array[nthresh] = MUY; else if (strcmp(arg[1],"muz") == 0) thresh_array[nthresh] = MUZ; else if (strcmp(arg[1],"radius") == 0) thresh_array[nthresh] = RADIUS; else if (strcmp(arg[1],"omegax") == 0) thresh_array[nthresh] = OMEGAX; else if (strcmp(arg[1],"omegay") == 0) thresh_array[nthresh] = OMEGAY; else if (strcmp(arg[1],"omegaz") == 0) thresh_array[nthresh] = OMEGAZ; else if (strcmp(arg[1],"angmomx") == 0) thresh_array[nthresh] = ANGMOMX; else if (strcmp(arg[1],"angmomy") == 0) thresh_array[nthresh] = ANGMOMY; else if (strcmp(arg[1],"angmomz") == 0) thresh_array[nthresh] = ANGMOMZ; else if (strcmp(arg[1],"quatw") == 0) thresh_array[nthresh] = QUATW; else if (strcmp(arg[1],"quati") == 0) thresh_array[nthresh] = QUATI; else if (strcmp(arg[1],"quatj") == 0) thresh_array[nthresh] = QUATJ; else if (strcmp(arg[1],"quatk") == 0) thresh_array[nthresh] = QUATK; else if (strcmp(arg[1],"tqx") == 0) thresh_array[nthresh] = TQX; else if (strcmp(arg[1],"tqy") == 0) thresh_array[nthresh] = TQY; else if (strcmp(arg[1],"tqz") == 0) thresh_array[nthresh] = TQZ; else if (strcmp(arg[1],"spin") == 0) thresh_array[nthresh] = SPIN; else if (strcmp(arg[1],"eradius") == 0) thresh_array[nthresh] = ERADIUS; else if (strcmp(arg[1],"ervel") == 0) thresh_array[nthresh] = ERVEL; else if (strcmp(arg[1],"erforce") == 0) thresh_array[nthresh] = ERFORCE; // compute value = c_ID // if no trailing [], then arg is set to 0, else arg is between [] // must grow field2index and argindex arrays, since access is beyond nfield else if (strncmp(arg[1],"c_",2) == 0) { thresh_array[nthresh] = COMPUTE; field2index = (int *) memory->srealloc(field2index, (nfield+nthresh+1)*sizeof(int), "dump:field2index"); argindex = (int *) memory->srealloc(argindex, (nfield+nthresh+1)*sizeof(int), "dump:argindex"); int n = strlen(arg[1]); char *suffix = new char[n]; strcpy(suffix,&arg[1][2]); char *ptr = strchr(suffix,'['); if (ptr) { if (suffix[strlen(suffix)-1] != ']') error->all("Invalid attribute in dump modify command"); argindex[nfield+nthresh] = atoi(ptr+1); *ptr = '\0'; } else argindex[nfield+nthresh] = 0; n = modify->find_compute(suffix); if (n < 0) error->all("Could not find dump modify compute ID"); if (modify->compute[n]->peratom_flag == 0) error->all("Dump modify compute ID does not compute per-atom info"); if (argindex[nfield+nthresh] == 0 && modify->compute[n]->size_peratom_cols > 0) error->all("Dump modify compute ID does not compute per-atom vector"); if (argindex[nfield+nthresh] > 0 && modify->compute[n]->size_peratom_cols == 0) error->all("Dump modify compute ID does not compute per-atom array"); if (argindex[nfield+nthresh] > 0 && argindex[nfield+nthresh] > modify->compute[n]->size_peratom_cols) error->all("Dump modify compute ID vector is not large enough"); field2index[nfield+nthresh] = add_compute(suffix); delete [] suffix; // fix value = f_ID // if no trailing [], then arg is set to 0, else arg is between [] // must grow field2index and argindex arrays, since access is beyond nfield } else if (strncmp(arg[1],"f_",2) == 0) { thresh_array[nthresh] = FIX; field2index = (int *) memory->srealloc(field2index, (nfield+nthresh+1)*sizeof(int), "dump:field2index"); argindex = (int *) memory->srealloc(argindex, (nfield+nthresh+1)*sizeof(int), "dump:argindex"); int n = strlen(arg[1]); char *suffix = new char[n]; strcpy(suffix,&arg[1][2]); char *ptr = strchr(suffix,'['); if (ptr) { if (suffix[strlen(suffix)-1] != ']') error->all("Invalid attribute in dump modify command"); argindex[nfield+nthresh] = atoi(ptr+1); *ptr = '\0'; } else argindex[nfield+nthresh] = 0; n = modify->find_fix(suffix); if (n < 0) error->all("Could not find dump modify fix ID"); if (modify->fix[n]->peratom_flag == 0) error->all("Dump modify fix ID does not compute per-atom info"); if (argindex[nfield+nthresh] == 0 && modify->fix[n]->size_peratom_cols > 0) error->all("Dump modify fix ID does not compute per-atom vector"); if (argindex[nfield+nthresh] > 0 && modify->fix[n]->size_peratom_cols == 0) error->all("Dump modify fix ID does not compute per-atom array"); if (argindex[nfield+nthresh] > 0 && argindex[nfield+nthresh] > modify->fix[n]->size_peratom_cols) error->all("Dump modify fix ID vector is not large enough"); field2index[nfield+nthresh] = add_fix(suffix); delete [] suffix; // variable value = v_ID // must grow field2index and argindex arrays, since access is beyond nfield } else if (strncmp(arg[1],"v_",2) == 0) { thresh_array[nthresh] = VARIABLE; field2index = (int *) memory->srealloc(field2index, (nfield+nthresh+1)*sizeof(int), "dump:field2index"); argindex = (int *) memory->srealloc(argindex, (nfield+nthresh+1)*sizeof(int), "dump:argindex"); int n = strlen(arg[1]); char *suffix = new char[n]; strcpy(suffix,&arg[1][2]); argindex[nfield+nthresh] = 0; n = input->variable->find(suffix); if (n < 0) error->all("Could not find dump modify variable name"); if (input->variable->atomstyle(n) == 0) error->all("Dump modify variable is not atom-style variable"); field2index[nfield+nthresh] = add_variable(suffix); delete [] suffix; } else error->all("Invalid dump_modify threshhold operator"); // set operation type of threshhold if (strcmp(arg[2],"<") == 0) thresh_op[nthresh] = LT; else if (strcmp(arg[2],"<=") == 0) thresh_op[nthresh] = LE; else if (strcmp(arg[2],">") == 0) thresh_op[nthresh] = GT; else if (strcmp(arg[2],">=") == 0) thresh_op[nthresh] = GE; else if (strcmp(arg[2],"==") == 0) thresh_op[nthresh] = EQ; else if (strcmp(arg[2],"!=") == 0) thresh_op[nthresh] = NEQ; else error->all("Invalid dump_modify threshhold operator"); // set threshhold value thresh_value[nthresh] = atof(arg[3]); nthresh++; return 4; // pass along unknown params to child class } else { int n = modify_param2(narg,arg); return n; } return 0; } /* ---------------------------------------------------------------------- return # of bytes of allocated memory in buf, choose, variable arrays ------------------------------------------------------------------------- */ double DumpCustom::memory_usage() { double bytes = Dump::memory_usage(); bytes += maxlocal * sizeof(int); bytes += maxlocal * sizeof(double); bytes += maxlocal * nvariable * sizeof(double); return bytes; } /* ---------------------------------------------------------------------- extraction of Compute, Fix, Variable results ------------------------------------------------------------------------- */ void DumpCustom::pack_compute(int n) { double *vector = compute[field2index[n]]->vector_atom; double **array = compute[field2index[n]]->array_atom; int index = argindex[n]; int nlocal = atom->nlocal; if (index == 0) { for (int i = 0; i < nlocal; i++) if (choose[i]) { buf[n] = vector[i]; n += size_one; } } else { index--; for (int i = 0; i < nlocal; i++) if (choose[i]) { buf[n] = array[i][index]; n += size_one; } } } /* ---------------------------------------------------------------------- */ void DumpCustom::pack_fix(int n) { double *vector = fix[field2index[n]]->vector_atom; double **array = fix[field2index[n]]->array_atom; int index = argindex[n]; int nlocal = atom->nlocal; if (index == 0) { for (int i = 0; i < nlocal; i++) if (choose[i]) { buf[n] = vector[i]; n += size_one; } } else { index--; for (int i = 0; i < nlocal; i++) if (choose[i]) { buf[n] = array[i][index]; n += size_one; } } } /* ---------------------------------------------------------------------- */ void DumpCustom::pack_variable(int n) { double *vector = vbuf[field2index[n]]; int nlocal = atom->nlocal; for (int i = 0; i < nlocal; i++) if (choose[i]) { buf[n] = vector[i]; n += size_one; } } /* ---------------------------------------------------------------------- one method for every attribute dump custom can output the atom property is packed into buf starting at n with stride size_one customize a new attribute by adding a method ------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */ void DumpCustom::pack_id(int n) { int *tag = atom->tag; int nlocal = atom->nlocal; for (int i = 0; i < nlocal; i++) if (choose[i]) { buf[n] = tag[i]; n += size_one; } } /* ---------------------------------------------------------------------- */ void DumpCustom::pack_molecule(int n) { int *molecule = atom->molecule; int nlocal = atom->nlocal; for (int i = 0; i < nlocal; i++) if (choose[i]) { buf[n] = molecule[i]; n += size_one; } } /* ---------------------------------------------------------------------- */ void DumpCustom::pack_type(int n) { int *type = atom->type; int nlocal = atom->nlocal; for (int i = 0; i < nlocal; i++) if (choose[i]) { buf[n] = type[i]; n += size_one; } } /* ---------------------------------------------------------------------- */ void DumpCustom::pack_mass(int n) { int *type = atom->type; double *mass = atom->mass; double *rmass = atom->rmass; int nlocal = atom->nlocal; if (rmass) { for (int i = 0; i < nlocal; i++) if (choose[i]) { buf[n] = rmass[i]; n += size_one; } } else { for (int i = 0; i < nlocal; i++) if (choose[i]) { buf[n] = mass[type[i]]; n += size_one; } } } /* ---------------------------------------------------------------------- */ void DumpCustom::pack_x(int n) { double **x = atom->x; int nlocal = atom->nlocal; for (int i = 0; i < nlocal; i++) if (choose[i]) { buf[n] = x[i][0]; n += size_one; } } /* ---------------------------------------------------------------------- */ void DumpCustom::pack_y(int n) { double **x = atom->x; int nlocal = atom->nlocal; for (int i = 0; i < nlocal; i++) if (choose[i]) { buf[n] = x[i][1]; n += size_one; } } /* ---------------------------------------------------------------------- */ void DumpCustom::pack_z(int n) { double **x = atom->x; int nlocal = atom->nlocal; for (int i = 0; i < nlocal; i++) if (choose[i]) { buf[n] = x[i][2]; n += size_one; } } /* ---------------------------------------------------------------------- */ void DumpCustom::pack_xs(int n) { double **x = atom->x; int nlocal = atom->nlocal; double boxxlo = domain->boxlo[0]; double invxprd = 1.0/domain->xprd; for (int i = 0; i < nlocal; i++) if (choose[i]) { buf[n] = (x[i][0] - boxxlo) * invxprd; n += size_one; } } /* ---------------------------------------------------------------------- */ void DumpCustom::pack_ys(int n) { double **x = atom->x; int nlocal = atom->nlocal; double boxylo = domain->boxlo[1]; double invyprd = 1.0/domain->yprd; for (int i = 0; i < nlocal; i++) if (choose[i]) { buf[n] = (x[i][1] - boxylo) * invyprd; n += size_one; } } /* ---------------------------------------------------------------------- */ void DumpCustom::pack_zs(int n) { double **x = atom->x; int nlocal = atom->nlocal; double boxzlo = domain->boxlo[2]; double invzprd = 1.0/domain->zprd; for (int i = 0; i < nlocal; i++) if (choose[i]) { buf[n] = (x[i][2] - boxzlo) * invzprd; n += size_one; } } /* ---------------------------------------------------------------------- */ void DumpCustom::pack_xs_triclinic(int n) { double **x = atom->x; int nlocal = atom->nlocal; double *boxlo = domain->boxlo; double *h_inv = domain->h_inv; for (int i = 0; i < nlocal; i++) if (choose[i]) { buf[n] = h_inv[0]*(x[i][0]-boxlo[0]) + h_inv[5]*(x[i][1]-boxlo[1]) + h_inv[4]*(x[i][2]-boxlo[2]); n += size_one; } } /* ---------------------------------------------------------------------- */ void DumpCustom::pack_ys_triclinic(int n) { double **x = atom->x; int nlocal = atom->nlocal; double *boxlo = domain->boxlo; double *h_inv = domain->h_inv; for (int i = 0; i < nlocal; i++) if (choose[i]) { buf[n] = h_inv[1]*(x[i][1]-boxlo[1]) + h_inv[3]*(x[i][2]-boxlo[2]); n += size_one; } } /* ---------------------------------------------------------------------- */ void DumpCustom::pack_zs_triclinic(int n) { double **x = atom->x; int nlocal = atom->nlocal; double *boxlo = domain->boxlo; double *h_inv = domain->h_inv; for (int i = 0; i < nlocal; i++) if (choose[i]) { buf[n] = h_inv[2]*(x[i][2]-boxlo[2]); n += size_one; } } /* ---------------------------------------------------------------------- */ void DumpCustom::pack_xu(int n) { double **x = atom->x; int *image = atom->image; int nlocal = atom->nlocal; double xprd = domain->xprd; for (int i = 0; i < nlocal; i++) if (choose[i]) { buf[n] = x[i][0] + ((image[i] & 1023) - 512) * xprd; n += size_one; } } /* ---------------------------------------------------------------------- */ void DumpCustom::pack_yu(int n) { double **x = atom->x; int *image = atom->image; int nlocal = atom->nlocal; double yprd = domain->yprd; for (int i = 0; i < nlocal; i++) if (choose[i]) { buf[n] = x[i][1] + ((image[i] >> 10 & 1023) - 512) * yprd; n += size_one; } } /* ---------------------------------------------------------------------- */ void DumpCustom::pack_zu(int n) { double **x = atom->x; int *image = atom->image; int nlocal = atom->nlocal; double zprd = domain->zprd; for (int i = 0; i < nlocal; i++) if (choose[i]) { buf[n] = x[i][2] + ((image[i] >> 20) - 512) * zprd; n += size_one; } } /* ---------------------------------------------------------------------- */ void DumpCustom::pack_xu_triclinic(int n) { double **x = atom->x; int *image = atom->image; int nlocal = atom->nlocal; double *h = domain->h; int xbox,ybox,zbox; for (int i = 0; i < nlocal; i++) if (choose[i]) { xbox = (image[i] & 1023) - 512; ybox = (image[i] >> 10 & 1023) - 512; zbox = (image[i] >> 20) - 512; buf[n] = x[i][0] + h[0]*xbox + h[5]*ybox + h[4]*zbox; n += size_one; } } /* ---------------------------------------------------------------------- */ void DumpCustom::pack_yu_triclinic(int n) { double **x = atom->x; int *image = atom->image; int nlocal = atom->nlocal; double *h = domain->h; int ybox,zbox; for (int i = 0; i < nlocal; i++) if (choose[i]) { ybox = (image[i] >> 10 & 1023) - 512; zbox = (image[i] >> 20) - 512; buf[n] = x[i][1] + h[1]*ybox + h[3]*zbox; n += size_one; } } /* ---------------------------------------------------------------------- */ void DumpCustom::pack_zu_triclinic(int n) { double **x = atom->x; int *image = atom->image; int nlocal = atom->nlocal; double *h = domain->h; int zbox; for (int i = 0; i < nlocal; i++) if (choose[i]) { zbox = (image[i] >> 20) - 512; buf[n] = x[i][2] + h[2]*zbox; n += size_one; } } /* ---------------------------------------------------------------------- */ void DumpCustom::pack_ix(int n) { int *image = atom->image; int nlocal = atom->nlocal; for (int i = 0; i < nlocal; i++) if (choose[i]) { buf[n] = (image[i] & 1023) - 512; n += size_one; } } /* ---------------------------------------------------------------------- */ void DumpCustom::pack_iy(int n) { int *image = atom->image; int nlocal = atom->nlocal; for (int i = 0; i < nlocal; i++) if (choose[i]) { buf[n] = (image[i] >> 10 & 1023) - 512; n += size_one; } } /* ---------------------------------------------------------------------- */ void DumpCustom::pack_iz(int n) { int *image = atom->image; int nlocal = atom->nlocal; for (int i = 0; i < nlocal; i++) if (choose[i]) { buf[n] = (image[i] >> 20) - 512; n += size_one; } } /* ---------------------------------------------------------------------- */ void DumpCustom::pack_vx(int n) { double **v = atom->v; int nlocal = atom->nlocal; for (int i = 0; i < nlocal; i++) if (choose[i]) { buf[n] = v[i][0]; n += size_one; } } /* ---------------------------------------------------------------------- */ void DumpCustom::pack_vy(int n) { double **v = atom->v; int nlocal = atom->nlocal; for (int i = 0; i < nlocal; i++) if (choose[i]) { buf[n] = v[i][1]; n += size_one; } } /* ---------------------------------------------------------------------- */ void DumpCustom::pack_vz(int n) { double **v = atom->v; int nlocal = atom->nlocal; for (int i = 0; i < nlocal; i++) if (choose[i]) { buf[n] = v[i][2]; n += size_one; } } /* ---------------------------------------------------------------------- */ void DumpCustom::pack_fx(int n) { double **f = atom->f; int nlocal = atom->nlocal; for (int i = 0; i < nlocal; i++) if (choose[i]) { buf[n] = f[i][0]; n += size_one; } } /* ---------------------------------------------------------------------- */ void DumpCustom::pack_fy(int n) { double **f = atom->f; int nlocal = atom->nlocal; for (int i = 0; i < nlocal; i++) if (choose[i]) { buf[n] = f[i][1]; n += size_one; } } /* ---------------------------------------------------------------------- */ void DumpCustom::pack_fz(int n) { double **f = atom->f; int nlocal = atom->nlocal; for (int i = 0; i < nlocal; i++) if (choose[i]) { buf[n] = f[i][2]; n += size_one; } } /* ---------------------------------------------------------------------- */ void DumpCustom::pack_q(int n) { double *q = atom->q; int nlocal = atom->nlocal; for (int i = 0; i < nlocal; i++) if (choose[i]) { buf[n] = q[i]; n += size_one; } } /* ---------------------------------------------------------------------- */ void DumpCustom::pack_mux(int n) { double **mu = atom->mu; int nlocal = atom->nlocal; for (int i = 0; i < nlocal; i++) if (choose[i]) { buf[n] = mu[i][0]; n += size_one; } } /* ---------------------------------------------------------------------- */ void DumpCustom::pack_muy(int n) { double **mu = atom->mu; int nlocal = atom->nlocal; for (int i = 0; i < nlocal; i++) if (choose[i]) { buf[n] = mu[i][1]; n += size_one; } } /* ---------------------------------------------------------------------- */ void DumpCustom::pack_muz(int n) { double **mu = atom->mu; int nlocal = atom->nlocal; for (int i = 0; i < nlocal; i++) if (choose[i]) { buf[n] = mu[i][2]; n += size_one; } } /* ---------------------------------------------------------------------- */ void DumpCustom::pack_radius(int n) { double *radius = atom->radius; int nlocal = atom->nlocal; for (int i = 0; i < nlocal; i++) if (choose[i]) { buf[n] = radius[i]; n += size_one; } } /* ---------------------------------------------------------------------- */ void DumpCustom::pack_omegax(int n) { double **omega = atom->omega; int nlocal = atom->nlocal; for (int i = 0; i < nlocal; i++) if (choose[i]) { buf[n] = omega[i][0]; n += size_one; } } /* ---------------------------------------------------------------------- */ void DumpCustom::pack_omegay(int n) { double **omega = atom->omega; int nlocal = atom->nlocal; for (int i = 0; i < nlocal; i++) if (choose[i]) { buf[n] = omega[i][1]; n += size_one; } } /* ---------------------------------------------------------------------- */ void DumpCustom::pack_omegaz(int n) { double **omega = atom->omega; int nlocal = atom->nlocal; for (int i = 0; i < nlocal; i++) if (choose[i]) { buf[n] = omega[i][2]; n += size_one; } } /* ---------------------------------------------------------------------- */ void DumpCustom::pack_angmomx(int n) { double **angmom = atom->angmom; int nlocal = atom->nlocal; for (int i = 0; i < nlocal; i++) if (choose[i]) { buf[n] = angmom[i][0]; n += size_one; } } /* ---------------------------------------------------------------------- */ void DumpCustom::pack_angmomy(int n) { double **angmom = atom->angmom; int nlocal = atom->nlocal; for (int i = 0; i < nlocal; i++) if (choose[i]) { buf[n] = angmom[i][1]; n += size_one; } } /* ---------------------------------------------------------------------- */ void DumpCustom::pack_angmomz(int n) { double **angmom = atom->angmom; int nlocal = atom->nlocal; for (int i = 0; i < nlocal; i++) if (choose[i]) { buf[n] = angmom[i][2]; n += size_one; } } /* ---------------------------------------------------------------------- */ void DumpCustom::pack_quatw(int n) { double **quat = atom->quat; int nlocal = atom->nlocal; for (int i = 0; i < nlocal; i++) if (choose[i]) { buf[n] = quat[i][0]; n += size_one; } } /* ---------------------------------------------------------------------- */ void DumpCustom::pack_quati(int n) { double **quat = atom->quat; int nlocal = atom->nlocal; for (int i = 0; i < nlocal; i++) if (choose[i]) { buf[n] = quat[i][1]; n += size_one; } } /* ---------------------------------------------------------------------- */ void DumpCustom::pack_quatj(int n) { double **quat = atom->quat; int nlocal = atom->nlocal; for (int i = 0; i < nlocal; i++) if (choose[i]) { buf[n] = quat[i][2]; n += size_one; } } /* ---------------------------------------------------------------------- */ void DumpCustom::pack_quatk(int n) { double **quat = atom->quat; int nlocal = atom->nlocal; for (int i = 0; i < nlocal; i++) if (choose[i]) { buf[n] = quat[i][3]; n += size_one; } } /* ---------------------------------------------------------------------- */ void DumpCustom::pack_tqx(int n) { double **torque = atom->torque; int nlocal = atom->nlocal; for (int i = 0; i < nlocal; i++) if (choose[i]) { buf[n] = torque[i][0]; n += size_one; } } /* ---------------------------------------------------------------------- */ void DumpCustom::pack_tqy(int n) { double **torque = atom->torque; int nlocal = atom->nlocal; for (int i = 0; i < nlocal; i++) if (choose[i]) { buf[n] = torque[i][1]; n += size_one; } } /* ---------------------------------------------------------------------- */ void DumpCustom::pack_tqz(int n) { double **torque = atom->torque; int nlocal = atom->nlocal; for (int i = 0; i < nlocal; i++) if (choose[i]) { buf[n] = torque[i][2]; n += size_one; } } /* ---------------------------------------------------------------------- */ void DumpCustom::pack_spin(int n) { int *spin = atom->spin; int nlocal = atom->nlocal; for (int i = 0; i < nlocal; i++) if (choose[i]) { buf[n] = spin[i]; n += size_one; } } /* ---------------------------------------------------------------------- */ void DumpCustom::pack_eradius(int n) { double *eradius = atom->eradius; int nlocal = atom->nlocal; for (int i = 0; i < nlocal; i++) if (choose[i]) { buf[n] = eradius[i]; n += size_one; } } /* ---------------------------------------------------------------------- */ void DumpCustom::pack_ervel(int n) { double *ervel = atom->ervel; int nlocal = atom->nlocal; for (int i = 0; i < nlocal; i++) if (choose[i]) { buf[n] = ervel[i]; n += size_one; } } /* ---------------------------------------------------------------------- */ void DumpCustom::pack_erforce(int n) { double *erforce = atom->erforce; int nlocal = atom->nlocal; for (int i = 0; i < nlocal; i++) if (choose[i]) { buf[n] = erforce[i]; n += size_one; } } diff --git a/src/dump_custom.h b/src/dump_custom.h index 18be848f0..0f7913272 100644 --- a/src/dump_custom.h +++ b/src/dump_custom.h @@ -1,164 +1,164 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ #ifdef DUMP_CLASS DumpStyle(custom,DumpCustom) #else #ifndef LMP_DUMP_CUSTOM_H #define LMP_DUMP_CUSTOM_H #include "dump.h" namespace LAMMPS_NS { class DumpCustom : public Dump { public: DumpCustom(class LAMMPS *, int, char **); virtual ~DumpCustom(); protected: int nevery; // dump frequency to check Fix against int iregion; // -1 if no region, else which region char *idregion; // region ID int nthresh; // # of defined threshholds int *thresh_array; // array to threshhhold on for each nthresh int *thresh_op; // threshhold operation for each nthresh double *thresh_value; // threshhold value for each nthresh int nmine; // # of lines I am dumping int *vtype; // type of each vector (INT, DOUBLE) char **vformat; // format string for each vector element char *columns; // column labels int maxlocal; // size of atom selection and variable arrays int *choose; // 1 if output this atom, 0 if no double *dchoose; // value for each atom to threshhold against int nfield; // # of keywords listed by user int *field2index; // which compute,fix,variable calcs this field int *argindex; // index into compute,fix scalar_atom,vector_atom // 0 for scalar_atom, 1-N for vector_atom values int ncompute; // # of Compute objects used by dump char **id_compute; // their IDs class Compute **compute; // list of ptrs to the Compute objects int nfix; // # of Fix objects used by dump char **id_fix; // their IDs class Fix **fix; // list of ptrs to the Fix objects int nvariable; // # of Variables used by dump char **id_variable; // their names int *variable; // list of indices for the Variables double **vbuf; // local storage for variable evaluation // private methods virtual void init_style(); - virtual void write_header(int); + virtual void write_header(bigint); int count(); void pack(int *); virtual void write_data(int, double *); double memory_usage(); void parse_fields(int, char **); int add_compute(char *); int add_fix(char *); int add_variable(char *); int modify_param(int, char **); virtual int modify_param2(int, char **) {return 0;} - typedef void (DumpCustom::*FnPtrHeader)(int); + typedef void (DumpCustom::*FnPtrHeader)(bigint); FnPtrHeader header_choice; // ptr to write header functions - void header_binary(int); - void header_binary_triclinic(int); - void header_item(int); - void header_item_triclinic(int); + void header_binary(bigint); + void header_binary_triclinic(bigint); + void header_item(bigint); + void header_item_triclinic(bigint); typedef void (DumpCustom::*FnPtrData)(int, double *); FnPtrData write_choice; // ptr to write data functions void write_binary(int, double *); void write_text(int, double *); // customize by adding a method prototype typedef void (DumpCustom::*FnPtrPack)(int); FnPtrPack *pack_choice; // ptrs to pack functions void pack_id(int); void pack_molecule(int); void pack_type(int); void pack_mass(int); void pack_x(int); void pack_y(int); void pack_z(int); void pack_xs(int); void pack_ys(int); void pack_zs(int); void pack_xs_triclinic(int); void pack_ys_triclinic(int); void pack_zs_triclinic(int); void pack_xu(int); void pack_yu(int); void pack_zu(int); void pack_xu_triclinic(int); void pack_yu_triclinic(int); void pack_zu_triclinic(int); void pack_ix(int); void pack_iy(int); void pack_iz(int); void pack_vx(int); void pack_vy(int); void pack_vz(int); void pack_fx(int); void pack_fy(int); void pack_fz(int); void pack_q(int); void pack_mux(int); void pack_muy(int); void pack_muz(int); void pack_radius(int); void pack_omegax(int); void pack_omegay(int); void pack_omegaz(int); void pack_angmomx(int); void pack_angmomy(int); void pack_angmomz(int); void pack_quatw(int); void pack_quati(int); void pack_quatj(int); void pack_quatk(int); void pack_tqx(int); void pack_tqy(int); void pack_tqz(int); void pack_spin(int); void pack_eradius(int); void pack_ervel(int); void pack_erforce(int); void pack_compute(int); void pack_fix(int); void pack_variable(int); }; } #endif #endif diff --git a/src/dump_dcd.cpp b/src/dump_dcd.cpp index 222b8dc4b..5235ccdf8 100644 --- a/src/dump_dcd.cpp +++ b/src/dump_dcd.cpp @@ -1,369 +1,371 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- Contributing author: Naveen Michaud-Agrawal (Johns Hopkins U) Axel Kohlmeyer (Temple U), support for groups ------------------------------------------------------------------------- */ #include "math.h" #include "inttypes.h" #include "stdio.h" #include "time.h" #include "string.h" #include "dump_dcd.h" #include "lmptype.h" #include "domain.h" #include "atom.h" #include "update.h" #include "output.h" #include "group.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; #define NFILE_POS 8L #define NSTEP_POS 20L // necessary to set SEEK params b/c MPI-2 messes with these settings #ifndef SEEK_SET #define SEEK_SET 0 #define SEEK_CUR 1 #define SEEK_END 2 #endif /* ---------------------------------------------------------------------- */ static inline void fwrite_int32(FILE* fd, uint32_t i) { fwrite(&i,sizeof(uint32_t),1,fd); } /* ---------------------------------------------------------------------- */ DumpDCD::DumpDCD(LAMMPS *lmp, int narg, char **arg) : Dump(lmp, narg, arg) { if (narg != 5) error->all("Illegal dump dcd command"); if (binary || compressed || multifile || multiproc) error->all("Invalid dump dcd filename"); size_one = 3; sort_flag = 1; sortcol = 0; unwrap_flag = 0; format_default = NULL; // allocate global array for atom coords - bigint n; - if (igroup == 0) n = static_cast<int> (atom->natoms); - else n = static_cast<int> (group->count(igroup)); - if (n > MAXINT32) error->all("Too many atoms for dump dcd"); - natoms = n; + bigint n = group->count(igroup); + if (n > MAXSMALLINT/sizeof(float)) error->all("Too many atoms for dump dcd"); + natoms = static_cast<int> (n); coords = (float *) memory->smalloc(3*natoms*sizeof(float),"dump:coords"); xf = &coords[0*natoms]; yf = &coords[1*natoms]; zf = &coords[2*natoms]; openfile(); headerflag = 0; nevery_save = 0; ntotal = 0; } /* ---------------------------------------------------------------------- */ DumpDCD::~DumpDCD() { memory->sfree(coords); } /* ---------------------------------------------------------------------- */ void DumpDCD::init_style() { if (sort_flag == 0 || sortcol != 0) error->all("Dump dcd requires sorting by atom ID"); // check that dump frequency has not changed and is not a variable int idump; for (idump = 0; idump < output->ndump; idump++) if (strcmp(id,output->dump[idump]->id) == 0) break; if (output->every_dump[idump] == 0) error->all("Cannot use variable every setting for dump dcd"); if (nevery_save == 0) nevery_save = output->every_dump[idump]; else if (nevery_save != output->every_dump[idump]) error->all("Cannot change dump_modify every for dump dcd"); } /* ---------------------------------------------------------------------- */ void DumpDCD::openfile() { if (me == 0) { fp = fopen(filename,"wb"); if (fp == NULL) error->one("Cannot open dump file"); } } /* ---------------------------------------------------------------------- */ -void DumpDCD::write_header(int n) +void DumpDCD::write_header(bigint n) { if (n != natoms) error->all("Dump dcd of non-matching # of atoms"); + if (update->ntimestep > MAXSMALLINT) + error->all("Too big a timestep for dump dcd"); // first time, write header for entire file if (headerflag == 0) { if (me == 0) write_dcd_header("Written by LAMMPS"); headerflag = 1; nframes = 0; } // dim[] = size and angle cosines of orthogonal or triclinic box // dim[0] = a = length of unit cell vector along x-axis // dim[1] = gamma = cosine of angle between a and b // dim[2] = b = length of unit cell vector in xy-plane // dim[3] = beta = cosine of angle between a and c // dim[4] = alpha = cosine of angle between b and c // dim[5] = c = length of final unit cell vector // 48 = 6 doubles double dim[6]; if (domain->triclinic) { double *h = domain->h; double alen = h[0]; double blen = sqrt(h[5]*h[5] + h[1]*h[1]); double clen = sqrt(h[4]*h[4] + h[3]*h[3] + h[2]*h[2]); dim[0] = alen; dim[2] = blen; dim[5] = clen; dim[4] = (h[5]*h[4] + h[1]*h[3]) / blen/clen; // alpha dim[3] = (h[0]*h[4]) / alen/clen; // beta dim[1] = (h[0]*h[5]) / alen/blen; // gamma } else { dim[0] = domain->xprd; dim[2] = domain->yprd; dim[5] = domain->zprd; dim[1] = dim[3] = dim[4] = 0.0; } if (me == 0) { uint32_t out_integer = 48; fwrite_int32(fp,out_integer); fwrite(dim,out_integer,1,fp); fwrite_int32(fp,out_integer); if (flush_flag) fflush(fp); } } /* ---------------------------------------------------------------------- */ int DumpDCD::count() { if (igroup == 0) return atom->nlocal; int *mask = atom->mask; int nlocal = atom->nlocal; int m = 0; for (int i = 0; i < nlocal; i++) if (mask[i] & groupbit) m++; return m; } /* ---------------------------------------------------------------------- */ void DumpDCD::pack(int *ids) { int m,n; int *tag = atom->tag; double **x = atom->x; int *image = atom->image; int *mask = atom->mask; int nlocal = atom->nlocal; m = n = 0; if (unwrap_flag) { double xprd = domain->xprd; double yprd = domain->yprd; double zprd = domain->zprd; double xy = domain->xy; double xz = domain->xz; double yz = domain->yz; for (int i = 0; i < nlocal; i++) { if (mask[i] & groupbit) { int ix = (image[i] & 1023) - 512; int iy = (image[i] >> 10 & 1023) - 512; int iz = (image[i] >> 20) - 512; if (domain->triclinic) { buf[m++] = x[i][0] + ix * xprd + iy * xy + iz * xz; buf[m++] = x[i][1] + iy * yprd + iz * yz; buf[m++] = x[i][2] + iz * zprd; } else { buf[m++] = x[i][0] + ix * xprd; buf[m++] = x[i][1] + iy * yprd; buf[m++] = x[i][2] + iz * zprd; } ids[n++] = tag[i]; } } } else { for (int i = 0; i < nlocal; i++) if (mask[i] & groupbit) { buf[m++] = x[i][0]; buf[m++] = x[i][1]; buf[m++] = x[i][2]; ids[n++] = tag[i]; } } } /* ---------------------------------------------------------------------- */ void DumpDCD::write_data(int n, double *mybuf) { // copy buf atom coords into 3 global arrays int m = 0; for (int i = 0; i < n; i++) { xf[ntotal] = mybuf[m++]; yf[ntotal] = mybuf[m++]; zf[ntotal] = mybuf[m++]; ntotal++; } // if last chunk of atoms in this snapshot, write global arrays to file if (ntotal == natoms) { write_frame(); ntotal = 0; } } /* ---------------------------------------------------------------------- */ int DumpDCD::modify_param(int narg, char **arg) { if (strcmp(arg[0],"unwrap") == 0) { if (narg < 2) error->all("Illegal dump_modify command"); if (strcmp(arg[1],"yes") == 0) unwrap_flag = 1; else if (strcmp(arg[1],"no") == 0) unwrap_flag = 0; else error->all("Illegal dump_modify command"); return 2; } return 0; } /* ---------------------------------------------------------------------- return # of bytes of allocated memory in buf and global coords array ------------------------------------------------------------------------- */ double DumpDCD::memory_usage() { double bytes = Dump::memory_usage(); bytes += 3*natoms * sizeof(float); return bytes; } /* ---------------------------------------------------------------------- */ void DumpDCD::write_frame() { // write coords uint32_t out_integer = natoms*sizeof(float); fwrite_int32(fp,out_integer); fwrite(xf,out_integer,1,fp); fwrite_int32(fp,out_integer); fwrite_int32(fp,out_integer); fwrite(yf,out_integer,1,fp); fwrite_int32(fp,out_integer); fwrite_int32(fp,out_integer); fwrite(zf,out_integer,1,fp); fwrite_int32(fp,out_integer); // update NFILE and NSTEP fields in DCD header nframes++; out_integer = nframes; fseek(fp,NFILE_POS,SEEK_SET); fwrite_int32(fp,out_integer); out_integer = update->ntimestep; fseek(fp,NSTEP_POS,SEEK_SET); fwrite_int32(fp,out_integer); fseek(fp,0,SEEK_END); } /* ---------------------------------------------------------------------- */ void DumpDCD::write_dcd_header(const char *remarks) { uint32_t out_integer; float out_float; char title_string[200]; time_t cur_time; struct tm *tmbuf; + int ntimestep = update->ntimestep; + out_integer = 84; fwrite_int32(fp,out_integer); strcpy(title_string,"CORD"); fwrite(title_string,4,1,fp); fwrite_int32(fp,0); // NFILE = # of snapshots in file - fwrite_int32(fp,update->ntimestep); // START = timestep of first snapshot + fwrite_int32(fp,ntimestep); // START = timestep of first snapshot fwrite_int32(fp,nevery_save); // SKIP = interval between snapshots - fwrite_int32(fp,update->ntimestep); // NSTEP = timestep of last snapshot + fwrite_int32(fp,ntimestep); // NSTEP = timestep of last snapshot fwrite_int32(fp,0); // NAMD writes NSTEP or ISTART fwrite_int32(fp,0); fwrite_int32(fp,0); fwrite_int32(fp,0); fwrite_int32(fp,0); out_float = update->dt; fwrite(&out_float,sizeof(float),1,fp); fwrite_int32(fp,1); fwrite_int32(fp,0); fwrite_int32(fp,0); fwrite_int32(fp,0); fwrite_int32(fp,0); fwrite_int32(fp,0); fwrite_int32(fp,0); fwrite_int32(fp,0); fwrite_int32(fp,0); fwrite_int32(fp,24); // pretend to be Charmm version 24 fwrite_int32(fp,84); fwrite_int32(fp,164); fwrite_int32(fp,2); strncpy(title_string,remarks,80); title_string[79] = '\0'; fwrite(title_string,80,1,fp); cur_time=time(NULL); tmbuf=localtime(&cur_time); memset(title_string,' ',81); strftime(title_string,80,"REMARKS Created %d %B,%Y at %R",tmbuf); fwrite(title_string,80,1,fp); fwrite_int32(fp,164); fwrite_int32(fp,4); fwrite_int32(fp,natoms); // number of atoms in each snapshot fwrite_int32(fp,4); if (flush_flag) fflush(fp); } diff --git a/src/dump_dcd.h b/src/dump_dcd.h index fc5e51668..c71f154ac 100644 --- a/src/dump_dcd.h +++ b/src/dump_dcd.h @@ -1,57 +1,57 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ #ifdef DUMP_CLASS DumpStyle(dcd,DumpDCD) #else #ifndef LMP_DUMP_DCD_H #define LMP_DUMP_DCD_H #include "stdio.h" #include "dump.h" #include "inttypes.h" namespace LAMMPS_NS { class DumpDCD : public Dump { public: DumpDCD(LAMMPS *, int, char**); ~DumpDCD(); private: int natoms,ntotal; int headerflag,nevery_save,nframes; float *coords,*xf,*yf,*zf; int unwrap_flag; // 1 if atom coords are unwrapped, 0 if no void init_style(); void openfile(); - void write_header(int); + void write_header(bigint); int count(); void pack(int *); void write_data(int, double *); int modify_param(int, char **); double memory_usage(); void write_frame(); void write_dcd_header(const char *); }; } #endif #endif diff --git a/src/dump_local.cpp b/src/dump_local.cpp index c93beac71..0230a0ac1 100644 --- a/src/dump_local.cpp +++ b/src/dump_local.cpp @@ -1,473 +1,472 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ #include "mpi.h" #include "string.h" #include "stdlib.h" #include "dump_local.h" #include "atom.h" #include "modify.h" #include "fix.h" #include "compute.h" #include "domain.h" #include "update.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; enum{INT,DOUBLE}; #define INVOKED_LOCAL 16 /* ---------------------------------------------------------------------- */ DumpLocal::DumpLocal(LAMMPS *lmp, int narg, char **arg) : Dump(lmp, narg, arg) { if (narg == 5) error->all("No dump local arguments specified"); clearstep = 1; nevery = atoi(arg[3]); size_one = nfield = narg-5; pack_choice = new FnPtrPack[nfield]; vtype = new int[nfield]; // computes & fixes which the dump accesses field2index = new int[nfield]; argindex = new int[nfield]; ncompute = 0; id_compute = NULL; compute = NULL; nfix = 0; id_fix = NULL; fix = NULL; // process attributes parse_fields(narg,arg); // setup format strings vformat = new char*[size_one]; format_default = new char[3*size_one+1]; format_default[0] = '\0'; for (int i = 0; i < size_one; i++) { if (vtype[i] == INT) format_default = strcat(format_default,"%d "); else format_default = strcat(format_default,"%g "); vformat[i] = NULL; } // setup column string int n = 0; for (int iarg = 5; iarg < narg; iarg++) n += strlen(arg[iarg]) + 2; columns = new char[n]; columns[0] = '\0'; for (int iarg = 5; iarg < narg; iarg++) { strcat(columns,arg[iarg]); strcat(columns," "); } // setup default label string char *str = "ENTRIES"; n = strlen(str) + 1; label = new char[n]; strcpy(label,str); } /* ---------------------------------------------------------------------- */ DumpLocal::~DumpLocal() { delete [] pack_choice; delete [] vtype; delete [] field2index; delete [] argindex; for (int i = 0; i < ncompute; i++) delete [] id_compute[i]; memory->sfree(id_compute); delete [] compute; for (int i = 0; i < nfix; i++) delete [] id_fix[i]; memory->sfree(id_fix); delete [] fix; for (int i = 0; i < size_one; i++) delete [] vformat[i]; delete [] vformat; delete [] columns; delete [] label; } /* ---------------------------------------------------------------------- */ void DumpLocal::init_style() { if (sort_flag && sortcol == 0) error->all("Dump local cannot sort by atom ID"); delete [] format; char *str; if (format_user) str = format_user; else str = format_default; int n = strlen(str) + 1; format = new char[n]; strcpy(format,str); // tokenize the format string and add space at end of each format element char *ptr; for (int i = 0; i < size_one; i++) { if (i == 0) ptr = strtok(format," \0"); else ptr = strtok(NULL," \0"); delete [] vformat[i]; vformat[i] = new char[strlen(ptr) + 2]; strcpy(vformat[i],ptr); vformat[i] = strcat(vformat[i]," "); } // find current ptr for each compute,fix,variable // check that fix frequency is acceptable int icompute; for (int i = 0; i < ncompute; i++) { icompute = modify->find_compute(id_compute[i]); if (icompute < 0) error->all("Could not find dump local compute ID"); compute[i] = modify->compute[icompute]; } int ifix; for (int i = 0; i < nfix; i++) { ifix = modify->find_fix(id_fix[i]); if (ifix < 0) error->all("Could not find dump local fix ID"); fix[i] = modify->fix[ifix]; if (nevery % modify->fix[ifix]->local_freq) error->all("Dump local and fix not computed at compatible times"); } // open single file, one time only if (multifile == 0) openfile(); } /* ---------------------------------------------------------------------- */ int DumpLocal::modify_param(int narg, char **arg) { if (strcmp(arg[0],"label") == 0) { if (narg < 2) error->all("Illegal dump_modify command"); delete [] label; int n = strlen(arg[1]) + 1; label = new char[n]; strcpy(label,arg[1]); return 2; } return 0; } /* ---------------------------------------------------------------------- */ -void DumpLocal::write_header(int ndump) +void DumpLocal::write_header(bigint ndump) { if (me == 0) { fprintf(fp,"ITEM: TIMESTEP\n"); - fprintf(fp,"%d\n",update->ntimestep); + fprintf(fp,BIGINT_FORMAT_NL,update->ntimestep); fprintf(fp,"ITEM: NUMBER OF %s\n",label); - fprintf(fp,"%d\n",ndump); + fprintf(fp,BIGINT_FORMAT_NL,ndump); fprintf(fp,"ITEM: %s %s\n",label,columns); } } /* ---------------------------------------------------------------------- */ int DumpLocal::count() { int i; // invoke Computes for local quantities if (ncompute) { - int ntimestep = update->ntimestep; for (i = 0; i < ncompute; i++) { if (!(compute[i]->invoked_flag & INVOKED_LOCAL)) { compute[i]->compute_local(); compute[i]->invoked_flag |= INVOKED_LOCAL; } } } // nmine = # of local values I contribute // must be consistent for all input fields nmine = -1; int icompute; for (int i = 0; i < ncompute; i++) { if (nmine < 0) nmine = compute[i]->size_local_rows; else if (nmine != compute[i]->size_local_rows) error->one("Dump local count is not consistent across input fields"); } int ifix; for (int i = 0; i < nfix; i++) { if (nmine < 0) nmine = fix[i]->size_local_rows; else if (nmine != fix[i]->size_local_rows) error->one("Dump local count is not consistent across input fields"); } return nmine; } /* ---------------------------------------------------------------------- */ void DumpLocal::pack(int *dummy) { for (int n = 0; n < size_one; n++) (this->*pack_choice[n])(n); } /* ---------------------------------------------------------------------- */ void DumpLocal::write_data(int n, double *mybuf) { int i,j; int m = 0; for (i = 0; i < n; i++) { for (j = 0; j < size_one; j++) { if (vtype[j] == INT) fprintf(fp,vformat[j],static_cast<int> (mybuf[m])); else fprintf(fp,vformat[j],mybuf[m]); m++; } fprintf(fp,"\n"); } } /* ---------------------------------------------------------------------- */ void DumpLocal::parse_fields(int narg, char **arg) { int computefixflag = 0; // customize by adding to if statement int i; for (int iarg = 5; iarg < narg; iarg++) { i = iarg-5; if (strcmp(arg[iarg],"index") == 0) { pack_choice[i] = &DumpLocal::pack_index; vtype[i] = INT; // compute value = c_ID // if no trailing [], then arg is set to 0, else arg is int between [] } else if (strncmp(arg[iarg],"c_",2) == 0) { computefixflag = 1; pack_choice[i] = &DumpLocal::pack_compute; vtype[i] = DOUBLE; int n = strlen(arg[iarg]); char *suffix = new char[n]; strcpy(suffix,&arg[iarg][2]); char *ptr = strchr(suffix,'['); if (ptr) { if (suffix[strlen(suffix)-1] != ']') error->all("Invalid attribute in dump local command"); argindex[i] = atoi(ptr+1); *ptr = '\0'; } else argindex[i] = 0; n = modify->find_compute(suffix); if (n < 0) error->all("Could not find dump local compute ID"); if (modify->compute[n]->local_flag == 0) error->all("Dump local compute does not compute local info"); if (argindex[i] == 0 && modify->compute[n]->size_local_cols > 0) error->all("Dump local compute does not calculate local vector"); if (argindex[i] > 0 && modify->compute[n]->size_local_cols == 0) error->all("Dump local compute does not calculate local array"); if (argindex[i] > 0 && argindex[i] > modify->compute[n]->size_local_cols) error->all("Dump local compute vector is accessed out-of-range"); field2index[i] = add_compute(suffix); delete [] suffix; // fix value = f_ID // if no trailing [], then arg is set to 0, else arg is between [] } else if (strncmp(arg[iarg],"f_",2) == 0) { computefixflag = 1; pack_choice[i] = &DumpLocal::pack_fix; vtype[i] = DOUBLE; int n = strlen(arg[iarg]); char *suffix = new char[n]; strcpy(suffix,&arg[iarg][2]); char *ptr = strchr(suffix,'['); if (ptr) { if (suffix[strlen(suffix)-1] != ']') error->all("Invalid attribute in dump local command"); argindex[i] = atoi(ptr+1); *ptr = '\0'; } else argindex[i] = 0; n = modify->find_fix(suffix); if (n < 0) error->all("Could not find dump local fix ID"); if (modify->fix[n]->local_flag == 0) error->all("Dump local fix does not compute local info"); if (argindex[i] == 0 && modify->fix[n]->size_local_cols > 0) error->all("Dump local fix does not compute local vector"); if (argindex[i] > 0 && modify->fix[n]->size_local_cols == 0) error->all("Dump local fix does not compute local array"); if (argindex[i] > 0 && argindex[i] > modify->fix[n]->size_local_cols) error->all("Dump local fix vector is accessed out-of-range"); field2index[i] = add_fix(suffix); delete [] suffix; } else error->all("Invalid attribute in dump local command"); } if (computefixflag == 0) error->all("Dump local attributes contain no compute or fix"); } /* ---------------------------------------------------------------------- add Compute to list of Compute objects used by dump return index of where this Compute is in list if already in list, do not add, just return index, else add to list ------------------------------------------------------------------------- */ int DumpLocal::add_compute(char *id) { int icompute; for (icompute = 0; icompute < ncompute; icompute++) if (strcmp(id,id_compute[icompute]) == 0) break; if (icompute < ncompute) return icompute; id_compute = (char **) memory->srealloc(id_compute,(ncompute+1)*sizeof(char *),"dump:id_compute"); delete [] compute; compute = new Compute*[ncompute+1]; int n = strlen(id) + 1; id_compute[ncompute] = new char[n]; strcpy(id_compute[ncompute],id); ncompute++; return ncompute-1; } /* ---------------------------------------------------------------------- add Fix to list of Fix objects used by dump return index of where this Fix is in list if already in list, do not add, just return index, else add to list ------------------------------------------------------------------------- */ int DumpLocal::add_fix(char *id) { int ifix; for (ifix = 0; ifix < nfix; ifix++) if (strcmp(id,id_fix[ifix]) == 0) break; if (ifix < nfix) return ifix; id_fix = (char **) memory->srealloc(id_fix,(nfix+1)*sizeof(char *),"dump:id_fix"); delete [] fix; fix = new Fix*[nfix+1]; int n = strlen(id) + 1; id_fix[nfix] = new char[n]; strcpy(id_fix[nfix],id); nfix++; return nfix-1; } /* ---------------------------------------------------------------------- extraction of Compute, Fix results ------------------------------------------------------------------------- */ void DumpLocal::pack_compute(int n) { double *vector = compute[field2index[n]]->vector_local; double **array = compute[field2index[n]]->array_local; int ncount = compute[field2index[n]]->size_local_rows; int index = argindex[n]; if (index == 0) { for (int i = 0; i < ncount; i++) { buf[n] = vector[i]; n += size_one; } } else { index--; for (int i = 0; i < ncount; i++) { buf[n] = array[i][index]; n += size_one; } } } /* ---------------------------------------------------------------------- */ void DumpLocal::pack_fix(int n) { double *vector = fix[field2index[n]]->vector_local; double **array = fix[field2index[n]]->array_local; int index = argindex[n]; if (index == 0) { for (int i = 0; i < nmine; i++) { buf[n] = vector[i]; n += size_one; } } else { index--; for (int i = 0; i < nmine; i++) { buf[n] = array[i][index]; n += size_one; } } } /* ---------------------------------------------------------------------- one method for every attribute dump local can output the local value is packed into buf starting at n with stride size_one customize a new attribute by adding a method ------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */ void DumpLocal::pack_index(int n) { int index; MPI_Scan(&nmine,&index,1,MPI_INT,MPI_SUM,world); index -= nmine; for (int i = 0; i < nmine; i++) { buf[n] = ++index; n += size_one; } } diff --git a/src/dump_local.h b/src/dump_local.h index 53173d791..cc2fedf96 100644 --- a/src/dump_local.h +++ b/src/dump_local.h @@ -1,80 +1,80 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ #ifdef DUMP_CLASS DumpStyle(local,DumpLocal) #else #ifndef LMP_DUMP_LOCAL_H #define LMP_DUMP_LOCAL_H #include "dump.h" namespace LAMMPS_NS { class DumpLocal : public Dump { public: DumpLocal(LAMMPS *, int, char **); ~DumpLocal(); private: int nevery; // dump frequency to check Fix against char *label; // string for dump file header int nmine; // # of lines I am dumping int *vtype; // type of each vector (INT, DOUBLE) char **vformat; // format string for each vector element char *columns; // column labels int nfield; // # of keywords listed by user int *field2index; // which compute,fix,variable calcs this field int *argindex; // index into compute,fix scalar_atom,vector_atom // 0 for scalar_atom, 1-N for vector_atom values int ncompute; // # of Compute objects used by dump char **id_compute; // their IDs class Compute **compute; // list of ptrs to the Compute objects int nfix; // # of Fix objects used by dump char **id_fix; // their IDs class Fix **fix; // list of ptrs to the Fix objects void init_style(); int modify_param(int, char **); - void write_header(int); + void write_header(bigint); int count(); void pack(int *); void write_data(int, double *); void parse_fields(int, char **); int add_compute(char *); int add_fix(char *); // customize by adding a method prototype typedef void (DumpLocal::*FnPtrPack)(int); FnPtrPack *pack_choice; // ptrs to pack functions void pack_index(int); void pack_compute(int); void pack_fix(int); }; } #endif #endif diff --git a/src/dump_xyz.cpp b/src/dump_xyz.cpp index 93d6294aa..06c0686e7 100644 --- a/src/dump_xyz.cpp +++ b/src/dump_xyz.cpp @@ -1,118 +1,118 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ #include "string.h" #include "dump_xyz.h" #include "atom.h" #include "group.h" #include "error.h" #include "memory.h" using namespace LAMMPS_NS; /* ---------------------------------------------------------------------- */ DumpXYZ::DumpXYZ(LAMMPS *lmp, int narg, char **arg) : Dump(lmp, narg, arg) { if (narg != 5) error->all("Illegal dump xyz command"); if (binary || multiproc) error->all("Invalid dump xyz filename"); size_one = 5; sort_flag = 1; sortcol = 0; char *str = (char *) "%d %g %g %g"; int n = strlen(str) + 1; format_default = new char[n]; strcpy(format_default,str); } /* ---------------------------------------------------------------------- */ void DumpXYZ::init_style() { delete [] format; char *str; if (format_user) str = format_user; else str = format_default; int n = strlen(str) + 2; format = new char[n]; strcpy(format,str); strcat(format,"\n"); // open single file, one time only if (multifile == 0) openfile(); } /* ---------------------------------------------------------------------- */ -void DumpXYZ::write_header(int n) +void DumpXYZ::write_header(bigint n) { if (me == 0) { - fprintf(fp,"%d\n",n); + fprintf(fp,BIGINT_FORMAT_NL,n); fprintf(fp,"Atoms\n"); } } /* ---------------------------------------------------------------------- */ int DumpXYZ::count() { if (igroup == 0) return atom->nlocal; int *mask = atom->mask; int nlocal = atom->nlocal; int m = 0; for (int i = 0; i < nlocal; i++) if (mask[i] & groupbit) m++; return m; } /* ---------------------------------------------------------------------- */ void DumpXYZ::pack(int *ids) { int m,n; int *tag = atom->tag; int *type = atom->type; int *mask = atom->mask; double **x = atom->x; int nlocal = atom->nlocal; m = n = 0; for (int i = 0; i < nlocal; i++) if (mask[i] & groupbit) { buf[m++] = tag[i]; buf[m++] = type[i]; buf[m++] = x[i][0]; buf[m++] = x[i][1]; buf[m++] = x[i][2]; if (ids) ids[n++] = tag[i]; } } /* ---------------------------------------------------------------------- */ void DumpXYZ::write_data(int n, double *mybuf) { int m = 0; for (int i = 0; i < n; i++) { fprintf(fp,format, static_cast<int> (mybuf[m+1]),mybuf[m+2],mybuf[m+3],mybuf[m+4]); m += size_one; } } diff --git a/src/dump_xyz.h b/src/dump_xyz.h index b15580511..39e6d5d19 100644 --- a/src/dump_xyz.h +++ b/src/dump_xyz.h @@ -1,43 +1,43 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ #ifdef DUMP_CLASS DumpStyle(xyz,DumpXYZ) #else #ifndef LMP_DUMP_XYZ_H #define LMP_DUMP_XYZ_H #include "dump.h" namespace LAMMPS_NS { class DumpXYZ : public Dump { public: DumpXYZ(class LAMMPS *, int, char**); ~DumpXYZ() {} private: void init_style(); - void write_header(int); + void write_header(bigint); int count(); void pack(int *); void write_data(int, double *); }; } #endif #endif diff --git a/src/finish.cpp b/src/finish.cpp index d45cf63b2..92496b5b9 100644 --- a/src/finish.cpp +++ b/src/finish.cpp @@ -1,657 +1,654 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ #include "mpi.h" #include "math.h" #include "string.h" #include "stdio.h" #include "finish.h" #include "timer.h" #include "atom.h" #include "force.h" #include "kspace.h" #include "update.h" #include "min.h" #include "neighbor.h" #include "neigh_list.h" #include "neigh_request.h" #include "output.h" #include "memory.h" using namespace LAMMPS_NS; #define MIN(A,B) ((A) < (B)) ? (A) : (B) #define MAX(A,B) ((A) > (B)) ? (A) : (B) /* ---------------------------------------------------------------------- */ Finish::Finish(LAMMPS *lmp) : Pointers(lmp) {} /* ---------------------------------------------------------------------- */ void Finish::end(int flag) { int i,m,nneigh,nneighfull; int histo[10]; int loopflag,minflag,prdflag,tadflag,timeflag,fftflag,histoflag,neighflag; double time,tmp,ave,max,min; double time_loop,time_other; bigint natoms; int me,nprocs; MPI_Comm_rank(world,&me); MPI_Comm_size(world,&nprocs); // choose flavors of statistical output // flag determines caller // flag = 0 = just loop summary // flag = 1 = dynamics or minimization // flag = 2 = PRD // flag = 3 = TAD loopflag = 1; minflag = prdflag = tadflag = timeflag = fftflag = histoflag = neighflag = 0; if (flag == 1) { if (update->whichflag == 2) minflag = 1; timeflag = histoflag = neighflag = 1; if (strstr(force->kspace_style,"pppm")) fftflag = 1; } if (flag == 2) prdflag = histoflag = neighflag = 1; if (flag == 3) tadflag = histoflag = neighflag = 1; // loop stats if (loopflag) { time_other = timer->array[TIME_LOOP] - (timer->array[TIME_PAIR] + timer->array[TIME_BOND] + timer->array[TIME_KSPACE] + timer->array[TIME_NEIGHBOR] + timer->array[TIME_COMM] + timer->array[TIME_OUTPUT]); time_loop = timer->array[TIME_LOOP]; MPI_Allreduce(&time_loop,&tmp,1,MPI_DOUBLE,MPI_SUM,world); time_loop = tmp/nprocs; // overall loop time // use actual natoms, in case atoms were lost bigint nblocal = atom->nlocal; - MPI_Allreduce(&nblocal,&natoms,1,MPI_UNSIGNED_LONG_LONG,MPI_SUM,world); + MPI_Allreduce(&nblocal,&natoms,1,MPI_LMP_BIGINT,MPI_SUM,world); if (me == 0) { - if (screen) - fprintf(screen, - "Loop time of %g on %d procs for %d steps with %lu atoms\n", - time_loop,nprocs,update->nsteps,natoms); - if (logfile) - fprintf(logfile, - "Loop time of %g on %d procs for %d steps with %lu atoms\n", - time_loop,nprocs,update->nsteps,natoms); + char str[128]; + sprintf(str,"Loop time of %%g on %%d procs for %%d steps with %s atoms\n", + BIGINT_FORMAT); + if (screen) fprintf(screen,str,time_loop,nprocs,update->nsteps,natoms); + if (logfile) fprintf(logfile,str,time_loop,nprocs,update->nsteps,natoms); } if (time_loop == 0.0) time_loop = 1.0; } // minimization stats if (minflag) { if (me == 0) { if (screen) fprintf(screen,"\n"); if (logfile) fprintf(logfile,"\n"); } if (me == 0) { if (screen) { fprintf(screen,"Minimization stats:\n"); fprintf(screen," Stopping criterion = %s\n", update->minimize->stopstr); fprintf(screen," Energy initial, next-to-last, final = \n" " %18.12g %18.12g %18.12g\n", update->minimize->einitial,update->minimize->eprevious, update->minimize->efinal); fprintf(screen," Force two-norm initial, final = %g %g\n", update->minimize->fnorm2_init,update->minimize->fnorm2_final); fprintf(screen," Force max component initial, final = %g %g\n", update->minimize->fnorminf_init, update->minimize->fnorminf_final); fprintf(screen," Final line search alpha, max atom move = %g %g\n", update->minimize->alpha_final, update->minimize->alpha_final* update->minimize->fnorminf_final); fprintf(screen," Iterations, force evaluations = %d %d\n", update->minimize->niter,update->minimize->neval); } if (logfile) { fprintf(logfile,"Minimization stats:\n"); fprintf(logfile," Stopping criterion = %s\n", update->minimize->stopstr); fprintf(logfile," Energy initial, next-to-last, final = \n" " %18.12g %18.12g %18.12g\n", update->minimize->einitial,update->minimize->eprevious, update->minimize->efinal); fprintf(logfile," Force two-norm initial, final = %g %g\n", update->minimize->fnorm2_init,update->minimize->fnorm2_final); fprintf(logfile," Force max component initial, final = %g %g\n", update->minimize->fnorminf_init, update->minimize->fnorminf_final); fprintf(logfile," Final line search alpha, max atom move = %g %g\n", update->minimize->alpha_final, update->minimize->alpha_final* update->minimize->fnorminf_final); fprintf(logfile," Iterations, force evaluations = %d %d\n", update->minimize->niter,update->minimize->neval); } } } // PRD stats using PAIR,BOND,KSPACE for dephase,dynamics,quench if (prdflag) { if (me == 0) { if (screen) fprintf(screen,"\n"); if (logfile) fprintf(logfile,"\n"); } if (screen) fprintf(screen,"PRD stats:\n"); if (logfile) fprintf(logfile,"PRD stats:\n"); time = timer->array[TIME_PAIR]; MPI_Allreduce(&time,&tmp,1,MPI_DOUBLE,MPI_SUM,world); time = tmp/nprocs; if (me == 0) { if (screen) fprintf(screen," Dephase time (%%) = %g (%g)\n", time,time/time_loop*100.0); if (logfile) fprintf(logfile," Dephase time (%%) = %g (%g)\n", time,time/time_loop*100.0); } time = timer->array[TIME_BOND]; MPI_Allreduce(&time,&tmp,1,MPI_DOUBLE,MPI_SUM,world); time = tmp/nprocs; if (me == 0) { if (screen) fprintf(screen," Dynamics time (%%) = %g (%g)\n", time,time/time_loop*100.0); if (logfile) fprintf(logfile," Dynamics time (%%) = %g (%g)\n", time,time/time_loop*100.0); } time = timer->array[TIME_KSPACE]; MPI_Allreduce(&time,&tmp,1,MPI_DOUBLE,MPI_SUM,world); time = tmp/nprocs; if (me == 0) { if (screen) fprintf(screen," Quench time (%%) = %g (%g)\n", time,time/time_loop*100.0); if (logfile) fprintf(logfile," Quench time (%%) = %g (%g)\n", time,time/time_loop*100.0); } time = time_other; MPI_Allreduce(&time,&tmp,1,MPI_DOUBLE,MPI_SUM,world); time = tmp/nprocs; if (me == 0) { if (screen) fprintf(screen," Other time (%%) = %g (%g)\n", time,time/time_loop*100.0); if (logfile) fprintf(logfile," Other time (%%) = %g (%g)\n", time,time/time_loop*100.0); } } // TAD stats using PAIR,BOND,KSPACE for neb,dynamics,quench if (tadflag) { if (me == 0) { if (screen) fprintf(screen,"\n"); if (logfile) fprintf(logfile,"\n"); } if (screen) fprintf(screen,"TAD stats:\n"); if (logfile) fprintf(logfile,"TAD stats:\n"); time = timer->array[TIME_PAIR]; MPI_Allreduce(&time,&tmp,1,MPI_DOUBLE,MPI_SUM,world); time = tmp/nprocs; if (me == 0) { if (screen) fprintf(screen," NEB time (%%) = %g (%g)\n", time,time/time_loop*100.0); if (logfile) fprintf(logfile," NEB time (%%) = %g (%g)\n", time,time/time_loop*100.0); } time = timer->array[TIME_BOND]; MPI_Allreduce(&time,&tmp,1,MPI_DOUBLE,MPI_SUM,world); time = tmp/nprocs; if (me == 0) { if (screen) fprintf(screen," Dynamics time (%%) = %g (%g)\n", time,time/time_loop*100.0); if (logfile) fprintf(logfile," Dynamics time (%%) = %g (%g)\n", time,time/time_loop*100.0); } time = timer->array[TIME_KSPACE]; MPI_Allreduce(&time,&tmp,1,MPI_DOUBLE,MPI_SUM,world); time = tmp/nprocs; if (me == 0) { if (screen) fprintf(screen," Quench time (%%) = %g (%g)\n", time,time/time_loop*100.0); if (logfile) fprintf(logfile," Quench time (%%) = %g (%g)\n", time,time/time_loop*100.0); } time = timer->array[TIME_COMM]; MPI_Allreduce(&time,&tmp,1,MPI_DOUBLE,MPI_SUM,world); time = tmp/nprocs; if (me == 0) { if (screen) fprintf(screen," Comm time (%%) = %g (%g)\n", time,time/time_loop*100.0); if (logfile) fprintf(logfile," Comm time (%%) = %g (%g)\n", time,time/time_loop*100.0); } time = timer->array[TIME_OUTPUT]; MPI_Allreduce(&time,&tmp,1,MPI_DOUBLE,MPI_SUM,world); time = tmp/nprocs; if (me == 0) { if (screen) fprintf(screen," Output time (%%) = %g (%g)\n", time,time/time_loop*100.0); if (logfile) fprintf(logfile," Output time (%%) = %g (%g)\n", time,time/time_loop*100.0); } time = time_other; MPI_Allreduce(&time,&tmp,1,MPI_DOUBLE,MPI_SUM,world); time = tmp/nprocs; if (me == 0) { if (screen) fprintf(screen," Other time (%%) = %g (%g)\n", time,time/time_loop*100.0); if (logfile) fprintf(logfile," Other time (%%) = %g (%g)\n", time,time/time_loop*100.0); } } // timing breakdowns if (timeflag) { if (me == 0) { if (screen) fprintf(screen,"\n"); if (logfile) fprintf(logfile,"\n"); } time = timer->array[TIME_PAIR]; MPI_Allreduce(&time,&tmp,1,MPI_DOUBLE,MPI_SUM,world); time = tmp/nprocs; if (me == 0) { if (screen) fprintf(screen,"Pair time (%%) = %g (%g)\n", time,time/time_loop*100.0); if (logfile) fprintf(logfile,"Pair time (%%) = %g (%g)\n", time,time/time_loop*100.0); } if (atom->molecular) { time = timer->array[TIME_BOND]; MPI_Allreduce(&time,&tmp,1,MPI_DOUBLE,MPI_SUM,world); time = tmp/nprocs; if (me == 0) { if (screen) fprintf(screen,"Bond time (%%) = %g (%g)\n", time,time/time_loop*100.0); if (logfile) fprintf(logfile,"Bond time (%%) = %g (%g)\n", time,time/time_loop*100.0); } } if (force->kspace) { time = timer->array[TIME_KSPACE]; MPI_Allreduce(&time,&tmp,1,MPI_DOUBLE,MPI_SUM,world); time = tmp/nprocs; if (me == 0) { if (screen) fprintf(screen,"Kspce time (%%) = %g (%g)\n", time,time/time_loop*100.0); if (logfile) fprintf(logfile,"Kspce time (%%) = %g (%g)\n", time,time/time_loop*100.0); } } time = timer->array[TIME_NEIGHBOR]; MPI_Allreduce(&time,&tmp,1,MPI_DOUBLE,MPI_SUM,world); time = tmp/nprocs; if (me == 0) { if (screen) fprintf(screen,"Neigh time (%%) = %g (%g)\n", time,time/time_loop*100.0); if (logfile) fprintf(logfile,"Neigh time (%%) = %g (%g)\n", time,time/time_loop*100.0); } time = timer->array[TIME_COMM]; MPI_Allreduce(&time,&tmp,1,MPI_DOUBLE,MPI_SUM,world); time = tmp/nprocs; if (me == 0) { if (screen) fprintf(screen,"Comm time (%%) = %g (%g)\n", time,time/time_loop*100.0); if (logfile) fprintf(logfile,"Comm time (%%) = %g (%g)\n", time,time/time_loop*100.0); } time = timer->array[TIME_OUTPUT]; MPI_Allreduce(&time,&tmp,1,MPI_DOUBLE,MPI_SUM,world); time = tmp/nprocs; if (me == 0) { if (screen) fprintf(screen,"Outpt time (%%) = %g (%g)\n", time,time/time_loop*100.0); if (logfile) fprintf(logfile,"Outpt time (%%) = %g (%g)\n", time,time/time_loop*100.0); } time = time_other; MPI_Allreduce(&time,&tmp,1,MPI_DOUBLE,MPI_SUM,world); time = tmp/nprocs; if (me == 0) { if (screen) fprintf(screen,"Other time (%%) = %g (%g)\n", time,time/time_loop*100.0); if (logfile) fprintf(logfile,"Other time (%%) = %g (%g)\n", time,time/time_loop*100.0); } } // FFT timing statistics // time3d,time1d = total time during run for 3d and 1d FFTs if (fftflag) { if (me == 0) { if (screen) fprintf(screen,"\n"); if (logfile) fprintf(logfile,"\n"); } int nsteps = update->nsteps; int nsample = 5; double time3d,time1d; force->kspace->timing(nsample,time3d,time1d); time3d = nsteps * time3d / nsample; MPI_Allreduce(&time3d,&tmp,1,MPI_DOUBLE,MPI_SUM,world); time3d = tmp/nprocs; time1d = nsteps * time1d / nsample; MPI_Allreduce(&time1d,&tmp,1,MPI_DOUBLE,MPI_SUM,world); time1d = tmp/nprocs; double time_kspace = timer->array[TIME_KSPACE]; MPI_Allreduce(&time_kspace,&tmp,1,MPI_DOUBLE,MPI_SUM,world); time_kspace = tmp/nprocs; double ntotal = 1.0 * force->kspace->nx_pppm * force->kspace->ny_pppm * force->kspace->nz_pppm; double nflops = 5.0 * ntotal * log(ntotal); double fraction,flop3,flop1; if (nsteps) { fraction = time3d/time_kspace*100.0; flop3 = nflops/1.0e9/(time3d/4.0/nsteps); flop1 = nflops/1.0e9/(time1d/4.0/nsteps); } else fraction = flop3 = flop1 = 0.0; if (me == 0) { if (screen) { fprintf(screen,"FFT time (%% of Kspce) = %g (%g)\n",time3d,fraction); fprintf(screen,"FFT Gflps 3d (1d only) = %g %g\n",flop3,flop1); } if (logfile) { fprintf(logfile,"FFT time (%% of Kspce) = %g (%g)\n",time3d,fraction); fprintf(logfile,"FFT Gflps 3d (1d only) = %g %g\n",flop3,flop1); } } } if (histoflag) { if (me == 0) { if (screen) fprintf(screen,"\n"); if (logfile) fprintf(logfile,"\n"); } tmp = atom->nlocal; stats(1,&tmp,&ave,&max,&min,10,histo); if (me == 0) { if (screen) { fprintf(screen,"Nlocal: %g ave %g max %g min\n",ave,max,min); fprintf(screen,"Histogram:"); for (i = 0; i < 10; i++) fprintf(screen," %d",histo[i]); fprintf(screen,"\n"); } if (logfile) { fprintf(logfile,"Nlocal: %g ave %g max %g min\n",ave,max,min); fprintf(logfile,"Histogram:"); for (i = 0; i < 10; i++) fprintf(logfile," %d",histo[i]); fprintf(logfile,"\n"); } } tmp = atom->nghost; stats(1,&tmp,&ave,&max,&min,10,histo); if (me == 0) { if (screen) { fprintf(screen,"Nghost: %g ave %g max %g min\n",ave,max,min); fprintf(screen,"Histogram:"); for (i = 0; i < 10; i++) fprintf(screen," %d",histo[i]); fprintf(screen,"\n"); } if (logfile) { fprintf(logfile,"Nghost: %g ave %g max %g min\n",ave,max,min); fprintf(logfile,"Histogram:"); for (i = 0; i < 10; i++) fprintf(logfile," %d",histo[i]); fprintf(logfile,"\n"); } } // find a non-skip neighbor list containing half the pairwise interactions // count neighbors in that list for stats purposes for (m = 0; m < neighbor->old_nrequest; m++) if ((neighbor->old_requests[m]->half || neighbor->old_requests[m]->gran || neighbor->old_requests[m]->respaouter || neighbor->old_requests[m]->half_from_full) && neighbor->old_requests[m]->skip == 0 && neighbor->lists[m]->numneigh) break; nneigh = 0; if (m < neighbor->old_nrequest) { int inum = neighbor->lists[m]->inum; int *ilist = neighbor->lists[m]->ilist; int *numneigh = neighbor->lists[m]->numneigh; for (i = 0; i < inum; i++) nneigh += numneigh[ilist[i]]; } tmp = nneigh; stats(1,&tmp,&ave,&max,&min,10,histo); if (me == 0) { if (screen) { fprintf(screen,"Neighs: %g ave %g max %g min\n",ave,max,min); fprintf(screen,"Histogram:"); for (i = 0; i < 10; i++) fprintf(screen," %d",histo[i]); fprintf(screen,"\n"); } if (logfile) { fprintf(logfile,"Neighs: %g ave %g max %g min\n",ave,max,min); fprintf(logfile,"Histogram:"); for (i = 0; i < 10; i++) fprintf(logfile," %d",histo[i]); fprintf(logfile,"\n"); } } // find a non-skip neighbor list containing full pairwise interactions // count neighbors in that list for stats purposes for (m = 0; m < neighbor->old_nrequest; m++) if (neighbor->old_requests[m]->full && neighbor->old_requests[m]->skip == 0) break; nneighfull = 0; if (m < neighbor->old_nrequest) { if (neighbor->lists[m]->numneigh > 0) { int inum = neighbor->lists[m]->inum; int *ilist = neighbor->lists[m]->ilist; int *numneigh = neighbor->lists[m]->numneigh; for (i = 0; i < inum; i++) nneighfull += numneigh[ilist[i]]; } tmp = nneighfull; stats(1,&tmp,&ave,&max,&min,10,histo); if (me == 0) { if (screen) { fprintf(screen,"FullNghs: %g ave %g max %g min\n",ave,max,min); fprintf(screen,"Histogram:"); for (i = 0; i < 10; i++) fprintf(screen," %d",histo[i]); fprintf(screen,"\n"); } if (logfile) { fprintf(logfile,"FullNghs: %g ave %g max %g min\n",ave,max,min); fprintf(logfile,"Histogram:"); for (i = 0; i < 10; i++) fprintf(logfile," %d",histo[i]); fprintf(logfile,"\n"); } } } } if (neighflag) { if (me == 0) { if (screen) fprintf(screen,"\n"); if (logfile) fprintf(logfile,"\n"); } tmp = MAX(nneigh,nneighfull); double nall; MPI_Allreduce(&tmp,&nall,1,MPI_DOUBLE,MPI_SUM,world); int nspec; double nspec_all; if (atom->molecular) { nspec = 0; for (i = 0; i < atom->nlocal; i++) nspec += atom->nspecial[i][2]; tmp = nspec; MPI_Allreduce(&tmp,&nspec_all,1,MPI_DOUBLE,MPI_SUM,world); } if (me == 0) { if (screen) { if (nall < 2.0e9) fprintf(screen, "Total # of neighbors = %d\n",static_cast<int> (nall)); else fprintf(screen,"Total # of neighbors = %g\n",nall); if (natoms > 0) fprintf(screen,"Ave neighs/atom = %g\n",nall/natoms); if (atom->molecular && natoms > 0) fprintf(screen,"Ave special neighs/atom = %g\n",nspec_all/natoms); fprintf(screen,"Neighbor list builds = %d\n",neighbor->ncalls); fprintf(screen,"Dangerous builds = %d\n",neighbor->ndanger); } if (logfile) { if (nall < 2.0e9) fprintf(logfile, "Total # of neighbors = %d\n",static_cast<int> (nall)); else fprintf(logfile,"Total # of neighbors = %g\n",nall); if (natoms > 0) fprintf(logfile,"Ave neighs/atom = %g\n",nall/natoms); if (atom->molecular && natoms > 0) fprintf(logfile,"Ave special neighs/atom = %g\n",nspec_all/natoms); fprintf(logfile,"Neighbor list builds = %d\n",neighbor->ncalls); fprintf(logfile,"Dangerous builds = %d\n",neighbor->ndanger); } } } if (logfile) fflush(logfile); } /* ---------------------------------------------------------------------- */ void Finish::stats(int n, double *data, double *pave, double *pmax, double *pmin, int nhisto, int *histo) { int i,m; int *histotmp; double min = 1.0e20; double max = -1.0e20; double ave = 0.0; for (i = 0; i < n; i++) { ave += data[i]; if (data[i] < min) min = data[i]; if (data[i] > max) max = data[i]; } int ntotal; MPI_Allreduce(&n,&ntotal,1,MPI_INT,MPI_SUM,world); double tmp; MPI_Allreduce(&ave,&tmp,1,MPI_DOUBLE,MPI_SUM,world); ave = tmp/ntotal; MPI_Allreduce(&min,&tmp,1,MPI_DOUBLE,MPI_MIN,world); min = tmp; MPI_Allreduce(&max,&tmp,1,MPI_DOUBLE,MPI_MAX,world); max = tmp; for (i = 0; i < nhisto; i++) histo[i] = 0; double del = max - min; for (i = 0; i < n; i++) { if (del == 0.0) m = 0; else m = static_cast<int> ((data[i]-min)/del * nhisto); if (m > nhisto-1) m = nhisto-1; histo[m]++; } histotmp = (int *) memory->smalloc(nhisto*sizeof(int),"finish:histotmp"); MPI_Allreduce(histo,histotmp,nhisto,MPI_INT,MPI_SUM,world); for (i = 0; i < nhisto; i++) histo[i] = histotmp[i]; memory->sfree(histotmp); *pave = ave; *pmax = max; *pmin = min; } diff --git a/src/fix.h b/src/fix.h index b35653d64..c44cccfa2 100644 --- a/src/fix.h +++ b/src/fix.h @@ -1,170 +1,171 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ #ifndef LMP_FIX_H #define LMP_FIX_H #include "pointers.h" +#include "lmptype.h" namespace LAMMPS_NS { class Fix : protected Pointers { public: char *id,*style; int igroup,groupbit; int restart_global; // 1 if Fix saves global state, 0 if not int restart_peratom; // 1 if Fix saves peratom state, 0 if not int force_reneighbor; // 1 if Fix forces reneighboring, 0 if not int box_change; // 1 if Fix changes box, 0 if not int box_change_size; // 1 if Fix changes box size, 0 if not int box_change_shape; // 1 if Fix changes box shape, 0 if not - int next_reneighbor; // next timestep to force a reneighboring + bigint next_reneighbor; // next timestep to force a reneighboring int thermo_energy; // 1 if fix_modify enabled ThEng, 0 if not int nevery; // how often to call an end_of_step fix int rigid_flag; // 1 if Fix integrates rigid bodies, 0 if not int virial_flag; // 1 if Fix contributes to virial, 0 if not int no_change_box; // 1 if cannot swap ortho <-> triclinic int time_integrate; // 1 if fix performs time integration, 0 if no int time_depend; // 1 if fix is timestep dependent, 0 if not int create_attribute; // 1 if fix stores attributes that need // setting when a new atom is created int restart_pbc; // 1 if fix moves atoms (except integrate) // so write_restart must remap to PBC int scalar_flag; // 0/1 if compute_scalar() function exists int vector_flag; // 0/1 if compute_vector() function exists int array_flag; // 0/1 if compute_array() function exists int size_vector; // length of global vector int size_array_rows; // rows in global array int size_array_cols; // columns in global array int global_freq; // frequency s/v data is available at int peratom_flag; // 0/1 if per-atom data is stored int size_peratom_cols; // 0 = vector, N = columns in peratom array int peratom_freq; // frequency per-atom data is available at int local_flag; // 0/1 if local data is stored int size_local_rows; // rows in local vector or array int size_local_cols; // 0 = vector, N = columns in local array int local_freq; // frequency local data is available at int extscalar; // 0/1 if global scalar is intensive/extensive int extvector; // 0/1/-1 if global vector is all int/ext/extlist int *extlist; // list of 0/1 int/ext for each vec component int extarray; // 0/1 if global array is intensive/extensive double *vector_atom; // computed per-atom vector double **array_atom; // computed per-atom array double *vector_local; // computed local vector double **array_local; // computed local array int comm_forward; // size of forward communication (0 if none) int comm_reverse; // size of reverse communication (0 if none) double virial[6]; // accumlated virial double **vatom; // accumulated per-atom virial int INITIAL_INTEGRATE,POST_INTEGRATE; // mask settings int PRE_EXCHANGE,PRE_NEIGHBOR; int PRE_FORCE,POST_FORCE,FINAL_INTEGRATE,END_OF_STEP,THERMO_ENERGY; int INITIAL_INTEGRATE_RESPA,POST_INTEGRATE_RESPA; int PRE_FORCE_RESPA,POST_FORCE_RESPA,FINAL_INTEGRATE_RESPA; int MIN_PRE_EXCHANGE,MIN_PRE_FORCE,MIN_POST_FORCE,MIN_ENERGY; int POST_RUN; Fix(class LAMMPS *, int, char **); virtual ~Fix(); void modify_params(int, char **); virtual int setmask() = 0; virtual void init() {} virtual void init_list(int, class NeighList *) {} virtual void setup(int) {} virtual void setup_pre_force(int) {} virtual void min_setup(int) {} virtual void initial_integrate(int) {} virtual void post_integrate() {} virtual void pre_exchange() {} virtual void pre_neighbor() {} virtual void pre_force(int) {} virtual void post_force(int) {} virtual void final_integrate() {} virtual void end_of_step() {} virtual void post_run() {} virtual void write_restart(FILE *) {} virtual void restart(char *) {} virtual void grow_arrays(int) {} virtual void copy_arrays(int, int) {} virtual void set_arrays(int) {} virtual int pack_exchange(int, double *) {return 0;} virtual int unpack_exchange(int, double *) {return 0;} virtual int pack_restart(int, double *) {return 0;} virtual void unpack_restart(int, int) {} virtual int size_restart(int) {return 0;} virtual int maxsize_restart() {return 0;} virtual void setup_pre_force_respa(int, int) {} virtual void initial_integrate_respa(int, int, int) {} virtual void post_integrate_respa(int, int) {} virtual void pre_force_respa(int, int, int) {} virtual void post_force_respa(int, int, int) {} virtual void final_integrate_respa(int, int) {} virtual void min_setup_pre_force(int) {} virtual void min_pre_exchange() {} virtual void min_pre_force(int) {} virtual void min_post_force(int) {} virtual double min_energy(double *) {return 0.0;} virtual void min_store() {} virtual void min_clearstore() {} virtual void min_pushstore() {} virtual void min_popstore() {} virtual int min_reset_ref() {return 0;} virtual void min_step(double, double *) {} virtual double max_alpha(double *) {return 0.0;} virtual int min_dof() {return 0;} virtual int pack_comm(int, int *, double *, int, int *) {return 0;} virtual void unpack_comm(int, int, double *) {} virtual int pack_reverse_comm(int, int, double *) {return 0;} virtual void unpack_reverse_comm(int, int *, double *) {} virtual double compute_scalar() {return 0.0;} virtual double compute_vector(int) {return 0.0;} virtual double compute_array(int,int) {return 0.0;} virtual int dof(int) {return 0;} virtual void deform(int) {} virtual void reset_target(double) {} virtual void reset_dt() {} virtual int modify_param(int, char **) {return 0;} virtual double memory_usage() {return 0.0;} protected: int evflag; int vflag_global,vflag_atom; int maxvatom; void v_setup(int); void v_tally(int, int *, double, double *); }; } #endif diff --git a/src/fix_ave_atom.cpp b/src/fix_ave_atom.cpp index eb8cf19b2..ef7de11d3 100644 --- a/src/fix_ave_atom.cpp +++ b/src/fix_ave_atom.cpp @@ -1,447 +1,448 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ #include "stdlib.h" #include "string.h" #include "fix_ave_atom.h" +#include "lmptype.h" #include "atom.h" #include "domain.h" #include "update.h" #include "modify.h" #include "compute.h" #include "input.h" #include "variable.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; enum{X,V,F,COMPUTE,FIX,VARIABLE}; #define INVOKED_PERATOM 8 /* ---------------------------------------------------------------------- */ FixAveAtom::FixAveAtom(LAMMPS *lmp, int narg, char **arg) : Fix(lmp, narg, arg) { if (narg < 7) error->all("Illegal fix ave/atom command"); time_depend = 1; nevery = atoi(arg[3]); nrepeat = atoi(arg[4]); peratom_freq = atoi(arg[5]); // parse remaining values which = new int[narg-6]; argindex = new int[narg-6]; ids = new char*[narg-6]; value2index = new int[narg-6]; nvalues = 0; int iarg = 6; while (iarg < narg) { ids[nvalues] = NULL; if (strcmp(arg[iarg],"x") == 0) { which[nvalues] = X; argindex[nvalues++] = 0; } else if (strcmp(arg[iarg],"y") == 0) { which[nvalues] = X; argindex[nvalues++] = 1; } else if (strcmp(arg[iarg],"z") == 0) { which[nvalues] = X; argindex[nvalues++] = 2; } else if (strcmp(arg[iarg],"vx") == 0) { which[nvalues] = V; argindex[nvalues++] = 0; } else if (strcmp(arg[iarg],"vy") == 0) { which[nvalues] = V; argindex[nvalues++] = 1; } else if (strcmp(arg[iarg],"vz") == 0) { which[nvalues] = V; argindex[nvalues++] = 2; } else if (strcmp(arg[iarg],"fx") == 0) { which[nvalues] = F; argindex[nvalues++] = 0; } else if (strcmp(arg[iarg],"fy") == 0) { which[nvalues] = F; argindex[nvalues++] = 1; } else if (strcmp(arg[iarg],"fz") == 0) { which[nvalues] = F; argindex[nvalues++] = 2; } else if (strncmp(arg[iarg],"c_",2) == 0 || strncmp(arg[iarg],"f_",2) == 0 || strncmp(arg[iarg],"v_",2) == 0) { if (arg[iarg][0] == 'c') which[nvalues] = COMPUTE; else if (arg[iarg][0] == 'f') which[nvalues] = FIX; else if (arg[iarg][0] == 'v') which[nvalues] = VARIABLE; int n = strlen(arg[iarg]); char *suffix = new char[n]; strcpy(suffix,&arg[iarg][2]); char *ptr = strchr(suffix,'['); if (ptr) { if (suffix[strlen(suffix)-1] != ']') error->all("Illegal fix ave/atom command"); argindex[nvalues] = atoi(ptr+1); *ptr = '\0'; } else argindex[nvalues] = 0; n = strlen(suffix) + 1; ids[nvalues] = new char[n]; strcpy(ids[nvalues],suffix); nvalues++; delete [] suffix; } else error->all("Illegal fix ave/atom command"); iarg++; } // setup and error check // for fix inputs, check that fix frequency is acceptable if (nevery <= 0 || nrepeat <= 0 || peratom_freq <= 0) error->all("Illegal fix ave/atom command"); if (peratom_freq % nevery || (nrepeat-1)*nevery >= peratom_freq) error->all("Illegal fix ave/atom command"); for (int i = 0; i < nvalues; i++) { if (which[i] == COMPUTE) { int icompute = modify->find_compute(ids[i]); if (icompute < 0) error->all("Compute ID for fix ave/atom does not exist"); if (modify->compute[icompute]->peratom_flag == 0) error->all("Fix ave/atom compute does not calculate per-atom values"); if (argindex[i] == 0 && modify->compute[icompute]->size_peratom_cols != 0) error->all("Fix ave/atom compute does not " "calculate a per-atom vector"); if (argindex[i] && modify->compute[icompute]->size_peratom_cols == 0) error->all("Fix ave/atom compute does not " "calculate a per-atom array"); if (argindex[i] && argindex[i] > modify->compute[icompute]->size_peratom_cols) error->all("Fix ave/atom compute array is accessed out-of-range"); } else if (which[i] == FIX) { int ifix = modify->find_fix(ids[i]); if (ifix < 0) error->all("Fix ID for fix ave/atom does not exist"); if (modify->fix[ifix]->peratom_flag == 0) error->all("Fix ave/atom fix does not calculate per-atom values"); if (argindex[i] == 0 && modify->fix[ifix]->size_peratom_cols != 0) error->all("Fix ave/atom fix does not calculate a per-atom vector"); if (argindex[i] && modify->fix[ifix]->size_peratom_cols == 0) error->all("Fix ave/atom fix does not calculate a per-atom array"); if (argindex[i] && argindex[i] > modify->fix[ifix]->size_peratom_cols) error->all("Fix ave/atom fix array is accessed out-of-range"); if (nevery % modify->fix[ifix]->peratom_freq) error->all("Fix for fix ave/atom not computed at compatible time"); } else if (which[i] == VARIABLE) { int ivariable = input->variable->find(ids[i]); if (ivariable < 0) error->all("Variable name for fix ave/atom does not exist"); if (input->variable->atomstyle(ivariable) == 0) error->all("Fix ave/atom variable is not atom-style variable"); } } // this fix produces either a per-atom vector or array peratom_flag = 1; if (nvalues == 1) size_peratom_cols = 0; else size_peratom_cols = nvalues; // perform initial allocation of atom-based array // register with Atom class array = NULL; grow_arrays(atom->nmax); atom->add_callback(0); // zero the array since dump may access it on timestep 0 // zero the array since a variable may access it before first run int nlocal = atom->nlocal; for (int i = 0; i < nlocal; i++) for (int m = 0; m < nvalues; m++) array[i][m] = 0.0; // nvalid = next step on which end_of_step does something // add nvalid to all computes that store invocation times // since don't know a priori which are invoked by this fix // once in end_of_step() can set timestep for ones actually invoked irepeat = 0; nvalid = nextvalid(); modify->addstep_compute_all(nvalid); } /* ---------------------------------------------------------------------- */ FixAveAtom::~FixAveAtom() { // unregister callback to this fix from Atom class atom->delete_callback(id,0); delete [] which; delete [] argindex; for (int m = 0; m < nvalues; m++) delete [] ids[m]; delete [] ids; delete [] value2index; memory->destroy_2d_double_array(array); } /* ---------------------------------------------------------------------- */ int FixAveAtom::setmask() { int mask = 0; mask |= END_OF_STEP; return mask; } /* ---------------------------------------------------------------------- */ void FixAveAtom::init() { // set indices and check validity of all computes,fixes,variables for (int m = 0; m < nvalues; m++) { if (which[m] == COMPUTE) { int icompute = modify->find_compute(ids[m]); if (icompute < 0) error->all("Compute ID for fix ave/atom does not exist"); value2index[m] = icompute; } else if (which[m] == FIX) { int ifix = modify->find_fix(ids[m]); if (ifix < 0) error->all("Fix ID for fix ave/atom does not exist"); value2index[m] = ifix; } else if (which[m] == VARIABLE) { int ivariable = input->variable->find(ids[m]); if (ivariable < 0) error->all("Variable name for fix ave/atom does not exist"); value2index[m] = ivariable; } else value2index[m] = -1; } // need to reset nvalid if nvalid < ntimestep b/c minimize was performed if (nvalid < update->ntimestep) { irepeat = 0; nvalid = nextvalid(); modify->addstep_compute_all(nvalid); } } /* ---------------------------------------------------------------------- only does something if nvalid = current timestep ------------------------------------------------------------------------- */ void FixAveAtom::setup(int vflag) { end_of_step(); } /* ---------------------------------------------------------------------- */ void FixAveAtom::end_of_step() { int i,j,m,n; // skip if not step which requires doing something - int ntimestep = update->ntimestep; + bigint ntimestep = update->ntimestep; if (ntimestep != nvalid) return; // zero if first step int nlocal = atom->nlocal; if (irepeat == 0) for (i = 0; i < nlocal; i++) for (m = 0; m < nvalues; m++) array[i][m] = 0.0; // accumulate results of attributes,computes,fixes,variables to local copy // compute/fix/variable may invoke computes so wrap with clear/add modify->clearstep_compute(); int *mask = atom->mask; for (m = 0; m < nvalues; m++) { n = value2index[m]; j = argindex[m]; if (which[m] == X) { double **x = atom->x; for (i = 0; i < nlocal; i++) if (mask[i] & groupbit) array[i][m] += x[i][j]; } else if (which[m] == V) { double **v = atom->v; for (i = 0; i < nlocal; i++) if (mask[i] & groupbit) array[i][m] += v[i][j]; } else if (which[m] == F) { double **f = atom->f; for (i = 0; i < nlocal; i++) if (mask[i] & groupbit) array[i][m] += f[i][j]; // invoke compute if not previously invoked } else if (which[m] == COMPUTE) { Compute *compute = modify->compute[n]; if (!(compute->invoked_flag & INVOKED_PERATOM)) { compute->compute_peratom(); compute->invoked_flag |= INVOKED_PERATOM; } if (j == 0) { double *compute_vector = compute->vector_atom; for (i = 0; i < nlocal; i++) if (mask[i] & groupbit) array[i][m] += compute_vector[i]; } else { int jm1 = j - 1; double **compute_array = compute->array_atom; for (i = 0; i < nlocal; i++) if (mask[i] & groupbit) array[i][m] += compute_array[i][jm1]; } // access fix fields, guaranteed to be ready } else if (which[m] == FIX) { if (j == 0) { double *fix_vector = modify->fix[n]->vector_atom; for (i = 0; i < nlocal; i++) if (mask[i] & groupbit) array[i][m] += fix_vector[i]; } else { int jm1 = j - 1; double **fix_array = modify->fix[n]->array_atom; for (i = 0; i < nlocal; i++) if (mask[i] & groupbit) array[i][m] += fix_array[i][jm1]; } // evaluate atom-style variable } else if (which[m] == VARIABLE) input->variable->compute_atom(n,igroup,&array[0][m],nvalues,1); } // done if irepeat < nrepeat // else reset irepeat and nvalid irepeat++; if (irepeat < nrepeat) { nvalid += nevery; modify->addstep_compute(nvalid); return; } irepeat = 0; nvalid = ntimestep+peratom_freq - (nrepeat-1)*nevery; modify->addstep_compute(nvalid); // average the final result for the Nfreq timestep double repeat = nrepeat; for (i = 0; i < nlocal; i++) for (m = 0; m < nvalues; m++) array[i][m] /= repeat; } /* ---------------------------------------------------------------------- memory usage of local atom-based array ------------------------------------------------------------------------- */ double FixAveAtom::memory_usage() { double bytes; bytes = atom->nmax*nvalues * sizeof(double); return bytes; } /* ---------------------------------------------------------------------- allocate atom-based array ------------------------------------------------------------------------- */ void FixAveAtom::grow_arrays(int nmax) { array = memory->grow_2d_double_array(array,nmax,nvalues, "fix_ave/atom:array"); array_atom = array; vector_atom = array[0]; } /* ---------------------------------------------------------------------- copy values within local atom-based array ------------------------------------------------------------------------- */ void FixAveAtom::copy_arrays(int i, int j) { for (int m = 0; m < nvalues; m++) array[j][m] = array[i][m]; } /* ---------------------------------------------------------------------- pack values in local atom-based array for exchange with another proc ------------------------------------------------------------------------- */ int FixAveAtom::pack_exchange(int i, double *buf) { for (int m = 0; m < nvalues; m++) buf[m] = array[i][m]; return nvalues; } /* ---------------------------------------------------------------------- unpack values in local atom-based array from exchange with another proc ------------------------------------------------------------------------- */ int FixAveAtom::unpack_exchange(int nlocal, double *buf) { for (int m = 0; m < nvalues; m++) array[nlocal][m] = buf[m]; return nvalues; } /* ---------------------------------------------------------------------- calculate nvalid = next step on which end_of_step does something can be this timestep if multiple of nfreq and nrepeat = 1 else backup from next multiple of nfreq ------------------------------------------------------------------------- */ -int FixAveAtom::nextvalid() +bigint FixAveAtom::nextvalid() { - int nvalid = (update->ntimestep/peratom_freq)*peratom_freq + peratom_freq; + bigint nvalid = (update->ntimestep/peratom_freq)*peratom_freq + peratom_freq; if (nvalid-peratom_freq == update->ntimestep && nrepeat == 1) nvalid = update->ntimestep; else nvalid -= (nrepeat-1)*nevery; if (nvalid < update->ntimestep) nvalid += peratom_freq; return nvalid; } diff --git a/src/fix_ave_atom.h b/src/fix_ave_atom.h index 7ab406b81..409b78cc2 100644 --- a/src/fix_ave_atom.h +++ b/src/fix_ave_atom.h @@ -1,57 +1,58 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain 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(ave/atom,FixAveAtom) #else #ifndef LMP_FIX_AVE_ATOM_H #define LMP_FIX_AVE_ATOM_H #include "stdio.h" #include "fix.h" +#include "lmptype.h" namespace LAMMPS_NS { class FixAveAtom : public Fix { public: FixAveAtom(class LAMMPS *, int, char **); ~FixAveAtom(); int setmask(); void init(); void setup(int); void end_of_step(); double memory_usage(); void grow_arrays(int); void copy_arrays(int, int); int pack_exchange(int, double *); int unpack_exchange(int, double *); private: int nvalues; - int nrepeat,nvalid,irepeat; + int nrepeat,irepeat; + bigint nvalid; int *which,*argindex,*value2index; char **ids; - double **array; - int nextvalid(); + bigint nextvalid(); }; } #endif #endif diff --git a/src/fix_ave_correlate.cpp b/src/fix_ave_correlate.cpp index 941970e52..b962a0d59 100644 --- a/src/fix_ave_correlate.cpp +++ b/src/fix_ave_correlate.cpp @@ -1,594 +1,597 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- Contributing authors: Benoit Leblanc, Dave Rigby, Paul Saxe (Materials Design) Reese Jones (Sandia) ------------------------------------------------------------------------- */ #include "stdlib.h" #include "string.h" #include "fix_ave_correlate.h" +#include "lmptype.h" #include "update.h" #include "modify.h" #include "compute.h" #include "input.h" #include "variable.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; enum{COMPUTE,FIX,VARIABLE}; enum{ONE,RUNNING}; enum{AUTO,UPPER,LOWER,AUTOUPPER,AUTOLOWER,FULL}; #define INVOKED_SCALAR 1 #define INVOKED_VECTOR 2 #define INVOKED_ARRAY 4 /* ---------------------------------------------------------------------- */ FixAveCorrelate::FixAveCorrelate(LAMMPS * lmp, int narg, char **arg): Fix (lmp, narg, arg) { if (narg < 7) error->all ("Illegal fix ave/correlate command"); MPI_Comm_rank(world,&me); nevery = atoi(arg[3]); nrepeat = atoi(arg[4]); nfreq = atoi(arg[5]); global_freq = nfreq; time_depend = 1; // parse values until one isn't recognized which = new int[narg-6]; argindex = new int[narg-6]; ids = new char*[narg-6]; value2index = new int[narg-6]; nvalues = 0; int iarg = 6; while (iarg < narg) { if (strncmp(arg[iarg],"c_",2) == 0 || strncmp(arg[iarg],"f_",2) == 0 || strncmp(arg[iarg],"v_",2) == 0) { if (arg[iarg][0] == 'c') which[nvalues] = COMPUTE; else if (arg[iarg][0] == 'f') which[nvalues] = FIX; else if (arg[iarg][0] == 'v') which[nvalues] = VARIABLE; int n = strlen(arg[iarg]); char *suffix = new char[n]; strcpy(suffix,&arg[iarg][2]); char *ptr = strchr(suffix,'['); if (ptr) { if (suffix[strlen(suffix)-1] != ']') error->all("Illegal fix ave/correlate command"); argindex[nvalues] = atoi(ptr+1); *ptr = '\0'; } else argindex[nvalues] = 0; n = strlen(suffix) + 1; ids[nvalues] = new char[n]; strcpy(ids[nvalues],suffix); delete [] suffix; nvalues++; iarg++; } else break; } // optional args type = AUTO; ave = ONE; startstep = 0; prefactor = 1.0; fp = NULL; char *title1 = NULL; char *title2 = NULL; char *title3 = NULL; while (iarg < narg) { if (strcmp(arg[iarg],"type") == 0) { if (iarg+2 > narg) error->all("Illegal fix ave/correlate command"); if (strcmp(arg[iarg+1],"auto") == 0) type = AUTO; else if (strcmp(arg[iarg+1],"upper") == 0) type = UPPER; else if (strcmp(arg[iarg+1],"lower") == 0) type = LOWER; else if (strcmp(arg[iarg+1],"auto/upper") == 0) type = AUTOUPPER; else if (strcmp(arg[iarg+1],"auto/lower") == 0) type = AUTOLOWER; else if (strcmp(arg[iarg+1],"full") == 0) type = FULL; else error->all("Illegal fix ave/correlate command"); iarg += 2; } else if (strcmp(arg[iarg],"ave") == 0) { if (iarg+2 > narg) error->all("Illegal fix ave/correlate command"); if (strcmp(arg[iarg+1],"one") == 0) ave = ONE; else if (strcmp(arg[iarg+1],"running") == 0) ave = RUNNING; else error->all("Illegal fix ave/correlate command"); iarg += 2; } else if (strcmp(arg[iarg],"start") == 0) { if (iarg+2 > narg) error->all("Illegal fix ave/correlate command"); startstep = atoi(arg[iarg+1]); iarg += 2; } else if (strcmp(arg[iarg],"prefactor") == 0) { if (iarg+2 > narg) error->all("Illegal fix ave/correlate command"); prefactor = atof(arg[iarg+1]); iarg += 2; } else if (strcmp(arg[iarg],"file") == 0) { if (iarg+2 > narg) error->all("Illegal fix ave/correlate command"); if (me == 0) { fp = fopen(arg[iarg+1],"w"); if (fp == NULL) { char str[128]; sprintf(str,"Cannot open fix ave/correlate file %s",arg[iarg+1]); error->one(str); } } iarg += 2; } else if (strcmp(arg[iarg],"title1") == 0) { if (iarg+2 > narg) error->all("Illegal fix ave/correlate command"); delete [] title1; int n = strlen(arg[iarg+1]) + 1; title1 = new char[n]; strcpy(title1,arg[iarg+1]); iarg += 2; } else if (strcmp(arg[iarg],"title2") == 0) { if (iarg+2 > narg) error->all("Illegal fix ave/correlate command"); delete [] title2; int n = strlen(arg[iarg+1]) + 1; title2 = new char[n]; strcpy(title2,arg[iarg+1]); iarg += 2; } else if (strcmp(arg[iarg],"title3") == 0) { if (iarg+2 > narg) error->all("Illegal fix ave/correlate command"); delete [] title3; int n = strlen(arg[iarg+1]) + 1; title3 = new char[n]; strcpy(title3,arg[iarg+1]); iarg += 2; } else error->all("Illegal fix ave/correlate command"); } // setup and error check // for fix inputs, check that fix frequency is acceptable if (nevery <= 0 || nrepeat <= 0 || nfreq <= 0) error->all("Illegal fix ave/correlate command"); if (nfreq % nevery) error->all("Illegal fix ave/correlate command"); if (ave == ONE && nfreq < (nrepeat-1)*nevery) error->all("Illegal fix ave/correlate command"); for (int i = 0; i < nvalues; i++) { if (which[i] == COMPUTE) { int icompute = modify->find_compute(ids[i]); if (icompute < 0) error->all ("Compute ID for fix ave/correlate does not exist"); if (argindex[i] == 0 && modify->compute[icompute]->scalar_flag == 0) error->all ("Fix ave/correlate compute does not calculate a scalar"); if (argindex[i] && modify->compute[icompute]->vector_flag == 0) error->all ("Fix ave/correlate compute does not calculate a vector"); if (argindex[i] && argindex[i] > modify->compute[icompute]->size_vector) error->all ("Fix ave/correlate compute vector " "is accessed out-of-range"); } else if (which[i] == FIX) { int ifix = modify->find_fix(ids[i]); if (ifix < 0) error->all ("Fix ID for fix ave/correlate does not exist"); if (argindex[i] == 0 && modify->fix[ifix]->scalar_flag == 0) error->all ("Fix ave/correlate fix does not calculate a scalar"); if (argindex[i] && modify->fix[ifix]->vector_flag == 0) error->all ("Fix ave/correlate fix does not calculate a vector"); if (argindex[i] && argindex[i] > modify->fix[ifix]->size_vector) error->all ("Fix ave/correlate fix vector is accessed out-of-range"); if (nevery % modify->fix[ifix]->global_freq) error->all("Fix for fix ave/correlate " "not computed at compatible time"); } else if (which[i] == VARIABLE) { int ivariable = input->variable->find(ids[i]); if (ivariable < 0) error->all ("Variable name for fix ave/correlate does not exist"); if (input->variable->equalstyle(ivariable) == 0) error->all ("Fix ave/correlate variable is not equal-style variable"); } } // npair = # of correlation pairs to calculate if (type == AUTO) npair = nvalues; if (type == UPPER || type == LOWER) npair = nvalues*(nvalues-1)/2; if (type == AUTOUPPER || type == AUTOLOWER) npair = nvalues*(nvalues+1)/2; if (type == FULL) npair = nvalues*nvalues; // print file comment lines if (fp && me == 0) { if (title1) fprintf(fp,"%s\n",title1); else fprintf(fp,"# Time-correlated data for fix %s\n",id); if (title2) fprintf(fp,"%s\n",title2); else fprintf(fp,"# Timestep Number-of-time-windows\n"); if (title3) fprintf(fp,"%s\n",title3); else { fprintf(fp,"# Index TimeDelta Ncount"); if (type == AUTO) for (int i = 0; i < nvalues; i++) fprintf(fp," %s*%s",arg[6+i],arg[6+i]); else if (type == UPPER) for (int i = 0; i < nvalues; i++) for (int j = i+1; j < nvalues; j++) fprintf(fp," %s*%s",arg[6+i],arg[6+j]); else if (type == LOWER) for (int i = 0; i < nvalues; i++) for (int j = 0; j < i-1; j++) fprintf(fp," %s*%s",arg[6+i],arg[6+j]); else if (type == AUTOUPPER) for (int i = 0; i < nvalues; i++) for (int j = i; j < nvalues; j++) fprintf(fp," %s*%s",arg[6+i],arg[6+j]); else if (type == AUTOLOWER) for (int i = 0; i < nvalues; i++) for (int j = 0; j < i; j++) fprintf(fp," %s*%s",arg[6+i],arg[6+j]); else if (type == FULL) for (int i = 0; i < nvalues; i++) for (int j = 0; j < nvalues; j++) fprintf(fp," %s*%s",arg[6+i],arg[6+j]); fprintf(fp,"\n"); } } delete [] title1; delete [] title2; delete [] title3; // allocate and initialize memory for averaging // set count and corr to zero since they accumulate // also set save versions to zero in case accessed via compute_array() values = memory->create_2d_double_array(nrepeat,nvalues, "ave/correlate:values"); count = (int *) memory->smalloc(nrepeat*sizeof(int), "ave/correlate:count"); save_count = (int *) memory->smalloc(nrepeat*sizeof(int), "ave/correlate:save_count"); corr = memory->create_2d_double_array(nrepeat,npair, "ave/correlate:corr"); save_corr = memory->create_2d_double_array(nrepeat,npair, "ave/correlate:save_corr"); int i,j; for (i = 0; i < nrepeat; i++) { save_count[i] = count[i] = 0; for (j = 0; j < npair; j++) save_corr[i][j] = corr[i][j] = 0.0; } // this fix produces a global array array_flag = 1; size_array_rows = nrepeat; size_array_cols = npair+2; extarray = 0; // nvalid = next step on which end_of_step does something // add nvalid to all computes that store invocation times // since don't know a priori which are invoked by this fix // once in end_of_step() can set timestep for ones actually invoked lastindex = -1; firstindex = 0; nsample = 0; nvalid = nextvalid(); modify->addstep_compute_all(nvalid); } /* ---------------------------------------------------------------------- */ FixAveCorrelate::~FixAveCorrelate() { delete [] which; delete [] argindex; delete [] value2index; for (int i = 0; i < nvalues; i++) delete [] ids[i]; delete [] ids; memory->destroy_2d_double_array(values); memory->sfree(count); memory->sfree(save_count); memory->destroy_2d_double_array(corr); memory->destroy_2d_double_array(save_corr); if (fp && me == 0) fclose(fp); } /* ---------------------------------------------------------------------- */ int FixAveCorrelate::setmask() { int mask = 0; mask |= END_OF_STEP; return mask; } /* ---------------------------------------------------------------------- */ void FixAveCorrelate::init() { // set current indices for all computes,fixes,variables for (int i = 0; i < nvalues; i++) { if (which[i] == COMPUTE) { int icompute = modify->find_compute(ids[i]); if (icompute < 0) error->all("Compute ID for fix ave/correlate does not exist"); value2index[i] = icompute; } else if (which[i] == FIX) { int ifix = modify->find_fix(ids[i]); if (ifix < 0) error->all("Fix ID for fix ave/correlate does not exist"); value2index[i] = ifix; } else if (which[i] == VARIABLE) { int ivariable = input->variable->find(ids[i]); if (ivariable < 0) error->all("Variable name for fix ave/correlate does not exist"); value2index[i] = ivariable; } } // need to reset nvalid if nvalid < ntimestep b/c minimize was performed if (nvalid < update->ntimestep) { lastindex = -1; firstindex = 0; nsample = 0; nvalid = nextvalid(); modify->addstep_compute_all(nvalid); } } /* ---------------------------------------------------------------------- only does something if nvalid = current timestep ------------------------------------------------------------------------- */ void FixAveCorrelate::setup(int vflag) { end_of_step(); } /* ---------------------------------------------------------------------- */ void FixAveCorrelate::end_of_step() { int i,j,k,m; double scalar; // skip if not step which requires doing something - int ntimestep = update->ntimestep; + bigint ntimestep = update->ntimestep; if (ntimestep != nvalid) return; // accumulate results of computes,fixes,variables to origin // compute/fix/variable may invoke computes so wrap with clear/add modify->clearstep_compute(); // lastindex = index in values ring of latest time sample lastindex++; if (lastindex == nrepeat) lastindex = 0; for (i = 0; i < nvalues; i++) { m = value2index[i]; // invoke compute if not previously invoked if (which[i] == COMPUTE) { Compute *compute = modify->compute[m]; if (argindex[i] == 0) { if (!(compute->invoked_flag & INVOKED_SCALAR)) { compute->compute_scalar(); compute->invoked_flag |= INVOKED_SCALAR; } scalar = compute->scalar; } else { if (!(compute->invoked_flag & INVOKED_VECTOR)) { compute->compute_vector(); compute->invoked_flag |= INVOKED_VECTOR; } scalar = compute->vector[argindex[i]-1]; } // access fix fields, guaranteed to be ready } else if (which[i] == FIX) { if (argindex[i] == 0) scalar = modify->fix[m]->compute_scalar(); else scalar = modify->fix[m]->compute_vector(argindex[i]-1); // evaluate equal-style variable } else if (which[i] == VARIABLE) scalar = input->variable->compute_equal(m); values[lastindex][i] = scalar; } // fistindex = index in values ring of earliest time sample // nsample = number of time samples in values ring if (nsample < nrepeat) nsample++; else { firstindex++; if (firstindex == nrepeat) firstindex = 0; } nvalid += nevery; modify->addstep_compute(nvalid); // calculate all Cij() enabled by latest values accumulate(); if (ntimestep % nfreq) return; // save results in save_count and save_corr for (i = 0; i < nrepeat; i++) { save_count[i] = count[i]; if (count[i]) for (j = 0; j < npair; j++) save_corr[i][j] = prefactor*corr[i][j]/count[i]; else for (j = 0; j < npair; j++) save_corr[i][j] = 0.0; } // output to file if (fp && me == 0) { - fprintf(fp,"%d %d\n",ntimestep,nrepeat); + char fstr[16]; + sprintf(fstr,"%s %%d\n",BIGINT_FORMAT); + fprintf(fp,fstr,ntimestep,nrepeat); for (i = 0; i < nrepeat; i++) { fprintf(fp,"%d %d %d",i+1,i*nevery,count[i]); if (count[i]) for (j = 0; j < npair; j++) fprintf(fp," %g",prefactor*corr[i][j]/count[i]); else for (j = 0; j < npair; j++) fprintf(fp," 0.0"); fprintf(fp,"\n"); } fflush(fp); } // zero accumulation if requested // recalculate Cij(0) if (ave == ONE) { for (i = 0; i < nrepeat; i++) { count[i] = 0; for (j = 0; j < npair; j++) corr[i][j] = 0.0; } nsample = 1; accumulate(); } } /* ---------------------------------------------------------------------- accumulate correlation data using more recently added values ------------------------------------------------------------------------- */ void FixAveCorrelate::accumulate() { int i,j,k,m,n,ipair; for (k = 0; k < nsample; k++) count[k]++; if (type == AUTO) { m = n = lastindex; for (k = 0; k < nsample; k++) { ipair = 0; for (i = 0; i < nvalues; i++) { corr[k][ipair++] += values[m][i]*values[n][i]; } m--; if (m < 0) m = nrepeat-1; } } else if (type == UPPER) { m = n = lastindex; for (k = 0; k < nsample; k++) { ipair = 0; for (i = 0; i < nvalues; i++) for (j = i+1; j < nvalues; j++) corr[k][ipair++] += values[m][i]*values[n][j]; m--; if (m < 0) m = nrepeat-1; } } else if (type == LOWER) { m = n = lastindex; for (k = 0; k < nsample; k++) { ipair = 0; for (i = 0; i < nvalues; i++) for (j = 0; j < i-1; j++) corr[k][ipair++] += values[m][i]*values[n][j]; m--; if (m < 0) m = nrepeat-1; } } else if (type == AUTOUPPER) { m = n = lastindex; for (k = 0; k < nsample; k++) { ipair = 0; for (i = 0; i < nvalues; i++) for (j = i; j < nvalues; j++) corr[k][ipair++] += values[m][i]*values[n][j]; m--; if (m < 0) m = nrepeat-1; } } else if (type == AUTOLOWER) { m = n = lastindex; for (k = 0; k < nsample; k++) { ipair = 0; for (i = 0; i < nvalues; i++) for (j = 0; j < i; j++) corr[k][ipair++] += values[m][i]*values[n][j]; m--; if (m < 0) m = nrepeat-1; } } else if (type == FULL) { m = n = lastindex; for (k = 0; k < nsample; k++) { ipair = 0; for (i = 0; i < nvalues; i++) for (j = 0; j < nvalues; j++) corr[k][ipair++] += values[m][i]*values[n][j]; m--; if (m < 0) m = nrepeat-1; } } } /* ---------------------------------------------------------------------- return I,J array value ------------------------------------------------------------------------- */ double FixAveCorrelate::compute_array(int i, int j) { if (j == 0) return 1.0*i*nevery; else if (j == 1) return 1.0*save_count[i]; else if (save_count[i]) return save_corr[i][j-2]; return 0.0; } /* ---------------------------------------------------------------------- nvalid = next step on which end_of_step does something this step if multiple of nevery, else next multiple startstep is lower bound ------------------------------------------------------------------------- */ -int FixAveCorrelate::nextvalid() +bigint FixAveCorrelate::nextvalid() { - int nvalid = update->ntimestep; + bigint nvalid = update->ntimestep; if (startstep > nvalid) nvalid = startstep; if (nvalid % nevery) nvalid = (nvalid/nevery)*nevery + nevery; return nvalid; } diff --git a/src/fix_ave_correlate.h b/src/fix_ave_correlate.h index faacf6eab..e5dc5046c 100644 --- a/src/fix_ave_correlate.h +++ b/src/fix_ave_correlate.h @@ -1,67 +1,69 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ #ifdef FIX_CLASS FixStyle(ave/correlate,FixAveCorrelate) #else #ifndef LMP_FIX_AVE_CORRELATE_H #define LMP_FIX_AVE_CORRELATE_H #include "stdio.h" #include "fix.h" +#include "lmptype.h" namespace LAMMPS_NS { class FixAveCorrelate : public Fix { public: FixAveCorrelate(class LAMMPS *, int, char **); ~FixAveCorrelate(); int setmask(); void init(); void setup(int); void end_of_step(); double compute_array(int,int); private: int me,nvalues; - int nrepeat,nfreq,nvalid; + int nrepeat,nfreq; + bigint nvalid; int *which,*argindex,*value2index; char **ids; FILE *fp; int type,ave,startstep; double prefactor; char *title1,*title2,*title3; int firstindex; // index in values ring of earliest time sample int lastindex; // index in values ring of latest time sample int nsample; // number of time samples in values ring int npair; // number of correlation pairs to calculate int *count; double **values,**corr; int *save_count; // saved values at Nfreq for output via compute_array() double **save_corr; void accumulate(); - int nextvalid(); + bigint nextvalid(); }; } #endif #endif diff --git a/src/fix_ave_histo.cpp b/src/fix_ave_histo.cpp index d04fea1c3..b0c234583 100644 --- a/src/fix_ave_histo.cpp +++ b/src/fix_ave_histo.cpp @@ -1,1001 +1,1003 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ #include "stdlib.h" #include "string.h" #include "fix_ave_histo.h" +#include "lmptype.h" #include "atom.h" #include "update.h" #include "modify.h" #include "compute.h" #include "group.h" #include "input.h" #include "variable.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; enum{X,V,F,COMPUTE,FIX,VARIABLE}; enum{ONE,RUNNING}; enum{SCALAR,VECTOR,WINDOW}; enum{GLOBAL,PERATOM,LOCAL}; enum{IGNORE,END,EXTRA}; #define INVOKED_SCALAR 1 #define INVOKED_VECTOR 2 #define INVOKED_ARRAY 4 #define INVOKED_PERATOM 8 #define INVOKED_LOCAL 16 #define BIG 1.0e20 #define MIN(A,B) ((A) < (B)) ? (A) : (B) #define MAX(A,B) ((A) > (B)) ? (A) : (B) /* ---------------------------------------------------------------------- */ FixAveHisto::FixAveHisto(LAMMPS *lmp, int narg, char **arg) : Fix(lmp, narg, arg) { if (narg < 10) error->all("Illegal fix ave/histo command"); MPI_Comm_rank(world,&me); nevery = atoi(arg[3]); nrepeat = atoi(arg[4]); nfreq = atoi(arg[5]); global_freq = nfreq; vector_flag = 1; size_vector = 4; extvector = 0; array_flag = 1; size_local_cols = 3; extarray = 0; time_depend = 1; lo = atof(arg[6]); hi = atof(arg[7]); nbins = atoi(arg[8]); // scan values to count them // then read options so know mode = SCALAR/VECTOR before re-reading values nvalues = 0; int iarg = 9; while (iarg < narg) { if (strcmp(arg[iarg],"x") == 0 || strcmp(arg[iarg],"y") == 0 || strcmp(arg[iarg],"z") == 0 || strcmp(arg[iarg],"vx") == 0 || strcmp(arg[iarg],"vy") == 0 || strcmp(arg[iarg],"vz") == 0 || strcmp(arg[iarg],"fx") == 0 || strcmp(arg[iarg],"fy") == 0 || strcmp(arg[iarg],"fz") == 0 || strncmp(arg[iarg],"c_",2) == 0 || strncmp(arg[iarg],"f_",2) == 0 || strncmp(arg[iarg],"v_",2) == 0) { nvalues++; iarg++; } else break; } options(narg,arg); // parse values until one isn't recognized // if mode = VECTOR and value is a global array: // expand it as if columns listed one by one // adjust nvalues accordingly via maxvalues which = argindex = value2index = NULL; ids = NULL; int maxvalues = nvalues; allocate_values(maxvalues); nvalues = 0; iarg = 9; while (iarg < narg) { if (strcmp(arg[iarg],"x") == 0) { which[nvalues] = X; argindex[nvalues] = 0; ids[nvalues] = NULL; nvalues++; iarg++; } else if (strcmp(arg[iarg],"y") == 0) { which[nvalues] = X; argindex[nvalues] = 1; ids[nvalues] = NULL; nvalues++; iarg++; } else if (strcmp(arg[iarg],"z") == 0) { which[nvalues] = X; argindex[nvalues] = 2; ids[nvalues] = NULL; nvalues++; iarg++; } else if (strcmp(arg[iarg],"vx") == 0) { which[nvalues] = V; argindex[nvalues] = 0; ids[nvalues] = NULL; nvalues++; iarg++; } else if (strcmp(arg[iarg],"vy") == 0) { which[nvalues] = V; argindex[nvalues] = 1; ids[nvalues] = NULL; nvalues++; iarg++; } else if (strcmp(arg[iarg],"vz") == 0) { which[nvalues] = V; argindex[nvalues] = 2; ids[nvalues] = NULL; nvalues++; iarg++; } else if (strcmp(arg[iarg],"fx") == 0) { which[nvalues] = F; argindex[nvalues] = 0; ids[nvalues] = NULL; nvalues++; iarg++; } else if (strcmp(arg[iarg],"fy") == 0) { which[nvalues] = F; argindex[nvalues] = 1; ids[nvalues] = NULL; nvalues++; iarg++; } else if (strcmp(arg[iarg],"fz") == 0) { which[nvalues] = F; argindex[nvalues] = 2; ids[nvalues] = NULL; nvalues++; iarg++; } else if ((strncmp(arg[iarg],"c_",2) == 0) || (strncmp(arg[iarg],"f_",2) == 0) || (strncmp(arg[iarg],"v_",2) == 0)) { if (arg[iarg][0] == 'c') which[nvalues] = COMPUTE; else if (arg[iarg][0] == 'f') which[nvalues] = FIX; else if (arg[iarg][0] == 'v') which[nvalues] = VARIABLE; int n = strlen(arg[iarg]); char *suffix = new char[n]; strcpy(suffix,&arg[iarg][2]); char *ptr = strchr(suffix,'['); if (ptr) { if (suffix[strlen(suffix)-1] != ']') error->all("Illegal fix ave/histo command"); argindex[nvalues] = atoi(ptr+1); *ptr = '\0'; } else argindex[nvalues] = 0; n = strlen(suffix) + 1; ids[nvalues] = new char[n]; strcpy(ids[nvalues],suffix); delete [] suffix; if (mode == VECTOR && which[nvalues] == COMPUTE && argindex[nvalues] == 0) { int icompute = modify->find_compute(ids[nvalues]); if (icompute < 0) error->all("Compute ID for fix ave/histo does not exist"); if (modify->compute[icompute]->array_flag) { int ncols = modify->compute[icompute]->size_array_cols; maxvalues += ncols-1; allocate_values(maxvalues); argindex[nvalues] = 1; for (int icol = 1; icol < ncols; icol++) { which[nvalues+icol] = which[nvalues]; argindex[nvalues+icol] = icol+1; n = strlen(ids[nvalues]) + 1; ids[nvalues+icol] = new char[n]; strcpy(ids[nvalues+icol],ids[nvalues]); } nvalues += ncols-1; } } else if (mode == VECTOR && which[nvalues] == FIX && argindex[nvalues] == 0) { int ifix = modify->find_fix(ids[nvalues]); if (ifix < 0) error->all("Fix ID for fix ave/histo does not exist"); if (modify->fix[ifix]->array_flag) { int ncols = modify->fix[ifix]->size_array_cols; maxvalues += ncols-1; allocate_values(maxvalues); argindex[nvalues] = 1; for (int icol = 1; icol < ncols; icol++) { which[nvalues+icol] = which[nvalues]; argindex[nvalues+icol] = icol+1; n = strlen(ids[nvalues]) + 1; ids[nvalues+icol] = new char[n]; strcpy(ids[nvalues+icol],ids[nvalues]); } nvalues += ncols-1; } } nvalues++; iarg++; } else break; } // setup and error check // kind = inputs are all global, or all per-atom, or all local // for fix inputs, check that fix frequency is acceptable if (nevery <= 0 || nrepeat <= 0 || nfreq <= 0) error->all("Illegal fix ave/histo command"); if (nfreq % nevery || (nrepeat-1)*nevery >= nfreq) error->all("Illegal fix ave/histo command"); if (lo >= hi) error->all("Illegal fix ave/histo command"); if (nbins <= 0) error->all("Illegal fix ave/histo command"); int kindflag; for (int i = 0; i < nvalues; i++) { if (which[i] == X || which[i] == V || which[i] == F) kindflag = PERATOM; else if (which[i] == COMPUTE) { Compute *compute = modify->compute[modify->find_compute(ids[0])]; if (compute->scalar_flag || compute->vector_flag || compute->array_flag) kindflag = GLOBAL; else if (compute->peratom_flag) kindflag = PERATOM; else if (compute->local_flag) kindflag = LOCAL; else error->all("Fix ave/histo input is invalid compute"); } else if (which[i] == FIX) { Fix *fix = modify->fix[modify->find_fix(ids[0])]; if (fix->scalar_flag || fix->vector_flag || fix->array_flag) kindflag = GLOBAL; else if (fix->peratom_flag) kindflag = PERATOM; else if (fix->local_flag) kindflag = LOCAL; else error->all("Fix ave/histo input is invalid fix"); } else if (which[i] == VARIABLE) { int ivariable = input->variable->find(ids[i]); if (input->variable->equalstyle(ivariable)) kindflag = GLOBAL; else if (input->variable->atomstyle(ivariable)) kindflag = PERATOM; else error->all("Fix ave/histo input is invalid variable"); } if (i == 0) kind = kindflag; else if (kindflag != kind) error->all("Fix ave/histo inputs are not all global, peratom, or local"); } if (kind == PERATOM && mode == SCALAR) error->all("Fix ave/histo cannot input per-atom values in scalar mode"); if (kind == LOCAL && mode == SCALAR) error->all("Fix ave/histo cannot input local values in scalar mode"); for (int i = 0; i < nvalues; i++) { if (which[i] == COMPUTE && kind == GLOBAL && mode == SCALAR) { int icompute = modify->find_compute(ids[i]); if (icompute < 0) error->all("Compute ID for fix ave/histo does not exist"); if (argindex[i] == 0 && modify->compute[icompute]->scalar_flag == 0) error->all("Fix ave/histo compute does not calculate a global scalar"); if (argindex[i] && modify->compute[icompute]->vector_flag == 0) error->all("Fix ave/histo compute does not calculate a global vector"); if (argindex[i] && argindex[i] > modify->compute[icompute]->size_vector) error->all("Fix ave/histo compute vector is accessed out-of-range"); } else if (which[i] == COMPUTE && kind == GLOBAL && mode == VECTOR) { int icompute = modify->find_compute(ids[i]); if (icompute < 0) error->all("Compute ID for fix ave/histo does not exist"); if (argindex[i] == 0 && modify->compute[icompute]->vector_flag == 0) error->all("Fix ave/histo compute does not calculate a global vector"); if (argindex[i] && modify->compute[icompute]->array_flag == 0) error->all("Fix ave/histo compute does not calculate a global array"); if (argindex[i] && argindex[i] > modify->compute[icompute]->size_array_cols) error->all("Fix ave/histo compute array is accessed out-of-range"); } else if (which[i] == COMPUTE && kind == PERATOM) { int icompute = modify->find_compute(ids[i]); if (icompute < 0) error->all("Compute ID for fix ave/histo does not exist"); if (modify->compute[icompute]->peratom_flag == 0) error->all("Fix ave/histo compute does not calculate per-atom values"); if (argindex[i] == 0 && modify->compute[icompute]->size_peratom_cols != 0) error->all("Fix ave/histo compute does not " "calculate a per-atom vector"); if (argindex[i] && modify->compute[icompute]->size_peratom_cols == 0) error->all("Fix ave/histo compute does not " "calculate a per-atom array"); if (argindex[i] && argindex[i] > modify->compute[icompute]->size_peratom_cols) error->all("Fix ave/histo compute array is accessed out-of-range"); } else if (which[i] == COMPUTE && kind == LOCAL) { int icompute = modify->find_compute(ids[i]); if (icompute < 0) error->all("Compute ID for fix ave/histo does not exist"); if (modify->compute[icompute]->local_flag == 0) error->all("Fix ave/histo compute does not calculate local values"); if (argindex[i] == 0 && modify->compute[icompute]->size_local_cols != 0) error->all("Fix ave/histo compute does not " "calculate a local vector"); if (argindex[i] && modify->compute[icompute]->size_local_cols == 0) error->all("Fix ave/histo compute does not " "calculate a local array"); if (argindex[i] && argindex[i] > modify->compute[icompute]->size_local_cols) error->all("Fix ave/histo compute array is accessed out-of-range"); } else if (which[i] == FIX && kind == GLOBAL && mode == SCALAR) { int ifix = modify->find_fix(ids[i]); if (ifix < 0) error->all("Fix ID for fix ave/histo does not exist"); if (argindex[i] == 0 && modify->fix[ifix]->scalar_flag == 0) error->all("Fix ave/histo fix does not calculate a global scalar"); if (argindex[i] && modify->fix[ifix]->vector_flag == 0) error->all("Fix ave/histo fix does not calculate a global vector"); if (argindex[i] && argindex[i] > modify->fix[ifix]->size_vector) error->all("Fix ave/histo fix vector is accessed out-of-range"); if (nevery % modify->fix[ifix]->global_freq) error->all("Fix for fix ave/histo not computed at compatible time"); } else if (which[i] == FIX && kind == GLOBAL && mode == VECTOR) { int ifix = modify->find_fix(ids[i]); if (ifix < 0) error->all("Fix ID for fix ave/histo does not exist"); if (argindex[i] == 0 && modify->fix[ifix]->vector_flag == 0) error->all("Fix ave/histo fix does not calculate a global vector"); if (argindex[i] && modify->fix[ifix]->array_flag == 0) error->all("Fix ave/histo fix does not calculate a global array"); if (argindex[i] && argindex[i] > modify->fix[ifix]->size_array_cols) error->all("Fix ave/histo fix array is accessed out-of-range"); if (nevery % modify->fix[ifix]->global_freq) error->all("Fix for fix ave/histo not computed at compatible time"); } else if (which[i] == FIX && kind == PERATOM) { int ifix = modify->find_fix(ids[i]); if (ifix < 0) error->all("Fix ID for fix ave/histo does not exist"); if (modify->fix[ifix]->peratom_flag == 0) error->all("Fix ave/histo fix does not calculate per-atom values"); if (argindex[i] == 0 && modify->fix[ifix]->size_peratom_cols != 0) error->all("Fix ave/histo fix does not " "calculate a per-atom vector"); if (argindex[i] && modify->fix[ifix]->size_peratom_cols == 0) error->all("Fix ave/histo fix does not " "calculate a per-atom array"); if (argindex[i] && argindex[i] > modify->fix[ifix]->size_peratom_cols) error->all("Fix ave/histo fix array is accessed out-of-range"); if (nevery % modify->fix[ifix]->global_freq) error->all("Fix for fix ave/histo not computed at compatible time"); } else if (which[i] == FIX && kind == LOCAL) { int ifix = modify->find_fix(ids[i]); if (ifix < 0) error->all("Fix ID for fix ave/histo does not exist"); if (modify->fix[ifix]->local_flag == 0) error->all("Fix ave/histo fix does not calculate local values"); if (argindex[i] == 0 && modify->fix[ifix]->size_local_cols != 0) error->all("Fix ave/histo fix does not " "calculate a local vector"); if (argindex[i] && modify->fix[ifix]->size_local_cols == 0) error->all("Fix ave/histo fix does not " "calculate a local array"); if (argindex[i] && argindex[i] > modify->fix[ifix]->size_local_cols) error->all("Fix ave/histo fix array is accessed out-of-range"); if (nevery % modify->fix[ifix]->global_freq) error->all("Fix for fix ave/histo not computed at compatible time"); } else if (which[i] == VARIABLE && kind == GLOBAL) { int ivariable = input->variable->find(ids[i]); if (ivariable < 0) error->all("Variable name for fix ave/histo does not exist"); } else if (which[i] == VARIABLE && kind == PERATOM) { int ivariable = input->variable->find(ids[i]); if (ivariable < 0) error->all("Variable name for fix ave/histo does not exist"); } } // print file comment lines if (fp && me == 0) { if (title1) fprintf(fp,"%s\n",title1); else fprintf(fp,"# Histogrammed data for fix %s\n",id); if (title2) fprintf(fp,"%s\n",title2); else fprintf(fp,"# TimeStep Number-of-bins " "Total-counts Missing-counts Min-value Max-value\n"); if (title3) fprintf(fp,"%s\n",title3); else fprintf(fp,"# Bin Coord Count Count/Total\n"); } delete [] title1; delete [] title2; delete [] title3; // allocate and initialize memory for averaging if (beyond == EXTRA) nbins += 2; size_local_rows = nbins; bin = new double[nbins]; bin_total = new double[nbins]; bin_all = new double[nbins]; coord = new double[nbins]; stats_list = NULL; bin_list = NULL; vector = NULL; maxatom = 0; if (ave == WINDOW) { stats_list = memory->create_2d_double_array(nwindow,4, "ave/histo:stats_list"); bin_list = memory->create_2d_double_array(nwindow,nbins, "ave/histo:bin_list"); } // initializations // set coord to bin centers if (beyond == EXTRA) { binsize = (hi-lo)/(nbins-2); bininv = 1.0/binsize; } else { binsize = (hi-lo)/nbins; bininv = 1.0/binsize; } if (beyond == EXTRA) { coord[0] = lo; coord[nbins-1] = hi; for (int i = 1; i < nbins-1; i++) coord[i] = lo + (i-1+0.5)*binsize; } else { for (int i = 0; i < nbins; i++) coord[i] = lo + (i+0.5)*binsize; } irepeat = 0; iwindow = window_limit = 0; stats_total[0] = stats_total[1] = stats_total[2] = stats_total[3] = 0.0; for (int i = 0; i < nbins; i++) bin_total[i] = 0.0; // nvalid = next step on which end_of_step does something // add nvalid to all computes that store invocation times // since don't know a priori which are invoked by this fix // once in end_of_step() can set timestep for ones actually invoked nvalid = nextvalid(); modify->addstep_compute_all(nvalid); } /* ---------------------------------------------------------------------- */ FixAveHisto::~FixAveHisto() { memory->sfree(which); memory->sfree(argindex); memory->sfree(value2index); for (int i = 0; i < nvalues; i++) delete [] ids[i]; memory->sfree(ids); if (fp && me == 0) fclose(fp); delete [] bin; delete [] bin_total; delete [] bin_all; delete [] coord; memory->destroy_2d_double_array(stats_list); memory->destroy_2d_double_array(bin_list); memory->sfree(vector); } /* ---------------------------------------------------------------------- */ int FixAveHisto::setmask() { int mask = 0; mask |= END_OF_STEP; return mask; } /* ---------------------------------------------------------------------- */ void FixAveHisto::init() { // set current indices for all computes,fixes,variables for (int i = 0; i < nvalues; i++) { if (which[i] == COMPUTE) { int icompute = modify->find_compute(ids[i]); if (icompute < 0) error->all("Compute ID for fix ave/histo does not exist"); value2index[i] = icompute; } else if (which[i] == FIX) { int ifix = modify->find_fix(ids[i]); if (ifix < 0) error->all("Fix ID for fix ave/histo does not exist"); value2index[i] = ifix; } else if (which[i] == VARIABLE) { int ivariable = input->variable->find(ids[i]); if (ivariable < 0) error->all("Variable name for fix ave/histo does not exist"); value2index[i] = ivariable; } } // need to reset nvalid if nvalid < ntimestep b/c minimize was performed if (nvalid < update->ntimestep) { irepeat = 0; nvalid = nextvalid(); modify->addstep_compute_all(nvalid); } } /* ---------------------------------------------------------------------- only does something if nvalid = current timestep ------------------------------------------------------------------------- */ void FixAveHisto::setup(int vflag) { end_of_step(); } /* ---------------------------------------------------------------------- */ void FixAveHisto::end_of_step() { int i,j,m; // skip if not step which requires doing something - int ntimestep = update->ntimestep; + bigint ntimestep = update->ntimestep; if (ntimestep != nvalid) return; // zero if first step if (irepeat == 0) { stats[0] = stats[1] = 0.0; stats[2] = BIG; stats[3] = -BIG; for (i = 0; i < nbins; i++) bin[i] = 0.0; } // accumulate results of computes,fixes,variables to local copy // compute/fix/variable may invoke computes so wrap with clear/add modify->clearstep_compute(); for (i = 0; i < nvalues; i++) { m = value2index[i]; j = argindex[i]; // atom attributes if (which[i] == X) bin_atoms(&atom->x[0][j],3); else if (which[i] == V) bin_atoms(&atom->v[0][j],3); else if (which[i] == F) bin_atoms(&atom->f[0][j],3); // invoke compute if not previously invoked if (which[i] == COMPUTE) { Compute *compute = modify->compute[m]; if (kind == GLOBAL && mode == SCALAR) { if (j == 0) { if (!(compute->invoked_flag & INVOKED_SCALAR)) { compute->compute_scalar(); compute->invoked_flag |= INVOKED_SCALAR; } bin_one(compute->scalar); } else { if (!(compute->invoked_flag & INVOKED_VECTOR)) { compute->compute_vector(); compute->invoked_flag |= INVOKED_VECTOR; } bin_one(compute->vector[j-1]); } } else if (kind == GLOBAL && mode == VECTOR) { if (j == 0) { if (!(compute->invoked_flag & INVOKED_VECTOR)) { compute->compute_vector(); compute->invoked_flag |= INVOKED_VECTOR; } bin_vector(compute->size_vector,compute->vector,1); } else { if (!(compute->invoked_flag & INVOKED_ARRAY)) { compute->compute_array(); compute->invoked_flag |= INVOKED_ARRAY; } bin_vector(compute->size_array_rows,&compute->array[0][j-1], compute->size_array_cols); } } else if (kind == PERATOM) { if (!(compute->invoked_flag & INVOKED_PERATOM)) { compute->compute_peratom(); compute->invoked_flag |= INVOKED_PERATOM; } if (j == 0) bin_atoms(compute->vector_atom,1); else bin_atoms(compute->array_atom[j-1], compute->size_peratom_cols); } else if (kind == LOCAL) { if (!(compute->invoked_flag & INVOKED_LOCAL)) { compute->compute_local(); compute->invoked_flag |= INVOKED_LOCAL; } if (j == 0) bin_vector(compute->size_local_rows,compute->vector_local,1); else bin_vector(compute->size_local_rows,&compute->array_local[0][j-1], compute->size_local_cols); } // access fix fields, guaranteed to be ready } else if (which[i] == FIX) { Fix *fix = modify->fix[m]; if (kind == GLOBAL && mode == SCALAR) { if (j == 0) bin_one(fix->compute_scalar()); else bin_one(fix->compute_vector(j-1)); } else if (kind == GLOBAL && mode == VECTOR) { if (j == 0) { int n = fix->size_vector; for (i = 0; i < n; i++) bin_one(fix->compute_vector(i)); } else { int n = fix->size_vector; for (i = 0; i < n; i++) bin_one(fix->compute_array(i,j-1)); } } else if (kind == PERATOM) { if (j == 0) bin_atoms(fix->vector_atom,1); else bin_atoms(fix->array_atom[j-1],fix->size_peratom_cols); } else if (kind == LOCAL) { if (j == 0) bin_vector(fix->size_local_rows,fix->vector_local,1); else bin_vector(fix->size_local_rows,&fix->array_local[0][j-1], fix->size_local_cols); } // evaluate equal-style variable } else if (which[i] == VARIABLE && kind == GLOBAL) { bin_one(input->variable->compute_equal(m)); } else if (which[i] == VARIABLE && kind == PERATOM) { if (atom->nlocal > maxatom) { memory->sfree(vector); maxatom = atom->nmax; vector = (double *) memory->smalloc(maxatom*sizeof(double), "ave/histo:vector"); } input->variable->compute_atom(m,igroup,vector,1,0); bin_atoms(vector,1); } } // done if irepeat < nrepeat // else reset irepeat and nvalid irepeat++; if (irepeat < nrepeat) { nvalid += nevery; modify->addstep_compute(nvalid); return; } irepeat = 0; nvalid = ntimestep + nfreq - (nrepeat-1)*nevery; modify->addstep_compute(nvalid); // merge histogram stats across procs if necessary if (kind == PERATOM || kind == LOCAL) { MPI_Allreduce(stats,stats_all,2,MPI_DOUBLE,MPI_SUM,world); MPI_Allreduce(&stats[2],&stats_all[2],1,MPI_DOUBLE,MPI_MIN,world); MPI_Allreduce(&stats[3],&stats_all[3],1,MPI_DOUBLE,MPI_MAX,world); MPI_Allreduce(bin,bin_all,nbins,MPI_DOUBLE,MPI_SUM,world); stats[0] = stats_all[0]; stats[1] = stats_all[1]; stats[2] = stats_all[2]; stats[3] = stats_all[3]; for (i = 0; i < nbins; i++) bin[i] = bin_all[i]; } // if ave = ONE, only single Nfreq timestep value is needed // if ave = RUNNING, combine with all previous Nfreq timestep values // if ave = WINDOW, combine with nwindow most recent Nfreq timestep values if (ntimestep >= startstep) { if (ave == ONE) { stats_total[0] = stats[0]; stats_total[1] = stats[1]; stats_total[2] = stats[2]; stats_total[3] = stats[3]; for (i = 0; i < nbins; i++) bin_total[i] = bin[i]; } else if (ave == RUNNING) { stats_total[0] += stats[0]; stats_total[1] += stats[1]; stats_total[2] = MIN(stats_total[2],stats[2]); stats_total[3] = MAX(stats_total[3],stats[3]); for (i = 0; i < nbins; i++) bin_total[i] += bin[i]; } else if (ave == WINDOW) { stats_total[0] += stats[0]; if (window_limit) stats_total[0] -= stats_list[iwindow][0]; stats_list[iwindow][0] = stats[0]; stats_total[1] += stats[1]; if (window_limit) stats_total[1] -= stats_list[iwindow][1]; stats_list[iwindow][1] = stats[1]; if (window_limit) m = nwindow; else m = iwindow+1; stats_list[iwindow][2] = stats[2]; stats_total[2] = stats_list[0][2]; for (i = 1; i < m; i++) stats_total[2] = MIN(stats_total[2],stats_list[i][2]); stats_list[iwindow][3] = stats[3]; stats_total[3] = stats_list[0][3]; for (i = 1; i < m; i++) stats_total[3] = MAX(stats_total[3],stats_list[i][3]); for (i = 0; i < nbins; i++) { bin_total[i] += bin[i]; if (window_limit) bin_total[i] -= bin_list[iwindow][i]; bin_list[iwindow][i] = bin[i]; } iwindow++; if (iwindow == nwindow) { iwindow = 0; window_limit = 1; } } } // output result to file if (fp && me == 0) { - fprintf(fp,"%d %d %g %g %g %g\n", - ntimestep,nbins, + char fstr[32]; + sprintf(fstr,"%s %%d %%g %%g %%g %%g\n",BIGINT_FORMAT); + fprintf(fp,fstr,ntimestep,nbins, stats_total[0],stats_total[1],stats_total[2],stats_total[3]); if (stats_total[0] != 0.0) for (i = 0; i < nbins; i++) fprintf(fp,"%d %g %g %g\n", i+1,coord[i],bin_total[i],bin_total[i]/stats_total[0]); else for (i = 0; i < nbins; i++) fprintf(fp,"%d %g %g %g\n",i+1,coord[i],0.0,0.0); fflush(fp); } } /* ---------------------------------------------------------------------- return Ith vector value ------------------------------------------------------------------------- */ double FixAveHisto::compute_vector(int i) { return stats_total[i]; } /* ---------------------------------------------------------------------- return I,J array value ------------------------------------------------------------------------- */ double FixAveHisto::compute_array(int i, int j) { if (j == 0) return coord[j]; else if (j == 1) return bin_total[j]; else if (stats_total[0] != 0.0) return bin_total[j]/stats_total[0]; return 0.0; } /* ---------------------------------------------------------------------- bin a single value ------------------------------------------------------------------------- */ void FixAveHisto::bin_one(double value) { stats[2] = MIN(stats[2],value); stats[3] = MAX(stats[3],value); if (value < lo) { if (beyond == IGNORE) { stats[1] += 1.0; return; } else bin[0] += 1.0; } else if (value > hi) { if (beyond == IGNORE) { stats[1] += 1.0; return; } else bin[nbins-1] += 1.0; } else { int ibin = static_cast<int> ((value-lo)*bininv); ibin = MIN(ibin,nbins-1); if (beyond == EXTRA) ibin++; bin[ibin] += 1.0; } stats[0] += 1.0; } /* ---------------------------------------------------------------------- bin a vector of values with stride ------------------------------------------------------------------------- */ void FixAveHisto::bin_vector(int n, double *values, int stride) { int m = 0; for (int i = 0; i < n; i++) { bin_one(values[m]); m += stride; } } /* ---------------------------------------------------------------------- bin a per-atom vector of values with stride only bin if atom is in group ------------------------------------------------------------------------- */ void FixAveHisto::bin_atoms(double *values, int stride) { int *mask = atom->mask; int nlocal = atom->nlocal; int m = 0; for (int i = 0; i < nlocal; i++) { if (mask[i] & groupbit) bin_one(values[m]); m += stride; } } /* ---------------------------------------------------------------------- parse optional args ------------------------------------------------------------------------- */ void FixAveHisto::options(int narg, char **arg) { // option defaults fp = NULL; ave = ONE; startstep = 0; mode = SCALAR; beyond = IGNORE; title1 = NULL; title2 = NULL; title3 = NULL; // optional args int iarg = 9 + nvalues; while (iarg < narg) { if (strcmp(arg[iarg],"file") == 0) { if (iarg+2 > narg) error->all("Illegal fix ave/histo command"); if (me == 0) { fp = fopen(arg[iarg+1],"w"); if (fp == NULL) { char str[128]; sprintf(str,"Cannot open fix ave/histo file %s",arg[iarg+1]); error->one(str); } } iarg += 2; } else if (strcmp(arg[iarg],"ave") == 0) { if (iarg+2 > narg) error->all("Illegal fix ave/histo command"); if (strcmp(arg[iarg+1],"one") == 0) ave = ONE; else if (strcmp(arg[iarg+1],"running") == 0) ave = RUNNING; else if (strcmp(arg[iarg+1],"window") == 0) ave = WINDOW; else error->all("Illegal fix ave/histo command"); if (ave == WINDOW) { if (iarg+3 > narg) error->all("Illegal fix ave/histo command"); nwindow = atoi(arg[iarg+2]); if (nwindow <= 0) error->all("Illegal fix ave/histo command"); } iarg += 2; if (ave == WINDOW) iarg++; } else if (strcmp(arg[iarg],"start") == 0) { if (iarg+2 > narg) error->all("Illegal fix ave/histo command"); startstep = atoi(arg[iarg+1]); iarg += 2; } else if (strcmp(arg[iarg],"mode") == 0) { if (iarg+2 > narg) error->all("Illegal fix ave/histo command"); if (strcmp(arg[iarg+1],"scalar") == 0) mode = SCALAR; else if (strcmp(arg[iarg+1],"vector") == 0) mode = VECTOR; else error->all("Illegal fix ave/histo command"); iarg += 2; } else if (strcmp(arg[iarg],"beyond") == 0) { if (iarg+2 > narg) error->all("Illegal fix ave/histo command"); if (strcmp(arg[iarg+1],"ignore") == 0) beyond = IGNORE; else if (strcmp(arg[iarg+1],"end") == 0) beyond = END; else if (strcmp(arg[iarg+1],"extra") == 0) beyond = EXTRA; else error->all("Illegal fix ave/histo command"); iarg += 2; } else if (strcmp(arg[iarg],"title1") == 0) { if (iarg+2 > narg) error->all("Illegal fix ave/spatial command"); delete [] title1; int n = strlen(arg[iarg+1]) + 1; title1 = new char[n]; strcpy(title1,arg[iarg+1]); iarg += 2; } else if (strcmp(arg[iarg],"title2") == 0) { if (iarg+2 > narg) error->all("Illegal fix ave/spatial command"); delete [] title2; int n = strlen(arg[iarg+1]) + 1; title2 = new char[n]; strcpy(title2,arg[iarg+1]); iarg += 2; } else if (strcmp(arg[iarg],"title3") == 0) { if (iarg+2 > narg) error->all("Illegal fix ave/spatial command"); delete [] title3; int n = strlen(arg[iarg+1]) + 1; title3 = new char[n]; strcpy(title3,arg[iarg+1]); iarg += 2; } else error->all("Illegal fix ave/histo command"); } } /* ---------------------------------------------------------------------- reallocate vectors for each input value, of length N ------------------------------------------------------------------------- */ void FixAveHisto::allocate_values(int n) { which = (int *) memory->srealloc(which,n*sizeof(int),"ave/time:which"); argindex = (int *) memory->srealloc(argindex,n*sizeof(int), "ave/time:argindex"); value2index = (int *) memory->srealloc(value2index,n*sizeof(int), "ave/time:value2index"); ids = (char **) memory->srealloc(ids,n*sizeof(char *),"ave/time:ids"); } /* ---------------------------------------------------------------------- calculate nvalid = next step on which end_of_step does something can be this timestep if multiple of nfreq and nrepeat = 1 else backup from next multiple of nfreq ------------------------------------------------------------------------- */ -int FixAveHisto::nextvalid() +bigint FixAveHisto::nextvalid() { - int nvalid = (update->ntimestep/nfreq)*nfreq + nfreq; + bigint nvalid = (update->ntimestep/nfreq)*nfreq + nfreq; if (nvalid-nfreq == update->ntimestep && nrepeat == 1) nvalid = update->ntimestep; else nvalid -= (nrepeat-1)*nevery; if (nvalid < update->ntimestep) nvalid += nfreq; return nvalid; } diff --git a/src/fix_ave_histo.h b/src/fix_ave_histo.h index 64903a973..7dc63220b 100644 --- a/src/fix_ave_histo.h +++ b/src/fix_ave_histo.h @@ -1,74 +1,76 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain 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(ave/histo,FixAveHisto) #else #ifndef LMP_FIX_AVE_HISTO_H #define LMP_FIX_AVE_HISTO_H #include "stdio.h" #include "fix.h" +#include "lmptype.h" namespace LAMMPS_NS { class FixAveHisto : public Fix { public: FixAveHisto(class LAMMPS *, int, char **); ~FixAveHisto(); int setmask(); void init(); void setup(int); void end_of_step(); double compute_vector(int); double compute_array(int,int); private: int me,nvalues; - int nrepeat,nfreq,nvalid,irepeat; + int nrepeat,nfreq,irepeat; + bigint nvalid; int *which,*argindex,*value2index; char **ids; FILE *fp; double lo,hi,binsize,bininv; int kind,beyond; double stats[4],stats_total[4],stats_all[4]; double **stats_list; int nbins; double *bin,*bin_total,*bin_all; double **bin_list; double *coord; double *vector; int maxatom; int ave,nwindow,nsum,startstep,mode; char *title1,*title2,*title3; int iwindow,window_limit; void bin_one(double); void bin_vector(int, double *, int); void bin_atoms(double *, int); void options(int, char **); void allocate_values(int); - int nextvalid(); + bigint nextvalid(); }; } #endif #endif diff --git a/src/fix_ave_spatial.cpp b/src/fix_ave_spatial.cpp index 7b562052a..760464223 100644 --- a/src/fix_ave_spatial.cpp +++ b/src/fix_ave_spatial.cpp @@ -1,1296 +1,1299 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- Contributing author: Pieter in 't Veld (SNL) ------------------------------------------------------------------------- */ #include "stdlib.h" #include "string.h" #include "fix_ave_spatial.h" +#include "lmptype.h" #include "atom.h" #include "update.h" #include "force.h" #include "domain.h" #include "region.h" #include "lattice.h" #include "modify.h" #include "compute.h" #include "input.h" #include "variable.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; enum{LOWER,CENTER,UPPER,COORD}; enum{V,F,DENSITY_NUMBER,DENSITY_MASS,COMPUTE,FIX,VARIABLE}; enum{SAMPLE,ALL}; enum{BOX,LATTICE,REDUCED}; enum{ONE,RUNNING,WINDOW}; #define INVOKED_PERATOM 8 #define BIG 1000000000 #define MIN(A,B) ((A) < (B)) ? (A) : (B) #define MAX(A,B) ((A) > (B)) ? (A) : (B) /* ---------------------------------------------------------------------- */ FixAveSpatial::FixAveSpatial(LAMMPS *lmp, int narg, char **arg) : Fix(lmp, narg, arg) { if (narg < 6) error->all("Illegal fix ave/spatial command"); MPI_Comm_rank(world,&me); nevery = atoi(arg[3]); nrepeat = atoi(arg[4]); nfreq = atoi(arg[5]); global_freq = nfreq; no_change_box = 1; time_depend = 1; ndim = 0; int iarg = 6; while (iarg < narg && ndim < 3) { if (iarg+3 > narg) break; if (strcmp(arg[iarg],"x") == 0) dim[ndim] = 0; else if (strcmp(arg[iarg],"y") == 0) dim[ndim] = 1; else if (strcmp(arg[iarg],"z") == 0) dim[ndim] = 2; else break; if (dim[ndim] == 2 && domain->dimension == 2) error->all("Cannot use fix ave/spatial z for 2 dimensional model"); if (strcmp(arg[iarg+1],"lower") == 0) originflag[ndim] = LOWER; if (strcmp(arg[iarg+1],"center") == 0) originflag[ndim] = CENTER; if (strcmp(arg[iarg+1],"upper") == 0) originflag[ndim] = UPPER; else originflag[ndim] = COORD; if (originflag[ndim] == COORD) origin[ndim] = atof(arg[iarg+1]); delta[ndim] = atof(arg[iarg+2]); ndim++; iarg += 3; } if (!ndim) error->all("Illegal fix ave/spatial command"); if (ndim == 2 && dim[0] == dim[1]) error->all("Same dimension twice in fix ave/spatial"); if (ndim == 3 && (dim[0] == dim[1] || dim[1] == dim[2] || dim[0] == dim[2])) error->all("Same dimension twice in fix ave/spatial"); // parse values until one isn't recognized which = new int[narg-9]; argindex = new int[narg-9]; ids = new char*[narg-9]; value2index = new int[narg-9]; nvalues = 0; while (iarg < narg) { ids[nvalues] = NULL; if (strcmp(arg[iarg],"vx") == 0) { which[nvalues] = V; argindex[nvalues++] = 0; } else if (strcmp(arg[iarg],"vy") == 0) { which[nvalues] = V; argindex[nvalues++] = 1; } else if (strcmp(arg[iarg],"vz") == 0) { which[nvalues] = V; argindex[nvalues++] = 2; } else if (strcmp(arg[iarg],"fx") == 0) { which[nvalues] = F; argindex[nvalues++] = 0; } else if (strcmp(arg[iarg],"fy") == 0) { which[nvalues] = F; argindex[nvalues++] = 1; } else if (strcmp(arg[iarg],"fz") == 0) { which[nvalues] = F; argindex[nvalues++] = 2; } else if (strcmp(arg[iarg],"density/number") == 0) { which[nvalues] = DENSITY_NUMBER; argindex[nvalues++] = 0; } else if (strcmp(arg[iarg],"density/mass") == 0) { which[nvalues] = DENSITY_MASS; argindex[nvalues++] = 0; } else if (strncmp(arg[iarg],"c_",2) == 0 || strncmp(arg[iarg],"f_",2) == 0 || strncmp(arg[iarg],"v_",2) == 0) { if (arg[iarg][0] == 'c') which[nvalues] = COMPUTE; else if (arg[iarg][0] == 'f') which[nvalues] = FIX; else if (arg[iarg][0] == 'v') which[nvalues] = VARIABLE; int n = strlen(arg[iarg]); char *suffix = new char[n]; strcpy(suffix,&arg[iarg][2]); char *ptr = strchr(suffix,'['); if (ptr) { if (suffix[strlen(suffix)-1] != ']') error->all("Illegal fix ave/spatial command"); argindex[nvalues] = atoi(ptr+1); *ptr = '\0'; } else argindex[nvalues] = 0; n = strlen(suffix) + 1; ids[nvalues] = new char[n]; strcpy(ids[nvalues],suffix); nvalues++; delete [] suffix; } else break; iarg++; } // optional args normflag = ALL; scaleflag = LATTICE; regionflag = 0; idregion = NULL; fp = NULL; ave = ONE; char *title1 = NULL; char *title2 = NULL; char *title3 = NULL; while (iarg < narg) { if (strcmp(arg[iarg],"norm") == 0) { if (iarg+2 > narg) error->all("Illegal fix ave/spatial command"); if (strcmp(arg[iarg+1],"all") == 0) normflag = ALL; else if (strcmp(arg[iarg+1],"sample") == 0) normflag = SAMPLE; else error->all("Illegal fix ave/spatial command"); iarg += 2; } else if (strcmp(arg[iarg],"units") == 0) { if (iarg+2 > narg) error->all("Illegal fix ave/spatial command"); if (strcmp(arg[iarg+1],"box") == 0) scaleflag = BOX; else if (strcmp(arg[iarg+1],"lattice") == 0) scaleflag = LATTICE; else if (strcmp(arg[iarg+1],"reduced") == 0) scaleflag = REDUCED; else error->all("Illegal fix ave/spatial command"); iarg += 2; } else if (strcmp(arg[iarg],"region") == 0) { if (iarg+2 > narg) error->all("Illegal fix ave/spatial command"); iregion = domain->find_region(arg[iarg+1]); if (iregion == -1) error->all("Region ID for fix ave/spatial does not exist"); int n = strlen(arg[iarg+1]) + 1; idregion = new char[n]; strcpy(idregion,arg[iarg+1]); regionflag = 1; iarg += 2; } else if (strcmp(arg[iarg],"file") == 0) { if (iarg+2 > narg) error->all("Illegal fix ave/spatial command"); if (me == 0) { fp = fopen(arg[iarg+1],"w"); if (fp == NULL) { char str[128]; sprintf(str,"Cannot open fix ave/spatial file %s",arg[iarg+1]); error->one(str); } } iarg += 2; } else if (strcmp(arg[iarg],"ave") == 0) { if (iarg+2 > narg) error->all("Illegal fix ave/spatial command"); if (strcmp(arg[iarg+1],"one") == 0) ave = ONE; else if (strcmp(arg[iarg+1],"running") == 0) ave = RUNNING; else if (strcmp(arg[iarg+1],"window") == 0) ave = WINDOW; else error->all("Illegal fix ave/spatial command"); if (ave == WINDOW) { if (iarg+3 > narg) error->all("Illegal fix ave/spatial command"); nwindow = atoi(arg[iarg+2]); if (nwindow <= 0) error->all("Illegal fix ave/spatial command"); } iarg += 2; if (ave == WINDOW) iarg++; } else if (strcmp(arg[iarg],"title1") == 0) { if (iarg+2 > narg) error->all("Illegal fix ave/spatial command"); delete [] title1; int n = strlen(arg[iarg+1]) + 1; title1 = new char[n]; strcpy(title1,arg[iarg+1]); iarg += 2; } else if (strcmp(arg[iarg],"title2") == 0) { if (iarg+2 > narg) error->all("Illegal fix ave/spatial command"); delete [] title2; int n = strlen(arg[iarg+1]) + 1; title2 = new char[n]; strcpy(title2,arg[iarg+1]); iarg += 2; } else if (strcmp(arg[iarg],"title3") == 0) { if (iarg+2 > narg) error->all("Illegal fix ave/spatial command"); delete [] title3; int n = strlen(arg[iarg+1]) + 1; title3 = new char[n]; strcpy(title3,arg[iarg+1]); iarg += 2; } else error->all("Illegal fix ave/spatial command"); } // setup and error check if (nevery <= 0 || nrepeat <= 0 || nfreq <= 0) error->all("Illegal fix ave/spatial command"); if (nfreq % nevery || (nrepeat-1)*nevery >= nfreq) error->all("Illegal fix ave/spatial command"); if (delta[0] <= 0.0) error->all("Illegal fix ave/spatial command"); if (ndim >= 2 && delta[1] <= 0.0) error->all("Illegal fix ave/spatial command"); if (ndim == 3 && delta[2] <= 0.0) error->all("Illegal fix ave/spatial command"); for (int i = 0; i < nvalues; i++) { if (which[i] == COMPUTE) { int icompute = modify->find_compute(ids[i]); if (icompute < 0) error->all("Compute ID for fix ave/spatial does not exist"); if (modify->compute[icompute]->peratom_flag == 0) error->all("Fix ave/spatial compute does not " "calculate per-atom values"); if (argindex[i] == 0 && modify->compute[icompute]->size_peratom_cols != 0) error->all("Fix ave/spatial compute does not " "calculate a per-atom vector"); if (argindex[i] && modify->compute[icompute]->size_peratom_cols == 0) error->all("Fix ave/spatial compute does not " "calculate a per-atom array"); if (argindex[i] && argindex[i] > modify->compute[icompute]->size_peratom_cols) error->all("Fix ave/spatial compute vector is accessed out-of-range"); } else if (which[i] == FIX) { int ifix = modify->find_fix(ids[i]); if (ifix < 0) error->all("Fix ID for fix ave/spatial does not exist"); if (modify->fix[ifix]->peratom_flag == 0) error->all("Fix ave/spatial fix does not calculate per-atom values"); if (argindex[i] && modify->fix[ifix]->size_peratom_cols != 0) error->all("Fix ave/spatial fix does not calculate a per-atom vector"); if (argindex[i] && modify->fix[ifix]->size_peratom_cols == 0) error->all("Fix ave/spatial fix does not calculate a per-atom array"); if (argindex[i] && argindex[i] > modify->fix[ifix]->size_peratom_cols) error->all("Fix ave/spatial fix vector is accessed out-of-range"); } else if (which[i] == VARIABLE) { int ivariable = input->variable->find(ids[i]); if (ivariable < 0) error->all("Variable name for fix ave/spatial does not exist"); if (input->variable->atomstyle(ivariable) == 0) error->all("Fix ave/spatial variable is not atom-style variable"); } } // print file comment lines if (fp && me == 0) { if (title1) fprintf(fp,"%s\n",title1); else fprintf(fp,"# Spatial-averaged data for fix %s and group %s\n", id,arg[1]); if (title2) fprintf(fp,"%s\n",title2); else fprintf(fp,"# Timestep Number-of-bins\n"); if (title3) fprintf(fp,"%s\n",title3); else { if (ndim == 1) fprintf(fp,"# Bin Coord Ncount"); else if (ndim == 2) fprintf(fp,"# Bin Coord1 Coord2 Ncount"); else if (ndim == 3) fprintf(fp,"# Bin Coord1 Coord2 Coord3 Ncount"); for (int i = 0; i < nvalues; i++) fprintf(fp," %s",arg[9+i]); fprintf(fp,"\n"); } } delete [] title1; delete [] title2; delete [] title3; // this fix produces a global array array_flag = 1; size_local_rows = BIG; size_local_cols = 1 + ndim + nvalues; extarray = 0; // setup scaling int triclinic = domain->triclinic; if (triclinic == 1 && scaleflag != REDUCED) error->all("Fix ave/spatial for triclinic boxes requires units reduced"); if (scaleflag == LATTICE && domain->lattice == NULL) error->all("Use of fix ave/spatial with undefined lattice"); if (scaleflag == LATTICE) { xscale = domain->lattice->xlattice; yscale = domain->lattice->ylattice; zscale = domain->lattice->zlattice; } else xscale = yscale = zscale = 1.0; // apply scaling factors double scale; for (int idim = 0; idim < ndim; idim++) { if (dim[idim] == 0) scale = xscale; else if (dim[idim] == 1) scale = yscale; else if (dim[idim] == 2) scale = zscale; delta[idim] *= scale; if (originflag[idim] == COORD) origin[idim] *= scale; invdelta[idim] = 1.0/delta[idim]; } // initializations irepeat = 0; iwindow = window_limit = 0; norm = 0; maxvar = 0; varatom = NULL; maxatom = 0; bin = NULL; nbins = maxbin = 0; count_one = count_many = count_sum = count_total = NULL; coord = NULL; count_list = NULL; values_one = values_many = values_sum = values_total = NULL; values_list = NULL; // nvalid = next step on which end_of_step does something // add nvalid to all computes that store invocation times // since don't know a priori which are invoked by this fix // once in end_of_step() can set timestep for ones actually invoked nvalid = nextvalid(); modify->addstep_compute_all(nvalid); } /* ---------------------------------------------------------------------- */ FixAveSpatial::~FixAveSpatial() { delete [] which; delete [] argindex; for (int i = 0; i < nvalues; i++) delete [] ids[i]; delete [] ids; delete [] value2index; delete [] idregion; if (fp && me == 0) fclose(fp); memory->sfree(varatom); memory->sfree(bin); memory->sfree(count_one); memory->sfree(count_many); memory->sfree(count_sum); memory->sfree(count_total); memory->destroy_2d_double_array(coord); memory->destroy_2d_double_array(count_list); memory->destroy_2d_double_array(values_one); memory->destroy_2d_double_array(values_many); memory->destroy_2d_double_array(values_sum); memory->destroy_2d_double_array(values_total); memory->destroy_3d_double_array(values_list); } /* ---------------------------------------------------------------------- */ int FixAveSpatial::setmask() { int mask = 0; mask |= END_OF_STEP; return mask; } /* ---------------------------------------------------------------------- */ void FixAveSpatial::init() { // set and check validity of region if (regionflag) { iregion = domain->find_region(idregion); if (iregion == -1) error->all("Region ID for fix ave/spatial does not exist"); region = domain->regions[iregion]; } // # of bins cannot vary for ave = RUNNING or WINDOW if (ave == RUNNING || ave == WINDOW) { if (scaleflag != REDUCED && domain->box_change) error->all("Fix ave/spatial settings invalid with changing box"); } // set indices and check validity of all computes,fixes,variables // check that fix frequency is acceptable for (int m = 0; m < nvalues; m++) { if (which[m] == COMPUTE) { int icompute = modify->find_compute(ids[m]); if (icompute < 0) error->all("Compute ID for fix ave/spatial does not exist"); value2index[m] = icompute; } else if (which[m] == FIX) { int ifix = modify->find_fix(ids[m]); if (ifix < 0) error->all("Fix ID for fix ave/spatial does not exist"); value2index[m] = ifix; if (nevery % modify->fix[ifix]->peratom_freq) error->all("Fix for fix ave/spatial not computed at compatible time"); } else if (which[m] == VARIABLE) { int ivariable = input->variable->find(ids[m]); if (ivariable < 0) error->all("Variable name for fix ave/spatial does not exist"); value2index[m] = ivariable; } else value2index[m] = -1; } // need to reset nvalid if nvalid < ntimestep b/c minimize was performed if (nvalid < update->ntimestep) { irepeat = 0; nvalid = nextvalid(); modify->addstep_compute_all(nvalid); } } /* ---------------------------------------------------------------------- setup initial bins only does averaging if nvalid = current timestep ------------------------------------------------------------------------- */ void FixAveSpatial::setup(int vflag) { setup_bins(); end_of_step(); } /* ---------------------------------------------------------------------- */ void FixAveSpatial::end_of_step() { int i,j,m,n; // skip if not step which requires doing something - int ntimestep = update->ntimestep; + bigint ntimestep = update->ntimestep; if (ntimestep != nvalid) return; // zero out arrays that accumulate over many samples // if box changes, first re-setup bins if (irepeat == 0) { if (domain->box_change) setup_bins(); for (m = 0; m < nbins; m++) { count_many[m] = count_sum[m] = 0.0; for (i = 0; i < nvalues; i++) values_many[m][i] = 0.0; } } // zero out arrays for one sample for (m = 0; m < nbins; m++) { count_one[m] = 0.0; for (i = 0; i < nvalues; i++) values_one[m][i] = 0.0; } // assign each atom to a bin double **x = atom->x; int *mask = atom->mask; int nlocal = atom->nlocal; if (nlocal > maxatom) { maxatom = atom->nmax; memory->sfree(bin); bin = (int *) memory->smalloc(maxatom*sizeof(int),"ave/spatial:bin"); } if (ndim == 1) atom2bin1d(); else if (ndim == 2) atom2bin2d(); else atom2bin3d(); // perform the computation for one sample // accumulate results of attributes,computes,fixes,variables to local copy // sum within each bin, only include atoms in fix group // compute/fix/variable may invoke computes so wrap with clear/add modify->clearstep_compute(); for (m = 0; m < nvalues; m++) { n = value2index[m]; j = argindex[m]; // V,F adds velocities,forces to values if (which[m] == V || which[m] == F) { double **attribute; if (which[m] == V) attribute = atom->v; else attribute = atom->f; if (regionflag == 0) { for (i = 0; i < nlocal; i++) if (mask[i] & groupbit) values_one[bin[i]][m] += attribute[i][j]; } else { for (i = 0; i < nlocal; i++) if (mask[i] & groupbit && region->match(x[i][0],x[i][1],x[i][2])) values_one[bin[i]][m] += attribute[i][j]; } // DENSITY_NUMBER adds 1 to values } else if (which[m] == DENSITY_NUMBER) { if (regionflag == 0) { for (i = 0; i < nlocal; i++) if (mask[i] & groupbit) values_one[bin[i]][m] += 1.0; } else { for (i = 0; i < nlocal; i++) if (mask[i] & groupbit && region->match(x[i][0],x[i][1],x[i][2])) values_one[bin[i]][m] += 1.0; } // DENSITY_MASS adds mass to values } else if (which[m] == DENSITY_MASS) { int *type = atom->type; double *mass = atom->mass; double *rmass = atom->rmass; if (regionflag == 0) { for (i = 0; i < nlocal; i++) if (mask[i] & groupbit) { if (rmass) values_one[bin[i]][m] += rmass[i]; else values_one[bin[i]][m] += mass[type[i]]; } } else { for (i = 0; i < nlocal; i++) if (mask[i] & groupbit && region->match(x[i][0],x[i][1],x[i][2])) { if (rmass) values_one[bin[i]][m] += rmass[i]; else values_one[bin[i]][m] += mass[type[i]]; } } // COMPUTE adds its scalar or vector component to values // invoke compute if not previously invoked } else if (which[m] == COMPUTE) { Compute *compute = modify->compute[n]; if (!(compute->invoked_flag & INVOKED_PERATOM)) { compute->compute_peratom(); compute->invoked_flag |= INVOKED_PERATOM; } double *vector = compute->vector_atom; double **array = compute->array_atom; int jm1 = j - 1; if (regionflag == 0) { for (i = 0; i < nlocal; i++) if (mask[i] & groupbit) { if (j == 0) values_one[bin[i]][m] += vector[i]; else values_one[bin[i]][m] += array[i][jm1]; } } else { for (i = 0; i < nlocal; i++) if (mask[i] & groupbit && region->match(x[i][0],x[i][1],x[i][2])) { if (j == 0) values_one[bin[i]][m] += vector[i]; else values_one[bin[i]][m] += array[i][jm1]; } } // FIX adds its scalar or vector component to values // access fix fields, guaranteed to be ready } else if (which[m] == FIX) { double *vector = modify->fix[n]->vector_atom; double **array = modify->fix[n]->array_atom; int jm1 = j - 1; if (regionflag == 0) { for (i = 0; i < nlocal; i++) if (mask[i] & groupbit) { if (j == 0) values_one[bin[i]][m] += vector[i]; else values_one[bin[i]][m] += array[i][jm1]; } } else { for (i = 0; i < nlocal; i++) if (mask[i] & groupbit && region->match(x[i][0],x[i][1],x[i][2])) { if (j == 0) values_one[bin[i]][m] += vector[i]; else values_one[bin[i]][m] += array[i][jm1]; } } // VARIABLE adds its per-atom quantities to values // evaluate atom-style variable } else if (which[m] == VARIABLE) { if (nlocal > maxvar) { maxvar = atom->nmax; memory->sfree(varatom); varatom = (double *) memory->smalloc(maxvar*sizeof(double),"ave/spatial:varatom"); } input->variable->compute_atom(n,igroup,varatom,1,0); if (regionflag == 0) { for (i = 0; i < nlocal; i++) if (mask[i] & groupbit) values_one[bin[i]][m] += varatom[i]; } else { for (i = 0; i < nlocal; i++) if (mask[i] & groupbit && region->match(x[i][0],x[i][1],x[i][2])) values_one[bin[i]][m] += varatom[i]; } } } // process a single sample // if normflag = ALL, accumulate values,count separately to many // if normflag = SAMPLE, one = value/count, accumulate one to many // exception is SAMPLE density: no normalization by atom count if (normflag == ALL) { for (m = 0; m < nbins; m++) { count_many[m] += count_one[m]; for (j = 0; j < nvalues; j++) values_many[m][j] += values_one[m][j]; } } else { MPI_Allreduce(count_one,count_many,nbins,MPI_DOUBLE,MPI_SUM,world); for (m = 0; m < nbins; m++) { if (count_many[m] > 0.0) for (j = 0; j < nvalues; j++) { if (which[j] == DENSITY_NUMBER || which[j] == DENSITY_MASS) values_many[m][j] += values_one[m][j]; else values_many[m][j] += values_one[m][j]/count_many[m]; } count_sum[m] += count_many[m]; } } // done if irepeat < nrepeat // else reset irepeat and nvalid irepeat++; if (irepeat < nrepeat) { nvalid += nevery; modify->addstep_compute(nvalid); return; } irepeat = 0; nvalid = ntimestep+nfreq - (nrepeat-1)*nevery; modify->addstep_compute(nvalid); // time average across samples // if normflag = ALL, final is total value / total count // if normflag = SAMPLE, final is sum of ave / repeat // exception is densities: normalized by repeat, not total count double repeat = nrepeat; double mv2d = force->mv2d; if (normflag == ALL) { MPI_Allreduce(count_many,count_sum,nbins,MPI_DOUBLE,MPI_SUM,world); MPI_Allreduce(&values_many[0][0],&values_sum[0][0],nbins*nvalues, MPI_DOUBLE,MPI_SUM,world); for (m = 0; m < nbins; m++) { if (count_sum[m] > 0.0) for (j = 0; j < nvalues; j++) if (which[j] == DENSITY_NUMBER) values_sum[m][j] /= repeat; else if (which[j] == DENSITY_MASS) values_sum[m][j] *= mv2d/repeat; else values_sum[m][j] /= count_sum[m]; count_sum[m] /= repeat; } } else { MPI_Allreduce(&values_many[0][0],&values_sum[0][0],nbins*nvalues, MPI_DOUBLE,MPI_SUM,world); for (m = 0; m < nbins; m++) { for (j = 0; j < nvalues; j++) values_sum[m][j] /= repeat; count_sum[m] /= repeat; } } // density is additionally normalized by bin volume for (j = 0; j < nvalues; j++) if (which[j] == DENSITY_NUMBER || which[j] == DENSITY_MASS) for (m = 0; m < nbins; m++) values_sum[m][j] /= bin_volume; // if ave = ONE, only single Nfreq timestep value is needed // if ave = RUNNING, combine with all previous Nfreq timestep values // if ave = WINDOW, comine with nwindow most recent Nfreq timestep values if (ave == ONE) { for (m = 0; m < nbins; m++) { for (i = 0; i < nvalues; i++) values_total[m][i] = values_sum[m][i]; count_total[m] = count_sum[m]; } norm = 1; } else if (ave == RUNNING) { for (m = 0; m < nbins; m++) { for (i = 0; i < nvalues; i++) values_total[m][i] += values_sum[m][i]; count_total[m] += count_sum[m]; } norm++; } else if (ave == WINDOW) { for (m = 0; m < nbins; m++) { for (i = 0; i < nvalues; i++) { values_total[m][i] += values_sum[m][i]; if (window_limit) values_total[m][i] -= values_list[iwindow][m][i]; values_list[iwindow][m][i] = values_sum[m][i]; } count_total[m] += count_sum[m]; if (window_limit) count_total[m] -= count_list[iwindow][m]; count_list[iwindow][m] = count_sum[m]; } iwindow++; if (iwindow == nwindow) { iwindow = 0; window_limit = 1; } if (window_limit) norm = nwindow; else norm = iwindow; } // output result to file if (fp && me == 0) { - fprintf(fp,"%d %d\n",ntimestep,nbins); + char fstr[16]; + sprintf(fstr,"%s %%d\n",BIGINT_FORMAT); + fprintf(fp,fstr,ntimestep,nbins); if (ndim == 1) for (m = 0; m < nbins; m++) { fprintf(fp," %d %g %g",m+1,coord[m][0], count_total[m]/norm); for (i = 0; i < nvalues; i++) fprintf(fp," %g",values_total[m][i]/norm); fprintf(fp,"\n"); } else if (ndim == 2) for (m = 0; m < nbins; m++) { fprintf(fp," %d %g %g %g",m+1,coord[m][0],coord[m][1], count_total[m]/norm); for (i = 0; i < nvalues; i++) fprintf(fp," %g",values_total[m][i]/norm); fprintf(fp,"\n"); } else for (m = 0; m < nbins; m++) { fprintf(fp," %d %g %g %g %g",m+1,coord[m][0],coord[m][1],coord[m][2], count_total[m]/norm); for (i = 0; i < nvalues; i++) fprintf(fp," %g",values_total[m][i]/norm); fprintf(fp,"\n"); } fflush(fp); } } /* ---------------------------------------------------------------------- setup 1d, 2d, or 3d bins and their extent and coordinates called at setup() and when averaging occurs if box size changes ------------------------------------------------------------------------- */ void FixAveSpatial::setup_bins() { int i,j,k,m,n; double lo,hi,coord1,coord2; // lo = bin boundary immediately below boxlo // hi = bin boundary immediately above boxhi // allocate and initialize arrays based on new bin count double *boxlo,*boxhi,*prd; if (scaleflag == REDUCED) { boxlo = domain->boxlo_lamda; boxhi = domain->boxhi_lamda; prd = domain->prd_lamda; } else { boxlo = domain->boxlo; boxhi = domain->boxhi; prd = domain->prd; } if (domain->dimension == 3) bin_volume = domain->xprd * domain->yprd * domain->zprd; else bin_volume = domain->xprd * domain->yprd; nbins = 1; for (m = 0; m < ndim; m++) { if (originflag[m] == LOWER) origin[m] = boxlo[dim[m]]; else if (originflag[m] == UPPER) origin[m] = boxhi[dim[m]]; else if (originflag[m] == CENTER) origin[m] = 0.5 * (boxlo[dim[m]] + boxhi[dim[m]]); if (origin[m] < boxlo[dim[m]]) { n = static_cast<int> ((boxlo[dim[m]] - origin[m]) * invdelta[m]); lo = origin[m] + n*delta[m]; } else { n = static_cast<int> ((origin[m] - boxlo[dim[m]]) * invdelta[m]); lo = origin[m] - n*delta[m]; if (lo > boxlo[dim[m]]) lo -= delta[m]; } if (origin[m] < boxhi[dim[m]]) { n = static_cast<int> ((boxhi[dim[m]] - origin[m]) * invdelta[m]); hi = origin[m] + n*delta[m]; if (hi < boxhi[dim[m]]) hi += delta[m]; } else { n = static_cast<int> ((origin[m] - boxhi[dim[m]]) * invdelta[m]); hi = origin[m] - n*delta[m]; } offset[m] = lo; nlayers[m] = static_cast<int> ((hi-lo) * invdelta[m] + 0.5); nbins *= nlayers[m]; bin_volume *= delta[m]/prd[dim[m]]; } // reallocate bin arrays if needed if (nbins > maxbin) { maxbin = nbins; count_one = (double *) memory->srealloc(count_one,nbins*sizeof(double), "ave/spatial:count_one"); count_many = (double *) memory->srealloc(count_many,nbins*sizeof(double), "ave/spatial:count_many"); count_sum = (double *) memory->srealloc(count_sum,nbins*sizeof(double), "ave/spatial:count_sum"); count_total = (double *) memory->srealloc(count_total,nbins*sizeof(double), "ave/spatial:count_total"); coord = memory->grow_2d_double_array(coord,nbins,ndim,"ave/spatial:coord"); values_one = memory->grow_2d_double_array(values_one,nbins,nvalues, "ave/spatial:values_one"); values_many = memory->grow_2d_double_array(values_many,nbins,nvalues, "ave/spatial:values_many"); values_sum = memory->grow_2d_double_array(values_sum,nbins,nvalues, "ave/spatial:values_sum"); values_total = memory->grow_2d_double_array(values_total,nbins,nvalues, "ave/spatial:values_total"); // only allocate count and values list for ave = WINDOW if (ave == WINDOW) { count_list = memory->create_2d_double_array(nwindow,nbins, "ave/spatial:count_list"); values_list = memory->create_3d_double_array(nwindow,nbins,nvalues, "ave/spatial:values_list"); } // reinitialize regrown count/values total since they accumulate for (m = 0; m < nbins; m++) { for (i = 0; i < nvalues; i++) values_total[m][i] = 0.0; count_total[m] = 0.0; } } // set bin coordinates if (ndim == 1) { for (i = 0; i < nlayers[0]; i++) coord[i][0] = offset[0] + (i+0.5)*delta[0]; } else if (ndim == 2) { m = 0; for (i = 0; i < nlayers[0]; i++) { coord1 = offset[0] + (i+0.5)*delta[0]; for (j = 0; j < nlayers[1]; j++) { coord[m][0] = coord1; coord[m][1] = offset[1] + (j+0.5)*delta[1]; m++; } } } else if (ndim == 3) { m = 0; for (i = 0; i < nlayers[0]; i++) { coord1 = offset[0] + (i+0.5)*delta[0]; for (j = 0; j < nlayers[1]; j++) { coord2 = offset[1] + (j+0.5)*delta[1]; for (k = 0; k < nlayers[2]; k++) { coord[m][0] = coord1; coord[m][1] = coord2; coord[m][2] = offset[2] + (k+0.5)*delta[2]; m++; } } } } } /* ---------------------------------------------------------------------- assign each atom to a 1d bin ------------------------------------------------------------------------- */ void FixAveSpatial::atom2bin1d() { int i,ibin; double *boxlo,*boxhi,*prd; double xremap; double lamda[3]; double **x = atom->x; int *mask = atom->mask; int nlocal = atom->nlocal; int idim = dim[0]; int nlayerm1 = nlayers[0] - 1; int periodicity = domain->periodicity[idim]; if (periodicity) { if (scaleflag == REDUCED) { boxlo = domain->boxlo_lamda; boxhi = domain->boxhi_lamda; prd = domain->prd_lamda; } else { boxlo = domain->boxlo; boxhi = domain->boxhi; prd = domain->prd; } } // remap each atom's relevant coord back into box via PBC if necessary // if scaleflag = REDUCED, box coords -> lamda coords if (regionflag == 0) { if (scaleflag == REDUCED) domain->x2lamda(nlocal); for (i = 0; i < nlocal; i++) if (mask[i] & groupbit) { xremap = x[i][idim]; if (periodicity) { if (xremap < boxlo[idim]) xremap += prd[idim]; if (xremap >= boxhi[idim]) xremap -= prd[idim]; } ibin = static_cast<int> ((xremap - offset[0]) * invdelta[0]); ibin = MAX(ibin,0); ibin = MIN(ibin,nlayerm1); bin[i] = ibin; count_one[ibin] += 1.0; } if (scaleflag == REDUCED) domain->lamda2x(nlocal); } else { for (i = 0; i < nlocal; i++) if (mask[i] & groupbit && region->match(x[i][0],x[i][1],x[i][2])) { if (scaleflag == REDUCED) { domain->x2lamda(x[i],lamda); xremap = lamda[idim]; } else xremap = x[i][idim]; if (periodicity) { if (xremap < boxlo[idim]) xremap += prd[idim]; if (xremap >= boxhi[idim]) xremap -= prd[idim]; } ibin = static_cast<int> ((xremap - offset[0]) * invdelta[0]); ibin = MAX(ibin,0); ibin = MIN(ibin,nlayerm1); bin[i] = ibin; count_one[ibin] += 1.0; } } } /* ---------------------------------------------------------------------- assign each atom to a 2d bin ------------------------------------------------------------------------- */ void FixAveSpatial::atom2bin2d() { int i,ibin,i1bin,i2bin; double *boxlo,*boxhi,*prd; double xremap,yremap; double lamda[3]; double **x = atom->x; int *mask = atom->mask; int nlocal = atom->nlocal; int idim = dim[0]; int jdim = dim[1]; int nlayer1m1 = nlayers[0] - 1; int nlayer2m1 = nlayers[1] - 1; int* periodicity = domain->periodicity; if (periodicity[idim] || periodicity[jdim]) { if (scaleflag == REDUCED) { boxlo = domain->boxlo_lamda; boxhi = domain->boxhi_lamda; prd = domain->prd_lamda; } else { boxlo = domain->boxlo; boxhi = domain->boxhi; prd = domain->prd; } } // remap each atom's relevant coord back into box via PBC if necessary // if scaleflag = REDUCED, box coords -> lamda coords if (regionflag == 0) { if (scaleflag == REDUCED) domain->x2lamda(nlocal); for (i = 0; i < nlocal; i++) if (mask[i] & groupbit) { xremap = x[i][idim]; if (periodicity[idim]) { if (xremap < boxlo[idim]) xremap += prd[idim]; if (xremap >= boxhi[idim]) xremap -= prd[idim]; } i1bin = static_cast<int> ((xremap - offset[0]) * invdelta[0]); i1bin = MAX(i1bin,0); i1bin = MIN(i1bin,nlayer1m1); yremap = x[i][jdim]; if (periodicity[jdim]) { if (yremap < boxlo[jdim]) yremap += prd[jdim]; if (yremap >= boxhi[jdim]) yremap -= prd[jdim]; } i2bin = static_cast<int> ((yremap - offset[1]) * invdelta[1]); i2bin = MAX(i2bin,0); i2bin = MIN(i2bin,nlayer2m1); ibin = i1bin*nlayers[1] + i2bin; bin[i] = ibin; count_one[ibin] += 1.0; } if (scaleflag == REDUCED) domain->lamda2x(nlocal); } else { for (i = 0; i < nlocal; i++) if (mask[i] & groupbit && region->match(x[i][0],x[i][1],x[i][2])) { if (scaleflag == REDUCED) { domain->x2lamda(x[i],lamda); xremap = lamda[idim]; yremap = lamda[jdim]; } else { xremap = x[i][idim]; yremap = x[i][jdim]; } if (periodicity[idim]) { if (xremap < boxlo[idim]) xremap += prd[idim]; if (xremap >= boxhi[idim]) xremap -= prd[idim]; } i1bin = static_cast<int> ((xremap - offset[0]) * invdelta[0]); i1bin = MAX(i1bin,0); i1bin = MIN(i1bin,nlayer1m1-1); if (periodicity[jdim]) { if (yremap < boxlo[jdim]) yremap += prd[jdim]; if (yremap >= boxhi[jdim]) yremap -= prd[jdim]; } i2bin = static_cast<int> ((yremap - offset[1]) * invdelta[1]); i2bin = MAX(i2bin,0); i2bin = MIN(i2bin,nlayer2m1-1); ibin = i1bin*nlayers[1] + i2bin; bin[i] = ibin; count_one[ibin] += 1.0; } } } /* ---------------------------------------------------------------------- assign each atom to a 3d bin ------------------------------------------------------------------------- */ void FixAveSpatial::atom2bin3d() { int i,ibin,i1bin,i2bin,i3bin; double *boxlo,*boxhi,*prd; double xremap,yremap,zremap; double lamda[3]; double **x = atom->x; int *mask = atom->mask; int nlocal = atom->nlocal; int idim = dim[0]; int jdim = dim[1]; int kdim = dim[2]; int nlayer1m1 = nlayers[0] - 1; int nlayer2m1 = nlayers[1] - 1; int nlayer3m1 = nlayers[2] - 1; int* periodicity = domain->periodicity; if (periodicity[idim] || periodicity[jdim] || periodicity[kdim]) { if (scaleflag == REDUCED) { boxlo = domain->boxlo_lamda; boxhi = domain->boxhi_lamda; prd = domain->prd_lamda; } else { boxlo = domain->boxlo; boxhi = domain->boxhi; prd = domain->prd; } } // remap each atom's relevant coord back into box via PBC if necessary // if scaleflag = REDUCED, box coords -> lamda coords if (regionflag == 0) { if (scaleflag == REDUCED) domain->x2lamda(nlocal); for (i = 0; i < nlocal; i++) if (mask[i] & groupbit) { xremap = x[i][idim]; if (periodicity[idim]) { if (xremap < boxlo[idim]) xremap += prd[idim]; if (xremap >= boxhi[idim]) xremap -= prd[idim]; } i1bin = static_cast<int> ((xremap - offset[0]) * invdelta[0]); i1bin = MAX(i1bin,0); i1bin = MIN(i1bin,nlayer1m1); yremap = x[i][jdim]; if (periodicity[jdim]) { if (yremap < boxlo[jdim]) yremap += prd[jdim]; if (yremap >= boxhi[jdim]) yremap -= prd[jdim]; } i2bin = static_cast<int> ((yremap - offset[1]) * invdelta[1]); i2bin = MAX(i2bin,0); i2bin = MIN(i2bin,nlayer2m1); zremap = x[i][kdim]; if (periodicity[kdim]) { if (zremap < boxlo[kdim]) yremap += prd[kdim]; if (zremap >= boxhi[kdim]) yremap -= prd[kdim]; } i3bin = static_cast<int> ((zremap - offset[2]) * invdelta[2]); i3bin = MAX(i3bin,0); i3bin = MIN(i3bin,nlayer3m1); ibin = i1bin*nlayers[1]*nlayers[2] + i2bin*nlayers[2] + i3bin; bin[i] = ibin; count_one[ibin] += 1.0; } if (scaleflag == REDUCED) domain->lamda2x(nlocal); } else { for (i = 0; i < nlocal; i++) if (mask[i] & groupbit && region->match(x[i][0],x[i][1],x[i][2])) { if (scaleflag == REDUCED) { domain->x2lamda(x[i],lamda); xremap = lamda[idim]; yremap = lamda[jdim]; zremap = lamda[kdim]; } else { xremap = x[i][idim]; yremap = x[i][jdim]; zremap = x[i][kdim]; } if (periodicity[idim]) { if (xremap < boxlo[idim]) xremap += prd[idim]; if (xremap >= boxhi[idim]) xremap -= prd[idim]; } i1bin = static_cast<int> ((xremap - offset[0]) * invdelta[0]); i1bin = MAX(i1bin,0); i1bin = MIN(i1bin,nlayer1m1); if (periodicity[jdim]) { if (yremap < boxlo[jdim]) yremap += prd[jdim]; if (yremap >= boxhi[jdim]) yremap -= prd[jdim]; } i2bin = static_cast<int> ((yremap - offset[1]) * invdelta[1]); i2bin = MAX(i2bin,0); i2bin = MIN(i2bin,nlayer2m1); if (periodicity[kdim]) { if (zremap < boxlo[kdim]) yremap += prd[kdim]; if (zremap >= boxhi[kdim]) yremap -= prd[kdim]; } i3bin = static_cast<int> ((zremap - offset[2]) * invdelta[2]); i3bin = MAX(i3bin,0); i3bin = MIN(i3bin,nlayer3m1); ibin = i1bin*nlayers[1]*nlayers[2] + i2bin*nlayers[2] + i3bin; bin[i] = ibin; count_one[ibin] += 1.0; } } } /* ---------------------------------------------------------------------- return I,J array value if I exceeds current bins, return 0.0 instead of generating an error column 1,2,3 = bin coords, next column = count, remaining columns = Nvalues ------------------------------------------------------------------------- */ double FixAveSpatial::compute_array(int i, int j) { if (values_total == NULL) return 0.0; if (i >= nbins) return 0.0; if (j < ndim) return coord[i][j]; j -= ndim+1; if (j < 0) return count_total[i]/norm; return values_total[i][j]/norm; } /* ---------------------------------------------------------------------- calculate nvalid = next step on which end_of_step does something can be this timestep if multiple of nfreq and nrepeat = 1 else backup from next multiple of nfreq ------------------------------------------------------------------------- */ -int FixAveSpatial::nextvalid() +bigint FixAveSpatial::nextvalid() { - int nvalid = (update->ntimestep/nfreq)*nfreq + nfreq; + bigint nvalid = (update->ntimestep/nfreq)*nfreq + nfreq; if (nvalid-nfreq == update->ntimestep && nrepeat == 1) nvalid = update->ntimestep; else nvalid -= (nrepeat-1)*nevery; if (nvalid < update->ntimestep) nvalid += nfreq; return nvalid; } /* ---------------------------------------------------------------------- memory usage of varatom and bins ------------------------------------------------------------------------- */ double FixAveSpatial::memory_usage() { double bytes = maxvar * sizeof(double); // varatom bytes += maxatom * sizeof(int); // bin bytes += 4*nbins * sizeof(double); // count one,many,sum,total bytes += ndim*nbins * sizeof(double); // coord bytes += nvalues*nbins * sizeof(double); // values one,many,sum,total bytes += nwindow*nbins * sizeof(double); // count_list bytes += nwindow*nbins*nvalues * sizeof(double); // values_list return bytes; } diff --git a/src/fix_ave_spatial.h b/src/fix_ave_spatial.h index 66dec3eaa..eefd20347 100644 --- a/src/fix_ave_spatial.h +++ b/src/fix_ave_spatial.h @@ -1,81 +1,83 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain 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(ave/spatial,FixAveSpatial) #else #ifndef LMP_FIX_AVE_SPATIAL_H #define LMP_FIX_AVE_SPATIAL_H #include "stdio.h" #include "fix.h" +#include "lmptype.h" namespace LAMMPS_NS { class FixAveSpatial : public Fix { public: FixAveSpatial(class LAMMPS *, int, char **); ~FixAveSpatial(); int setmask(); void init(); void setup(int); void end_of_step(); double compute_array(int,int); double memory_usage(); private: int me,nvalues; - int nrepeat,nfreq,nvalid,irepeat; + int nrepeat,nfreq,irepeat; + bigint nvalid; int ndim,normflag,regionflag,iregion; char *tstring,*sstring,*idregion; int *which,*argindex,*value2index; char **ids; FILE *fp; class Region *region; int ave,nwindow,scaleflag; int norm,iwindow,window_limit; double xscale,yscale,zscale; double bin_volume; int dim[3],originflag[3],nlayers[3]; double origin[3],delta[3]; double offset[3],invdelta[3]; int maxvar; double *varatom; int maxatom; int *bin; int nbins,maxbin; double **coord; double *count_one,*count_many,*count_sum; double **values_one,**values_many,**values_sum; double *count_total,**count_list; double **values_total,***values_list; void setup_bins(); void atom2bin1d(); void atom2bin2d(); void atom2bin3d(); - int nextvalid(); + bigint nextvalid(); }; } #endif #endif diff --git a/src/fix_ave_time.cpp b/src/fix_ave_time.cpp index 2edc58074..a2138243c 100644 --- a/src/fix_ave_time.cpp +++ b/src/fix_ave_time.cpp @@ -1,932 +1,935 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- Contributing author: Pieter in 't Veld (SNL) ------------------------------------------------------------------------- */ #include "stdlib.h" #include "string.h" #include "fix_ave_time.h" +#include "lmptype.h" #include "update.h" #include "modify.h" #include "compute.h" #include "group.h" #include "input.h" #include "variable.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; enum{COMPUTE,FIX,VARIABLE}; enum{ONE,RUNNING,WINDOW}; enum{SCALAR,VECTOR}; #define INVOKED_SCALAR 1 #define INVOKED_VECTOR 2 #define INVOKED_ARRAY 4 /* ---------------------------------------------------------------------- */ FixAveTime::FixAveTime(LAMMPS *lmp, int narg, char **arg) : Fix(lmp, narg, arg) { if (narg < 7) error->all("Illegal fix ave/time command"); MPI_Comm_rank(world,&me); nevery = atoi(arg[3]); nrepeat = atoi(arg[4]); nfreq = atoi(arg[5]); global_freq = nfreq; time_depend = 1; // scan values to count them // then read options so know mode = SCALAR/VECTOR before re-reading values nvalues = 0; int iarg = 6; while (iarg < narg) { if ((strncmp(arg[iarg],"c_",2) == 0) || (strncmp(arg[iarg],"f_",2) == 0) || (strncmp(arg[iarg],"v_",2) == 0)) { nvalues++; iarg++; } else break; } options(narg,arg); // parse values until one isn't recognized // if mode = VECTOR and value is a global array: // expand it as if columns listed one by one // adjust nvalues accordingly via maxvalues which = argindex = value2index = offcol = NULL; ids = NULL; int maxvalues = nvalues; allocate_values(maxvalues); nvalues = 0; iarg = 6; while (iarg < narg) { if (strncmp(arg[iarg],"c_",2) == 0 || strncmp(arg[iarg],"f_",2) == 0 || strncmp(arg[iarg],"v_",2) == 0) { if (arg[iarg][0] == 'c') which[nvalues] = COMPUTE; else if (arg[iarg][0] == 'f') which[nvalues] = FIX; else if (arg[iarg][0] == 'v') which[nvalues] = VARIABLE; int n = strlen(arg[iarg]); char *suffix = new char[n]; strcpy(suffix,&arg[iarg][2]); char *ptr = strchr(suffix,'['); if (ptr) { if (suffix[strlen(suffix)-1] != ']') error->all("Illegal fix ave/time command"); argindex[nvalues] = atoi(ptr+1); *ptr = '\0'; } else argindex[nvalues] = 0; n = strlen(suffix) + 1; ids[nvalues] = new char[n]; strcpy(ids[nvalues],suffix); delete [] suffix; if (mode == VECTOR && which[nvalues] == COMPUTE && argindex[nvalues] == 0) { int icompute = modify->find_compute(ids[nvalues]); if (icompute < 0) error->all("Compute ID for fix ave/time does not exist"); if (modify->compute[icompute]->array_flag) { int ncols = modify->compute[icompute]->size_array_cols; maxvalues += ncols-1; allocate_values(maxvalues); argindex[nvalues] = 1; for (int icol = 1; icol < ncols; icol++) { which[nvalues+icol] = which[nvalues]; argindex[nvalues+icol] = icol+1; n = strlen(ids[nvalues]) + 1; ids[nvalues+icol] = new char[n]; strcpy(ids[nvalues+icol],ids[nvalues]); } nvalues += ncols-1; } } else if (mode == VECTOR && which[nvalues] == FIX && argindex[nvalues] == 0) { int ifix = modify->find_fix(ids[nvalues]); if (ifix < 0) error->all("Fix ID for fix ave/time does not exist"); if (modify->fix[ifix]->array_flag) { int ncols = modify->fix[ifix]->size_array_cols; maxvalues += ncols-1; allocate_values(maxvalues); argindex[nvalues] = 1; for (int icol = 1; icol < ncols; icol++) { which[nvalues+icol] = which[nvalues]; argindex[nvalues+icol] = icol+1; n = strlen(ids[nvalues]) + 1; ids[nvalues+icol] = new char[n]; strcpy(ids[nvalues+icol],ids[nvalues]); } nvalues += ncols-1; } } nvalues++; iarg++; } else break; } // set off columns now that nvalues is finalized for (int i = 0; i < nvalues; i++) offcol[i] = 0; for (int i = 0; i < noff; i++) { if (offlist[i] < 1 || offlist[i] > nvalues) error->all("Invalid fix ave/time off column"); offcol[offlist[i]-1] = 1; } // setup and error check // for fix inputs, check that fix frequency is acceptable if (nevery <= 0 || nrepeat <= 0 || nfreq <= 0) error->all("Illegal fix ave/time command"); if (nfreq % nevery || (nrepeat-1)*nevery >= nfreq) error->all("Illegal fix ave/time command"); for (int i = 0; i < nvalues; i++) { if (which[i] == COMPUTE && mode == SCALAR) { int icompute = modify->find_compute(ids[i]); if (icompute < 0) error->all("Compute ID for fix ave/time does not exist"); if (argindex[i] == 0 && modify->compute[icompute]->scalar_flag == 0) error->all("Fix ave/time compute does not calculate a scalar"); if (argindex[i] && modify->compute[icompute]->vector_flag == 0) error->all("Fix ave/time compute does not calculate a vector"); if (argindex[i] && argindex[i] > modify->compute[icompute]->size_vector) error->all("Fix ave/time compute vector is accessed out-of-range"); } else if (which[i] == COMPUTE && mode == VECTOR) { int icompute = modify->find_compute(ids[i]); if (icompute < 0) error->all("Compute ID for fix ave/time does not exist"); if (argindex[i] == 0 && modify->compute[icompute]->vector_flag == 0) error->all("Fix ave/time compute does not calculate a vector"); if (argindex[i] && modify->compute[icompute]->array_flag == 0) error->all("Fix ave/time compute does not calculate an array"); if (argindex[i] && argindex[i] > modify->compute[icompute]->size_array_cols) error->all("Fix ave/time compute array is accessed out-of-range"); } else if (which[i] == FIX && mode == SCALAR) { int ifix = modify->find_fix(ids[i]); if (ifix < 0) error->all("Fix ID for fix ave/time does not exist"); if (argindex[i] == 0 && modify->fix[ifix]->scalar_flag == 0) error->all("Fix ave/time fix does not calculate a scalar"); if (argindex[i] && modify->fix[ifix]->vector_flag == 0) error->all("Fix ave/time fix does not calculate a vector"); if (argindex[i] && argindex[i] > modify->fix[ifix]->size_vector) error->all("Fix ave/time fix vector is accessed out-of-range"); if (nevery % modify->fix[ifix]->global_freq) error->all("Fix for fix ave/time not computed at compatible time"); } else if (which[i] == FIX && mode == VECTOR) { int ifix = modify->find_fix(ids[i]); if (ifix < 0) error->all("Fix ID for fix ave/time does not exist"); if (argindex[i] == 0 && modify->fix[ifix]->vector_flag == 0) error->all("Fix ave/time fix does not calculate a vector"); if (argindex[i] && modify->fix[ifix]->array_flag == 0) error->all("Fix ave/time fix does not calculate an array"); if (argindex[i] && argindex[i] > modify->fix[ifix]->size_array_cols) error->all("Fix ave/time fix array is accessed out-of-range"); if (nevery % modify->fix[ifix]->global_freq) error->all("Fix for fix ave/time not computed at compatible time"); } else if (which[i] == VARIABLE) { int ivariable = input->variable->find(ids[i]); if (ivariable < 0) error->all("Variable name for fix ave/time does not exist"); if (input->variable->equalstyle(ivariable) == 0) error->all("Fix ave/time variable is not equal-style variable"); if (mode == VECTOR) error->all("Fix ave/time cannot use variable with vector mode"); } } // if VECTOR mode, check that all columns are same length // nrows = # of rows in output array if (mode == VECTOR) { int length; for (int i = 0; i < nvalues; i++) { if (which[i] == COMPUTE) { int icompute = modify->find_compute(ids[i]); if (argindex[i] == 0) length = modify->compute[icompute]->size_vector; else length = modify->compute[icompute]->size_array_rows; } else if (which[i] == FIX) { int ifix = modify->find_fix(ids[i]); if (argindex[i] == 0) length = modify->fix[ifix]->size_vector; else length = modify->fix[ifix]->size_array_rows; } if (i == 0) nrows = length; else if (length != nrows) error->all("Fix ave/time columns are inconsistent lengths"); } column = new double[nrows]; } else column = NULL; // print file comment lines // for mode = VECTOR, cannot use arg to print // since array args may have been expanded to multiple vectors if (fp && me == 0) { if (title1) fprintf(fp,"%s\n",title1); else fprintf(fp,"# Time-averaged data for fix %s\n",id); if (title2) fprintf(fp,"%s\n",title2); else if (mode == SCALAR) { fprintf(fp,"# TimeStep"); for (int i = 0; i < nvalues; i++) fprintf(fp," %s",arg[6+i]); fprintf(fp,"\n"); } else fprintf(fp,"# TimeStep Number-of-rows\n"); if (title3 && mode == VECTOR) fprintf(fp,"%s\n",title3); else if (mode == VECTOR) { fprintf(fp,"# Row"); for (int i = 0; i < nvalues; i++) { if (which[i] == COMPUTE) fprintf(fp," c_%s",ids[i]); else if (which[i] == FIX) fprintf(fp," f_%s",ids[i]); else if (which[i] == VARIABLE) fprintf(fp," v_%s",ids[i]); if (argindex[i]) fprintf(fp,"[%d]",argindex[i]); } fprintf(fp,"\n"); } } delete [] title1; delete [] title2; delete [] title3; // allocate memory for averaging vector = vector_total = NULL; vector_list = NULL; array = array_total = NULL; array_list = NULL; if (mode == SCALAR) { vector = new double[nvalues]; vector_total = new double[nvalues]; if (ave == WINDOW) vector_list = memory->create_2d_double_array(nwindow,nvalues, "ave/time:vector_list"); } else { array = memory->create_2d_double_array(nrows,nvalues,"ave/time:array"); array_total = memory->create_2d_double_array(nrows,nvalues, "ave/time:array_total"); if (ave == WINDOW) array_list = memory->create_3d_double_array(nwindow,nrows,nvalues, "ave/time:array_list"); } // this fix produces either a global scalar or vector or array // SCALAR mode produces either a scalar or vector // VECTOR mode produces either a vector or array // intensive/extensive flags set by compute,fix,variable that produces value extlist = NULL; if (mode == SCALAR) { if (nvalues == 1) { scalar_flag = 1; if (which[0] == COMPUTE) { Compute *compute = modify->compute[modify->find_compute(ids[0])]; if (argindex[0] == 0) extscalar = compute->extscalar; else if (compute->extvector >= 0) extscalar = compute->extvector; else extscalar = compute->extlist[argindex[0]-1]; } else if (which[0] == FIX) { Fix *fix = modify->fix[modify->find_fix(ids[0])]; if (argindex[0] == 0) extscalar = fix->extscalar; else if (fix->extvector >= 0) extscalar = fix->extvector; else extscalar = fix->extlist[argindex[0]-1]; } else if (which[0] == VARIABLE) extscalar = 0; } else { vector_flag = 1; size_vector = nvalues; extvector = -1; extlist = new int[nvalues]; for (int i = 0; i < nvalues; i++) { if (which[i] == COMPUTE) { Compute *compute = modify->compute[modify->find_compute(ids[i])]; if (argindex[i] == 0) extlist[i] = compute->extscalar; else if (compute->extvector >= 0) extlist[i] = compute->extvector; else extlist[i] = compute->extlist[argindex[i]-1]; } else if (which[i] == FIX) { Fix *fix = modify->fix[modify->find_fix(ids[i])]; if (argindex[i] == 0) extlist[i] = fix->extscalar; else if (fix->extvector >= 0) extlist[i] = fix->extvector; else extlist[i] = fix->extlist[argindex[i]-1]; } else if (which[i] == VARIABLE) extlist[i] = 0; } } } else { if (nvalues == 1) { vector_flag = 1; size_vector = nrows; if (which[0] == COMPUTE) { Compute *compute = modify->compute[modify->find_compute(ids[0])]; if (argindex[0] == 0) { extvector = compute->extvector; if (extvector == -1) { extlist = new int[nrows]; for (int i = 0; i < nrows; i++) extlist[i] = compute->extlist[i]; } } else extvector = compute->extarray; } else if (which[0] == FIX) { Fix *fix = modify->fix[modify->find_fix(ids[0])]; if (argindex[0] == 0) { extvector = fix->extvector; if (extvector == -1) { extlist = new int[nrows]; for (int i = 0; i < nrows; i++) extlist[i] = fix->extlist[i]; } } else extvector = fix->extarray; } } else { array_flag = 1; size_local_rows = nrows; size_local_cols = nvalues; int value; for (int i = 0; i < nvalues; i++) { if (which[i] == COMPUTE) { Compute *compute = modify->compute[modify->find_compute(ids[i])]; if (argindex[i] == 0) value = compute->extvector; else value = compute->extarray; } else if (which[i] == FIX) { Fix *fix = modify->fix[modify->find_fix(ids[i])]; if (argindex[i] == 0) value = fix->extvector; else value = fix->extarray; } if (value == -1) error->all("Fix ave/time cannot set output array " "intensive/extensive from these inputs"); if (i == 0) extarray = value; else if (value != extarray) error->all("Fix ave/time cannot set output array " "intensive/extensive from these inputs"); } } } // initializations // set vector_total/array_total to zero since it accumulates irepeat = 0; iwindow = window_limit = 0; norm = 0; if (mode == SCALAR) for (int i = 0; i < nvalues; i++) vector_total[i] = 0.0; else for (int i = 0; i < nrows; i++) for (int j = 0; j < nvalues; j++) array_total[i][j] = 0.0; // nvalid = next step on which end_of_step does something // add nvalid to all computes that store invocation times // since don't know a priori which are invoked by this fix // once in end_of_step() can set timestep for ones actually invoked nvalid = nextvalid(); modify->addstep_compute_all(nvalid); } /* ---------------------------------------------------------------------- */ FixAveTime::~FixAveTime() { memory->sfree(which); memory->sfree(argindex); memory->sfree(value2index); memory->sfree(offcol); for (int i = 0; i < nvalues; i++) delete [] ids[i]; memory->sfree(ids); delete [] extlist; if (fp && me == 0) fclose(fp); delete [] vector; delete [] vector_total; delete [] column; memory->destroy_2d_double_array(array); memory->destroy_2d_double_array(array_total); memory->destroy_3d_double_array(array_list); } /* ---------------------------------------------------------------------- */ int FixAveTime::setmask() { int mask = 0; mask |= END_OF_STEP; return mask; } /* ---------------------------------------------------------------------- */ void FixAveTime::init() { // set current indices for all computes,fixes,variables for (int i = 0; i < nvalues; i++) { if (which[i] == COMPUTE) { int icompute = modify->find_compute(ids[i]); if (icompute < 0) error->all("Compute ID for fix ave/time does not exist"); value2index[i] = icompute; } else if (which[i] == FIX) { int ifix = modify->find_fix(ids[i]); if (ifix < 0) error->all("Fix ID for fix ave/time does not exist"); value2index[i] = ifix; } else if (which[i] == VARIABLE) { int ivariable = input->variable->find(ids[i]); if (ivariable < 0) error->all("Variable name for fix ave/time does not exist"); value2index[i] = ivariable; } } // need to reset nvalid if nvalid < ntimestep b/c minimize was performed if (nvalid < update->ntimestep) { irepeat = 0; nvalid = nextvalid(); modify->addstep_compute_all(nvalid); } } /* ---------------------------------------------------------------------- only does something if nvalid = current timestep ------------------------------------------------------------------------- */ void FixAveTime::setup(int vflag) { end_of_step(); } /* ---------------------------------------------------------------------- */ void FixAveTime::end_of_step() { // skip if not step which requires doing something - int ntimestep = update->ntimestep; + bigint ntimestep = update->ntimestep; if (ntimestep != nvalid) return; if (mode == SCALAR) invoke_scalar(ntimestep); else invoke_vector(ntimestep); } /* ---------------------------------------------------------------------- */ -void FixAveTime::invoke_scalar(int ntimestep) +void FixAveTime::invoke_scalar(bigint ntimestep) { int i,m; double scalar; // zero if first step if (irepeat == 0) for (i = 0; i < nvalues; i++) vector[i] = 0.0; // accumulate results of computes,fixes,variables to local copy // compute/fix/variable may invoke computes so wrap with clear/add modify->clearstep_compute(); for (i = 0; i < nvalues; i++) { m = value2index[i]; // invoke compute if not previously invoked if (which[i] == COMPUTE) { Compute *compute = modify->compute[m]; if (argindex[i] == 0) { if (!(compute->invoked_flag & INVOKED_SCALAR)) { compute->compute_scalar(); compute->invoked_flag |= INVOKED_SCALAR; } scalar = compute->scalar; } else { if (!(compute->invoked_flag & INVOKED_VECTOR)) { compute->compute_vector(); compute->invoked_flag |= INVOKED_VECTOR; } scalar = compute->vector[argindex[i]-1]; } // access fix fields, guaranteed to be ready } else if (which[i] == FIX) { if (argindex[i] == 0) scalar = modify->fix[m]->compute_scalar(); else scalar = modify->fix[m]->compute_vector(argindex[i]-1); // evaluate equal-style variable } else if (which[i] == VARIABLE) scalar = input->variable->compute_equal(m); // add value to vector or just set directly if offcol is set if (offcol[i]) vector[i] = scalar; else vector[i] += scalar; } // done if irepeat < nrepeat // else reset irepeat and nvalid irepeat++; if (irepeat < nrepeat) { nvalid += nevery; modify->addstep_compute(nvalid); return; } irepeat = 0; nvalid = ntimestep + nfreq - (nrepeat-1)*nevery; modify->addstep_compute(nvalid); // average the final result for the Nfreq timestep double repeat = nrepeat; for (i = 0; i < nvalues; i++) if (offcol[i] == 0) vector[i] /= repeat; // if ave = ONE, only single Nfreq timestep value is needed // if ave = RUNNING, combine with all previous Nfreq timestep values // if ave = WINDOW, combine with nwindow most recent Nfreq timestep values if (ntimestep >= startstep) { if (ave == ONE) { for (i = 0; i < nvalues; i++) vector_total[i] = vector[i]; norm = 1; } else if (ave == RUNNING) { for (i = 0; i < nvalues; i++) vector_total[i] += vector[i]; norm++; } else if (ave == WINDOW) { for (i = 0; i < nvalues; i++) { vector_total[i] += vector[i]; if (window_limit) vector_total[i] -= vector_list[iwindow][i]; vector_list[iwindow][i] = vector[i]; } iwindow++; if (iwindow == nwindow) { iwindow = 0; window_limit = 1; } if (window_limit) norm = nwindow; else norm = iwindow; } } // insure any columns with offcol set are effectively set to last value for (i = 0; i < nvalues; i++) if (offcol[i]) vector_total[i] = norm*vector[i]; // output result to file if (fp && me == 0) { - fprintf(fp,"%d",ntimestep); + fprintf(fp,BIGINT_FORMAT,ntimestep); for (i = 0; i < nvalues; i++) fprintf(fp," %g",vector_total[i]/norm); fprintf(fp,"\n"); fflush(fp); } } /* ---------------------------------------------------------------------- */ -void FixAveTime::invoke_vector(int ntimestep) +void FixAveTime::invoke_vector(bigint ntimestep) { int i,j,m; // zero if first step if (irepeat == 0) for (i = 0; i < nrows; i++) for (j = 0; j < nvalues; j++) array[i][j] = 0.0; // accumulate results of computes,fixes,variables to local copy // compute/fix/variable may invoke computes so wrap with clear/add modify->clearstep_compute(); for (j = 0; j < nvalues; j++) { m = value2index[j]; // invoke compute if not previously invoked if (which[j] == COMPUTE) { Compute *compute = modify->compute[m]; if (argindex[j] == 0) { if (!(compute->invoked_flag & INVOKED_VECTOR)) { compute->compute_vector(); compute->invoked_flag |= INVOKED_VECTOR; } double *cvector = compute->vector; for (i = 0; i < nrows; i++) column[i] = cvector[i]; } else { if (!(compute->invoked_flag & INVOKED_ARRAY)) { compute->compute_array(); compute->invoked_flag |= INVOKED_ARRAY; } double **carray = compute->array; int icol = argindex[j]-1; for (i = 0; i < nrows; i++) column[i] = carray[i][icol]; } // access fix fields, guaranteed to be ready } else if (which[j] == FIX) { Fix *fix = modify->fix[m]; if (argindex[j] == 0) for (i = 0; i < nrows; i++) column[i] = fix->compute_vector(i); else { int icol = argindex[j]-1; for (i = 0; i < nrows; i++) column[i] = fix->compute_array(i,icol); } } // add columns of values to array or just set directly if offcol is set if (offcol[j]) { for (i = 0; i < nrows; i++) array[i][j] = column[i]; } else { for (i = 0; i < nrows; i++) array[i][j] += column[i]; } } // done if irepeat < nrepeat // else reset irepeat and nvalid irepeat++; if (irepeat < nrepeat) { nvalid += nevery; modify->addstep_compute(nvalid); return; } irepeat = 0; nvalid = ntimestep+nfreq - (nrepeat-1)*nevery; modify->addstep_compute(nvalid); // average the final result for the Nfreq timestep double repeat = nrepeat; for (i = 0; i < nrows; i++) for (j = 0; j < nvalues; j++) if (offcol[j] == 0) array[i][j] /= repeat; // if ave = ONE, only single Nfreq timestep value is needed // if ave = RUNNING, combine with all previous Nfreq timestep values // if ave = WINDOW, combine with nwindow most recent Nfreq timestep values if (ntimestep >= startstep) { if (ave == ONE) { for (i = 0; i < nrows; i++) for (j = 0; j < nvalues; j++) array_total[i][j] = array[i][j]; norm = 1; } else if (ave == RUNNING) { for (i = 0; i < nrows; i++) for (j = 0; j < nvalues; j++) array_total[i][j] += array[i][j]; norm++; } else if (ave == WINDOW) { for (i = 0; i < nrows; i++) for (j = 0; j < nvalues; j++) { array_total[i][j] += array[i][j]; if (window_limit) array_total[i][j] -= array_list[iwindow][i][j]; array_list[iwindow][i][j] = array[i][j]; } iwindow++; if (iwindow == nwindow) { iwindow = 0; window_limit = 1; } if (window_limit) norm = nwindow; else norm = iwindow; } } // insure any columns with offcol set are effectively set to last value for (i = 0; i < nrows; i++) for (j = 0; j < nvalues; j++) if (offcol[j]) array_total[i][j] = norm*array[i][j]; // output result to file if (fp && me == 0) { - fprintf(fp,"%d %d\n",ntimestep,nrows); + char fstr[16]; + sprintf(fstr,"%s %%d\n",BIGINT_FORMAT); + fprintf(fp,fstr,ntimestep,nrows); for (i = 0; i < nrows; i++) { fprintf(fp,"%d",i+1); for (j = 0; j < nvalues; j++) fprintf(fp," %g",array_total[i][j]/norm); fprintf(fp,"\n"); } fflush(fp); } } /* ---------------------------------------------------------------------- return scalar value ------------------------------------------------------------------------- */ double FixAveTime::compute_scalar() { if (norm) return vector_total[0]/norm; return 0.0; } /* ---------------------------------------------------------------------- return Ith vector value ------------------------------------------------------------------------- */ double FixAveTime::compute_vector(int i) { if (norm) { if (mode == SCALAR) return vector_total[i]/norm; if (mode == VECTOR) return array_total[i][0]; } return 0.0; } /* ---------------------------------------------------------------------- return I,J array value ------------------------------------------------------------------------- */ double FixAveTime::compute_array(int i, int j) { if (norm) return array_total[i][j]/norm; return 0.0; } /* ---------------------------------------------------------------------- parse optional args ------------------------------------------------------------------------- */ void FixAveTime::options(int narg, char **arg) { // option defaults fp = NULL; ave = ONE; startstep = 0; mode = SCALAR; noff = 0; offlist = NULL; title1 = NULL; title2 = NULL; title3 = NULL; // optional args int iarg = 6 + nvalues; while (iarg < narg) { if (strcmp(arg[iarg],"file") == 0) { if (iarg+2 > narg) error->all("Illegal fix ave/time command"); if (me == 0) { fp = fopen(arg[iarg+1],"w"); if (fp == NULL) { char str[128]; sprintf(str,"Cannot open fix ave/time file %s",arg[iarg+1]); error->one(str); } } iarg += 2; } else if (strcmp(arg[iarg],"ave") == 0) { if (iarg+2 > narg) error->all("Illegal fix ave/time command"); if (strcmp(arg[iarg+1],"one") == 0) ave = ONE; else if (strcmp(arg[iarg+1],"running") == 0) ave = RUNNING; else if (strcmp(arg[iarg+1],"window") == 0) ave = WINDOW; else error->all("Illegal fix ave/time command"); if (ave == WINDOW) { if (iarg+3 > narg) error->all("Illegal fix ave/time command"); nwindow = atoi(arg[iarg+2]); if (nwindow <= 0) error->all("Illegal fix ave/time command"); } iarg += 2; if (ave == WINDOW) iarg++; } else if (strcmp(arg[iarg],"start") == 0) { if (iarg+2 > narg) error->all("Illegal fix ave/time command"); startstep = atoi(arg[iarg+1]); iarg += 2; } else if (strcmp(arg[iarg],"mode") == 0) { if (iarg+2 > narg) error->all("Illegal fix ave/time command"); if (strcmp(arg[iarg+1],"scalar") == 0) mode = SCALAR; else if (strcmp(arg[iarg+1],"vector") == 0) mode = VECTOR; else error->all("Illegal fix ave/time command"); iarg += 2; } else if (strcmp(arg[iarg],"off") == 0) { if (iarg+2 > narg) error->all("Illegal fix ave/time command"); offlist = (int *) memory->srealloc(offlist,(noff+1)*sizeof(int),"ave/time:offlist"); offlist[noff++] = atoi(arg[iarg+1]); iarg += 2; } else if (strcmp(arg[iarg],"title1") == 0) { if (iarg+2 > narg) error->all("Illegal fix ave/spatial command"); delete [] title1; int n = strlen(arg[iarg+1]) + 1; title1 = new char[n]; strcpy(title1,arg[iarg+1]); iarg += 2; } else if (strcmp(arg[iarg],"title2") == 0) { if (iarg+2 > narg) error->all("Illegal fix ave/spatial command"); delete [] title2; int n = strlen(arg[iarg+1]) + 1; title2 = new char[n]; strcpy(title2,arg[iarg+1]); iarg += 2; } else if (strcmp(arg[iarg],"title3") == 0) { if (iarg+2 > narg) error->all("Illegal fix ave/spatial command"); delete [] title3; int n = strlen(arg[iarg+1]) + 1; title3 = new char[n]; strcpy(title3,arg[iarg+1]); iarg += 2; } else error->all("Illegal fix ave/time command"); } } /* ---------------------------------------------------------------------- reallocate vectors for each input value, of length N ------------------------------------------------------------------------- */ void FixAveTime::allocate_values(int n) { which = (int *) memory->srealloc(which,n*sizeof(int),"ave/time:which"); argindex = (int *) memory->srealloc(argindex,n*sizeof(int), "ave/time:argindex"); value2index = (int *) memory->srealloc(value2index,n*sizeof(int), "ave/time:value2index"); offcol = (int *) memory->srealloc(offcol,n*sizeof(int),"ave/time:offcol"); ids = (char **) memory->srealloc(ids,n*sizeof(char *),"ave/time:ids"); } /* ---------------------------------------------------------------------- calculate nvalid = next step on which end_of_step does something can be this timestep if multiple of nfreq and nrepeat = 1 else backup from next multiple of nfreq ------------------------------------------------------------------------- */ -int FixAveTime::nextvalid() +bigint FixAveTime::nextvalid() { - int nvalid = (update->ntimestep/nfreq)*nfreq + nfreq; + bigint nvalid = (update->ntimestep/nfreq)*nfreq + nfreq; if (nvalid-nfreq == update->ntimestep && nrepeat == 1) nvalid = update->ntimestep; else nvalid -= (nrepeat-1)*nevery; if (nvalid < update->ntimestep) nvalid += nfreq; return nvalid; } diff --git a/src/fix_ave_time.h b/src/fix_ave_time.h index 286511ea2..a8c118d39 100644 --- a/src/fix_ave_time.h +++ b/src/fix_ave_time.h @@ -1,72 +1,74 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain 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(ave/time,FixAveTime) #else #ifndef LMP_FIX_AVE_TIME_H #define LMP_FIX_AVE_TIME_H #include "stdio.h" #include "fix.h" +#include "lmptype.h" namespace LAMMPS_NS { class FixAveTime : public Fix { public: FixAveTime(class LAMMPS *, int, char **); ~FixAveTime(); int setmask(); void init(); void setup(int); void end_of_step(); double compute_scalar(); double compute_vector(int); double compute_array(int,int); private: int me,nvalues; - int nrepeat,nfreq,nvalid,irepeat; + int nrepeat,nfreq,irepeat; + bigint nvalid; int *which,*argindex,*value2index,*offcol; char **ids; FILE *fp; int nrows; int ave,nwindow,nsum,startstep,mode; int noff; int *offlist; char *title1,*title2,*title3; int norm,iwindow,window_limit; double *vector; double *vector_total; double **vector_list; double *column; double **array; double **array_total; double ***array_list; - void invoke_scalar(int); - void invoke_vector(int); + void invoke_scalar(bigint); + void invoke_vector(bigint); void options(int, char **); void allocate_values(int); - int nextvalid(); + bigint nextvalid(); }; } #endif #endif diff --git a/src/fix_deposit.cpp b/src/fix_deposit.cpp index 60fc34ed6..357a32594 100644 --- a/src/fix_deposit.cpp +++ b/src/fix_deposit.cpp @@ -1,459 +1,460 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ #include "math.h" #include "stdlib.h" #include "string.h" #include "fix_deposit.h" #include "atom.h" #include "atom_vec.h" #include "force.h" #include "update.h" #include "modify.h" #include "fix.h" #include "comm.h" #include "domain.h" #include "lattice.h" #include "region.h" #include "random_park.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; /* ---------------------------------------------------------------------- */ FixDeposit::FixDeposit(LAMMPS *lmp, int narg, char **arg) : Fix(lmp, narg, arg) { if (narg < 7) error->all("Illegal fix deposit command"); restart_global = 1; time_depend = 1; // required args ninsert = atoi(arg[3]); ntype = atoi(arg[4]); nfreq = atoi(arg[5]); seed = atoi(arg[6]); if (seed <= 0) error->all("Illegal fix deposit command"); // set defaults iregion = -1; idregion = NULL; globalflag = localflag = 0; lo = hi = deltasq = 0.0; nearsq = 0.0; maxattempt = 10; rateflag = 0; vxlo = vxhi = vylo = vyhi = vzlo = vzhi = 0.0; scaleflag = 1; // read options from end of input line options(narg-7,&arg[7]); // error checks on region and its extent being inside simulation box if (iregion == -1) error->all("Must specify a region in fix deposit"); if (domain->regions[iregion]->bboxflag == 0) error->all("Fix deposit region does not support a bounding box"); if (domain->regions[iregion]->dynamic_check()) error->all("Fix deposit region cannot be dynamic"); xlo = domain->regions[iregion]->extent_xlo; xhi = domain->regions[iregion]->extent_xhi; ylo = domain->regions[iregion]->extent_ylo; yhi = domain->regions[iregion]->extent_yhi; zlo = domain->regions[iregion]->extent_zlo; zhi = domain->regions[iregion]->extent_zhi; if (domain->triclinic == 0) { if (xlo < domain->boxlo[0] || xhi > domain->boxhi[0] || ylo < domain->boxlo[1] || yhi > domain->boxhi[1] || zlo < domain->boxlo[2] || zhi > domain->boxhi[2]) error->all("Deposition region extends outside simulation box"); } else { if (xlo < domain->boxlo_bound[0] || xhi > domain->boxhi_bound[0] || ylo < domain->boxlo_bound[1] || yhi > domain->boxhi_bound[1] || zlo < domain->boxlo_bound[2] || zhi > domain->boxhi_bound[2]) error->all("Deposition region extends outside simulation box"); } // setup scaling if (scaleflag && domain->lattice == NULL) error->all("Use of fix deposit with undefined lattice"); double xscale,yscale,zscale; if (scaleflag) { xscale = domain->lattice->xlattice; yscale = domain->lattice->ylattice; zscale = domain->lattice->zlattice; } else xscale = yscale = zscale = 1.0; // apply scaling to all input parameters with dist/vel units if (domain->dimension == 2) { lo *= yscale; hi *= yscale; rate *= yscale; } else { lo *= zscale; hi *= zscale; rate *= zscale; } deltasq *= xscale*xscale; nearsq *= xscale*xscale; vxlo *= xscale; vxhi *= xscale; vylo *= yscale; vyhi *= yscale; vzlo *= zscale; vzhi *= zscale; // random number generator, same for all procs random = new RanPark(lmp,seed); // set up reneighboring force_reneighbor = 1; next_reneighbor = update->ntimestep + 1; nfirst = next_reneighbor; ninserted = 0; } /* ---------------------------------------------------------------------- */ FixDeposit::~FixDeposit() { delete random; delete [] idregion; } /* ---------------------------------------------------------------------- */ int FixDeposit::setmask() { int mask = 0; mask |= PRE_EXCHANGE; return mask; } /* ---------------------------------------------------------------------- */ void FixDeposit::init() { // set index and check validity of region iregion = domain->find_region(idregion); if (iregion == -1) error->all("Region ID for fix deposit does not exist"); } /* ---------------------------------------------------------------------- perform particle insertion ------------------------------------------------------------------------- */ void FixDeposit::pre_exchange() { int i,j; int flag,flagall; double coord[3],lamda[3],delx,dely,delz,rsq; double *newcoord; // just return if should not be called on this timestep if (next_reneighbor != update->ntimestep) return; // compute current offset = bottom of insertion volume double offset = 0.0; if (rateflag) offset = (update->ntimestep - nfirst) * update->dt * rate; double *sublo,*subhi; if (domain->triclinic == 0) { sublo = domain->sublo; subhi = domain->subhi; } else { sublo = domain->sublo_lamda; subhi = domain->subhi_lamda; } // attempt an insertion until successful int nfix = modify->nfix; Fix **fix = modify->fix; int success = 0; int attempt = 0; while (attempt < maxattempt) { attempt++; // choose random position for new atom within region coord[0] = xlo + random->uniform() * (xhi-xlo); coord[1] = ylo + random->uniform() * (yhi-ylo); coord[2] = zlo + random->uniform() * (zhi-zlo); while (domain->regions[iregion]->match(coord[0],coord[1],coord[2]) == 0) { coord[0] = xlo + random->uniform() * (xhi-xlo); coord[1] = ylo + random->uniform() * (yhi-ylo); coord[2] = zlo + random->uniform() * (zhi-zlo); } // adjust vertical coord by offset if (domain->dimension == 2) coord[1] += offset; else coord[2] += offset; // if global, reset vertical coord to be lo-hi above highest atom // if local, reset vertical coord to be lo-hi above highest "nearby" atom // local computation computes lateral distance between 2 particles w/ PBC if (globalflag || localflag) { int dim; double max,maxall,delx,dely,delz,rsq; if (domain->dimension == 2) { dim = 1; max = domain->boxlo[1]; } else { dim = 2; max = domain->boxlo[2]; } double **x = atom->x; int nlocal = atom->nlocal; for (i = 0; i < nlocal; i++) { if (localflag) { delx = coord[0] - x[i][0]; dely = coord[1] - x[i][1]; delz = 0.0; domain->minimum_image(delx,dely,delz); if (domain->dimension == 2) rsq = delx*delx; else rsq = delx*delx + dely*dely; if (rsq > deltasq) continue; } if (x[i][dim] > max) max = x[i][dim]; } MPI_Allreduce(&max,&maxall,1,MPI_DOUBLE,MPI_MAX,world); if (domain->dimension == 2) coord[1] = maxall + lo + random->uniform()*(hi-lo); else coord[2] = maxall + lo + random->uniform()*(hi-lo); } // now have final coord // if distance to any atom is less than near, try again double **x = atom->x; int nlocal = atom->nlocal; flag = 0; for (i = 0; i < nlocal; i++) { delx = coord[0] - x[i][0]; dely = coord[1] - x[i][1]; delz = coord[2] - x[i][2]; domain->minimum_image(delx,dely,delz); rsq = delx*delx + dely*dely + delz*delz; if (rsq < nearsq) flag = 1; } MPI_Allreduce(&flag,&flagall,1,MPI_INT,MPI_MAX,world); if (flagall) continue; // insertion will proceed // choose random velocity for new atom double vxtmp = vxlo + random->uniform() * (vxhi-vxlo); double vytmp = vylo + random->uniform() * (vyhi-vylo); double vztmp = vzlo + random->uniform() * (vzhi-vzlo); // check if new atom is in my sub-box or above it if I'm highest proc // if so, add to my list via create_atom() // initialize info about the atoms // set group mask to "all" plus fix group if (domain->triclinic) { domain->x2lamda(coord,lamda); newcoord = lamda; } else newcoord = coord; flag = 0; if (newcoord[0] >= sublo[0] && newcoord[0] < subhi[0] && newcoord[1] >= sublo[1] && newcoord[1] < subhi[1] && newcoord[2] >= sublo[2] && newcoord[2] < subhi[2]) flag = 1; else if (domain->dimension == 3 && newcoord[2] >= domain->boxhi[2] && comm->myloc[2] == comm->procgrid[2]-1 && newcoord[0] >= sublo[0] && newcoord[0] < subhi[0] && newcoord[1] >= sublo[1] && newcoord[1] < subhi[1]) flag = 1; else if (domain->dimension == 2 && newcoord[1] >= domain->boxhi[1] && comm->myloc[1] == comm->procgrid[1]-1 && newcoord[0] >= sublo[0] && newcoord[0] < subhi[0]) flag = 1; if (flag) { atom->avec->create_atom(ntype,coord); int m = atom->nlocal - 1; atom->type[m] = ntype; atom->mask[m] = 1 | groupbit; atom->v[m][0] = vxtmp; atom->v[m][1] = vytmp; atom->v[m][2] = vztmp; for (j = 0; j < nfix; j++) if (fix[j]->create_attribute) fix[j]->set_arrays(m); } MPI_Allreduce(&flag,&success,1,MPI_INT,MPI_MAX,world); break; } // warn if not successful b/c too many attempts or no proc owned particle - if (comm->me == 0) - if (success == 0) - error->warning("Particle deposition was unsuccessful",0); + if (!success && comm->me == 0) + error->warning("Particle deposition was unsuccessful",0); - // set tag # of new particle beyond all previous atoms // reset global natoms + // set tag # of new particle beyond all previous atoms // if global map exists, reset it now instead of waiting for comm // since deleting atoms messes up ghosts - if (success && atom->tag_enable) { - atom->tag_extend(); + if (success) { atom->natoms += 1; - if (atom->map_style) { - atom->nghost = 0; - atom->map_init(); - atom->map_set(); + if (atom->tag_enable) { + atom->tag_extend(); + if (atom->map_style) { + atom->nghost = 0; + atom->map_init(); + atom->map_set(); + } } } // next timestep to insert // next_reneighbor = 0 if done if (success) ninserted++; if (ninserted < ninsert) next_reneighbor += nfreq; else next_reneighbor = 0; } /* ---------------------------------------------------------------------- parse optional parameters at end of input line ------------------------------------------------------------------------- */ void FixDeposit::options(int narg, char **arg) { if (narg < 0) error->all("Illegal fix indent command"); int iarg = 0; while (iarg < narg) { if (strcmp(arg[iarg],"region") == 0) { if (iarg+2 > narg) error->all("Illegal fix deposit command"); iregion = domain->find_region(arg[iarg+1]); if (iregion == -1) error->all("Region ID for fix deposit does not exist"); int n = strlen(arg[iarg+1]) + 1; idregion = new char[n]; strcpy(idregion,arg[iarg+1]); iarg += 2; } else if (strcmp(arg[iarg],"global") == 0) { if (iarg+3 > narg) error->all("Illegal fix deposit command"); globalflag = 1; localflag = 0; lo = atof(arg[iarg+1]); hi = atof(arg[iarg+2]); iarg += 3; } else if (strcmp(arg[iarg],"local") == 0) { if (iarg+4 > narg) error->all("Illegal fix deposit command"); localflag = 1; globalflag = 0; lo = atof(arg[iarg+1]); hi = atof(arg[iarg+2]); deltasq = atof(arg[iarg+3])*atof(arg[iarg+3]); iarg += 4; } else if (strcmp(arg[iarg],"near") == 0) { if (iarg+2 > narg) error->all("Illegal fix deposit command"); nearsq = atof(arg[iarg+1])*atof(arg[iarg+1]); iarg += 2; } else if (strcmp(arg[iarg],"attempt") == 0) { if (iarg+2 > narg) error->all("Illegal fix deposit command"); maxattempt = atoi(arg[iarg+1]); iarg += 2; } else if (strcmp(arg[iarg],"rate") == 0) { if (iarg+2 > narg) error->all("Illegal fix deposit command"); rateflag = 1; rate = atof(arg[iarg+1]); iarg += 2; } else if (strcmp(arg[iarg],"vx") == 0) { if (iarg+3 > narg) error->all("Illegal fix deposit command"); vxlo = atof(arg[iarg+1]); vxhi = atof(arg[iarg+2]); iarg += 3; } else if (strcmp(arg[iarg],"vy") == 0) { if (iarg+3 > narg) error->all("Illegal fix deposit command"); vylo = atof(arg[iarg+1]); vyhi = atof(arg[iarg+2]); iarg += 3; } else if (strcmp(arg[iarg],"vz") == 0) { if (iarg+3 > narg) error->all("Illegal fix deposit command"); vzlo = atof(arg[iarg+1]); vzhi = atof(arg[iarg+2]); iarg += 3; } else if (strcmp(arg[iarg],"units") == 0) { if (iarg+2 > narg) error->all("Illegal fix deposit command"); if (strcmp(arg[iarg+1],"box") == 0) scaleflag = 0; else if (strcmp(arg[iarg+1],"lattice") == 0) scaleflag = 1; else error->all("Illegal fix deposit command"); iarg += 2; } else error->all("Illegal fix deposit command"); } } /* ---------------------------------------------------------------------- pack entire state of Fix into one write ------------------------------------------------------------------------- */ void FixDeposit::write_restart(FILE *fp) { int n = 0; double list[4]; list[n++] = random->state(); list[n++] = ninserted; list[n++] = nfirst; list[n++] = next_reneighbor; if (comm->me == 0) { int size = n * sizeof(double); fwrite(&size,sizeof(int),1,fp); fwrite(list,sizeof(double),n,fp); } } /* ---------------------------------------------------------------------- use state info from restart file to restart the Fix ------------------------------------------------------------------------- */ void FixDeposit::restart(char *buf) { int n = 0; double *list = (double *) buf; seed = static_cast<int> (list[n++]); ninserted = static_cast<int> (list[n++]); nfirst = static_cast<int> (list[n++]); next_reneighbor = static_cast<int> (list[n++]); random->reset(seed); } diff --git a/src/fix_orient_fcc.cpp b/src/fix_orient_fcc.cpp index 5a7ea4470..5f7fdc068 100644 --- a/src/fix_orient_fcc.cpp +++ b/src/fix_orient_fcc.cpp @@ -1,565 +1,564 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- Contributing authors: Koenraad Janssens and David Olmsted (SNL) ------------------------------------------------------------------------- */ #include "math.h" #include "string.h" #include "stdlib.h" #include "mpi.h" #include "fix_orient_fcc.h" #include "atom.h" #include "update.h" #include "respa.h" #include "neighbor.h" #include "neigh_list.h" #include "neigh_request.h" #include "comm.h" #include "output.h" #include "error.h" using namespace LAMMPS_NS; #define BIG 1000000000 #define MIN(A,B) ((A) < (B)) ? (A) : (B) #define MAX(A,B) ((A) > (B)) ? (A) : (B) /* ---------------------------------------------------------------------- */ FixOrientFCC::FixOrientFCC(LAMMPS *lmp, int narg, char **arg) : Fix(lmp, narg, arg) { MPI_Comm_rank(world,&me); if (narg != 11) error->all("Illegal fix orient/fcc command"); scalar_flag = 1; global_freq = 1; extscalar = 1; nstats = atoi(arg[3]); direction_of_motion = atoi(arg[4]); a = atof(arg[5]); Vxi = atof(arg[6]); uxif_low = atof(arg[7]); uxif_high = atof(arg[8]); if (direction_of_motion == 0) { int n = strlen(arg[9]) + 1; chifilename = new char[n]; strcpy(chifilename,arg[9]); n = strlen(arg[10]) + 1; xifilename = new char[n]; strcpy(xifilename,arg[10]); } else if (direction_of_motion == 1) { int n = strlen(arg[9]) + 1; xifilename = new char[n]; strcpy(xifilename,arg[9]); n = strlen(arg[10]) + 1; chifilename = new char[n]; strcpy(chifilename,arg[10]); } else error->all("Illegal fix orient/fcc command"); // initializations PI = 4.0*atan(1.0); half_fcc_nn = 6; use_xismooth = false; double xicutoff = 1.57; xicutoffsq = xicutoff * xicutoff; cutsq = 0.5 * a*a*xicutoffsq; nmax = 0; // read xi and chi reference orientations from files if (me == 0) { char line[512]; char *result; int count; FILE *infile = fopen(xifilename,"r"); if (infile == NULL) error->one("Fix orient/fcc file open failed"); for (int i = 0; i < 6; i++) { result = fgets(line,512,infile); if (!result) error->one("Fix orient/fcc file read failed"); count = sscanf(line,"%lg %lg %lg",&Rxi[i][0],&Rxi[i][1],&Rxi[i][2]); if (count != 3) error->one("Fix orient/fcc file read failed"); } fclose(infile); infile = fopen(chifilename,"r"); if (infile == NULL) error->one("Fix orient/fcc file open failed"); for (int i = 0; i < 6; i++) { result = fgets(line,512,infile); if (!result) error->one("Fix orient/fcc file read failed"); count = sscanf(line,"%lg %lg %lg",&Rchi[i][0],&Rchi[i][1],&Rchi[i][2]); if (count != 3) error->one("Fix orient/fcc file read failed"); } fclose(infile); } MPI_Bcast(&Rxi[0][0],18,MPI_DOUBLE,0,world); MPI_Bcast(&Rchi[0][0],18,MPI_DOUBLE,0,world); // make copy of the reference vectors for (int i = 0; i < 6; i++) for (int j = 0; j < 3; j++) { half_xi_chi_vec[0][i][j] = Rxi[i][j]; half_xi_chi_vec[1][i][j] = Rchi[i][j]; } // compute xiid,xi0,xi1 for all 12 neighbors // xi is the favored crystal // want order parameter when actual is Rchi double xi_sq,dxi[3],rchi[3]; xiid = 0.0; for (int i = 0; i < 6; i++) { rchi[0] = Rchi[i][0]; rchi[1] = Rchi[i][1]; rchi[2] = Rchi[i][2]; find_best_ref(rchi,0,xi_sq,dxi); xiid += sqrt(xi_sq); for (int j = 0; j < 3; j++) rchi[j] = -rchi[j]; find_best_ref(rchi,0,xi_sq,dxi); xiid += sqrt(xi_sq); } xiid /= 12.0; xi0 = uxif_low * xiid; xi1 = uxif_high * xiid; // set comm size needed by this Fix // NOTE: doesn't seem that use_xismooth is ever true if (use_xismooth) comm_forward = 62; else comm_forward = 50; added_energy = 0.0; } /* ---------------------------------------------------------------------- */ FixOrientFCC::~FixOrientFCC() { delete [] xifilename; delete [] chifilename; if (nmax) delete [] nbr; } /* ---------------------------------------------------------------------- */ int FixOrientFCC::setmask() { int mask = 0; mask |= POST_FORCE; mask |= THERMO_ENERGY; mask |= POST_FORCE_RESPA; return mask; } /* ---------------------------------------------------------------------- */ void FixOrientFCC::init() { if (strcmp(update->integrate_style,"respa") == 0) nlevels_respa = ((Respa *) update->integrate)->nlevels; // need a full neighbor list, built whenever re-neighboring occurs int irequest = neighbor->request((void *) this); neighbor->requests[irequest]->pair = 0; neighbor->requests[irequest]->fix = 1; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->full = 1; } /* ---------------------------------------------------------------------- */ void FixOrientFCC::init_list(int id, NeighList *ptr) { list = ptr; } /* ---------------------------------------------------------------------- */ void FixOrientFCC::setup(int vflag) { if (strcmp(update->integrate_style,"verlet") == 0) post_force(vflag); else { ((Respa *) update->integrate)->copy_flevel_f(nlevels_respa-1); post_force_respa(vflag,nlevels_respa-1,0); ((Respa *) update->integrate)->copy_f_flevel(nlevels_respa-1); } } /* ---------------------------------------------------------------------- */ void FixOrientFCC::post_force(int vflag) { int i,j,k,ii,jj,inum,jnum,m,n,nn,nsort,id_self; int *ilist,*jlist,*numneigh,**firstneigh; double edelta,omega; double dx,dy,dz,rsq,xismooth,xi_sq,duxi,duxi_other; double dxi[3]; double *dxiptr; bool found_myself; // set local ptrs double **x = atom->x; double **f = atom->f; int *mask = atom->mask; int *tag = atom->tag; int nlocal = atom->nlocal; int nall = atom->nlocal + atom->nghost; inum = list->inum; ilist = list->ilist; numneigh = list->numneigh; firstneigh = list->firstneigh; // insure nbr data structure is adequate size if (nall > nmax) { if (nmax) delete [] nbr; nbr = new Nbr[nall]; nmax = nall; } // loop over owned atoms and build Nbr data structure of neighbors // use full neighbor list added_energy = 0.0; int count = 0; int mincount = BIG; int maxcount = 0; for (ii = 0; ii < inum; ii++) { i = ilist[ii]; jlist = firstneigh[i]; jnum = numneigh[i]; if (jnum < mincount) mincount = jnum; if (jnum > maxcount) { if (maxcount) delete [] sort; sort = new Sort[jnum]; maxcount = jnum; } // loop over all neighbors of atom i // for those within cutsq, build sort data structure // store local id, rsq, delta vector, xismooth (if included) nsort = 0; for (jj = 0; jj < jnum; jj++) { j = jlist[jj]; count++; dx = x[i][0] - x[j][0]; dy = x[i][1] - x[j][1]; dz = x[i][2] - x[j][2]; rsq = dx*dx + dy*dy + dz*dz; if (rsq < cutsq) { sort[nsort].id = j; sort[nsort].rsq = rsq; sort[nsort].delta[0] = dx; sort[nsort].delta[1] = dy; sort[nsort].delta[2] = dz; if (use_xismooth) { xismooth = (xicutoffsq - 2.0*rsq/(a*a)) / (xicutoffsq - 1.0); sort[nsort].xismooth = 1.0 - fabs(1.0-xismooth); } nsort++; } } // sort neighbors by rsq distance // no need to sort if nsort <= 12 if (nsort > 12) qsort(sort,nsort,sizeof(Sort),compare); // copy up to 12 nearest neighbors into nbr data structure // operate on delta vector via find_best_ref() to compute dxi n = MIN(12,nsort); nbr[i].n = n; if (n == 0) continue; double xi_total = 0.0; for (j = 0; j < n; j++) { find_best_ref(sort[j].delta,0,xi_sq,dxi); xi_total += sqrt(xi_sq); nbr[i].id[j] = sort[j].id; nbr[i].dxi[j][0] = dxi[0]/n; nbr[i].dxi[j][1] = dxi[1]/n; nbr[i].dxi[j][2] = dxi[2]/n; if (use_xismooth) nbr[i].xismooth[j] = sort[j].xismooth; } xi_total /= n; // compute potential derivative to xi if (xi_total < xi0) { nbr[i].duxi = 0.0; edelta = 0.0; } else if (xi_total > xi1) { nbr[i].duxi = 0.0; edelta = Vxi; } else { omega = (0.5*PI)*(xi_total-xi0) / (xi1-xi0); nbr[i].duxi = PI*Vxi*sin(2.0*omega) / (2.0*(xi1-xi0)); edelta = Vxi*(1 - cos(2.0*omega)) / 2.0; } added_energy += edelta; } if (maxcount) delete [] sort; // communicate to acquire nbr data for ghost atoms comm->forward_comm_fix(this); // compute grain boundary force on each owned atom // skip atoms not in group for (ii = 0; ii < inum; ii++) { i = ilist[ii]; if (!(mask[i] & groupbit)) continue; n = nbr[i].n; duxi = nbr[i].duxi; for (j = 0; j < n; j++) { dxiptr = &nbr[i].dxi[j][0]; if (use_xismooth) { xismooth = nbr[i].xismooth[j]; f[i][0] += duxi * dxiptr[0] * xismooth; f[i][1] += duxi * dxiptr[1] * xismooth; f[i][2] += duxi * dxiptr[2] * xismooth; } else { f[i][0] += duxi * dxiptr[0]; f[i][1] += duxi * dxiptr[1]; f[i][2] += duxi * dxiptr[2]; } // m = local index of neighbor // id_self = ID for atom I in atom M's neighbor list // if M is local atom, id_self will be local ID of atom I // if M is ghost atom, id_self will be global ID of atom I m = nbr[i].id[j]; if (m < nlocal) id_self = i; else id_self = tag[i]; found_myself = false; nn = nbr[m].n; for (k = 0; k < nn; k++) { if (id_self == nbr[m].id[k]) { if (found_myself) error->one("Fix orient/fcc found self twice"); found_myself = true; duxi_other = nbr[m].duxi; dxiptr = &nbr[m].dxi[k][0]; if (use_xismooth) { xismooth = nbr[m].xismooth[k]; f[i][0] -= duxi_other * dxiptr[0] * xismooth; f[i][1] -= duxi_other * dxiptr[1] * xismooth; f[i][2] -= duxi_other * dxiptr[2] * xismooth; } else { f[i][0] -= duxi_other * dxiptr[0]; f[i][1] -= duxi_other * dxiptr[1]; f[i][2] -= duxi_other * dxiptr[2]; } } } } } // print statistics every nstats timesteps if (nstats && update->ntimestep % nstats == 0) { int total; MPI_Allreduce(&count,&total,1,MPI_INT,MPI_SUM,world); double ave = total/atom->natoms; int min,max; MPI_Allreduce(&mincount,&min,1,MPI_INT,MPI_MIN,world); MPI_Allreduce(&maxcount,&max,1,MPI_INT,MPI_MAX,world); if (me == 0) { - if (screen) { - fprintf(screen,"orient step %d: %lu atoms have %d neighbors\n", - update->ntimestep,atom->natoms,total); + char str[64]; + sprintf(str,"orient step %%d: %s atoms have %%d neighbors\n", + BIGINT_FORMAT); + if (screen) fprintf(screen,str,update->ntimestep,atom->natoms,total); + if (logfile) fprintf(logfile,str,update->ntimestep,atom->natoms,total); + if (screen) fprintf(screen," neighs: min = %d, max = %d, ave = %g\n", min,max,ave); - } - if (logfile) { - fprintf(logfile,"orient step %d: %lu atoms have %d neighbors\n", - update->ntimestep,atom->natoms,total); + if (logfile) fprintf(logfile," neighs: min = %d, max = %d, ave = %g\n", min,max,ave); - } } } } /* ---------------------------------------------------------------------- */ void FixOrientFCC::post_force_respa(int vflag, int ilevel, int iloop) { if (ilevel == nlevels_respa-1) post_force(vflag); } /* ---------------------------------------------------------------------- */ double FixOrientFCC::compute_scalar() { MPI_Allreduce(&added_energy,&total_added_e,1,MPI_DOUBLE,MPI_SUM,world); return total_added_e; } /* ---------------------------------------------------------------------- */ int FixOrientFCC::pack_comm(int n, int *list, double *buf, int pbc_flag, int *pbc) { int i,j,k,id,num; int *tag = atom->tag; int nlocal = atom->nlocal; int m = 0; for (i = 0; i < n; i++) { k = list[i]; num = nbr[k].n; buf[m++] = static_cast<double> (num); buf[m++] = nbr[k].duxi; for (j = 0; j < num; j++) { if (use_xismooth) buf[m++] = nbr[m].xismooth[j]; buf[m++] = nbr[k].dxi[j][0]; buf[m++] = nbr[k].dxi[j][1]; buf[m++] = nbr[k].dxi[j][2]; // id stored in buf needs to be global ID // if k is a local atom, it stores local IDs, so convert to global // if k is a ghost atom (already comm'd), its IDs are already global id = nbr[k].id[j]; if (k < nlocal) id = tag[id]; buf[m++] = static_cast<double> (id); } m += (12-num) * 3; if (use_xismooth) m += 12-num; } if (use_xismooth) return 62; return 50; } /* ---------------------------------------------------------------------- */ void FixOrientFCC::unpack_comm(int n, int first, double *buf) { int i,j,num; int last = first + n; int m = 0; for (i = first; i < last; i++) { nbr[i].n = num = static_cast<int> (buf[m++]); nbr[i].duxi = buf[m++]; for (j = 0; j < num; j++) { if (use_xismooth) nbr[i].xismooth[j] = buf[m++]; nbr[i].dxi[j][0] = buf[m++]; nbr[i].dxi[j][1] = buf[m++]; nbr[i].dxi[j][2] = buf[m++]; nbr[i].id[j] = static_cast<int> (buf[m++]); } m += (12-num) * 3; if (use_xismooth) m += 12-num; } } /* ---------------------------------------------------------------------- */ void FixOrientFCC::find_best_ref(double *displs, int which_crystal, double &xi_sq, double *dxi) { int i; double dot,tmp; double best_dot = -1.0; // best is biggest (smallest angle) int best_i = -1; int best_sign = 0; for (i = 0; i < half_fcc_nn; i++) { dot = displs[0] * half_xi_chi_vec[which_crystal][i][0] + displs[1] * half_xi_chi_vec[which_crystal][i][1] + displs[2] * half_xi_chi_vec[which_crystal][i][2]; if (fabs(dot) > best_dot) { best_dot = fabs(dot); best_i = i; if (dot < 0.0) best_sign = -1; else best_sign = 1; } } xi_sq = 0.0; for (i = 0; i < 3; i++) { tmp = displs[i] - best_sign * half_xi_chi_vec[which_crystal][best_i][i]; xi_sq += tmp*tmp; } if (xi_sq > 0.0) { double xi = sqrt(xi_sq); for (i = 0; i < 3; i++) dxi[i] = (best_sign * half_xi_chi_vec[which_crystal][best_i][i] - displs[i]) / xi; } else dxi[0] = dxi[1] = dxi[2] = 0.0; } /* ---------------------------------------------------------------------- compare two neighbors I and J in sort data structure called via qsort in post_force() method is a static method so can't access sort data structure directly return -1 if I < J, 0 if I = J, 1 if I > J do comparison based on rsq distance ------------------------------------------------------------------------- */ int FixOrientFCC::compare(const void *pi, const void *pj) { FixOrientFCC::Sort *ineigh = (FixOrientFCC::Sort *) pi; FixOrientFCC::Sort *jneigh = (FixOrientFCC::Sort *) pj; if (ineigh->rsq < jneigh->rsq) return -1; else if (ineigh->rsq > jneigh->rsq) return 1; return 0; } /* ---------------------------------------------------------------------- memory usage of local atom-based arrays ------------------------------------------------------------------------- */ double FixOrientFCC::memory_usage() { double bytes = atom->nmax * sizeof(Nbr); return bytes; } diff --git a/src/fix_shake.cpp b/src/fix_shake.cpp index 96aecdf77..cf38f11e4 100644 --- a/src/fix_shake.cpp +++ b/src/fix_shake.cpp @@ -1,2427 +1,2435 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ #include "mpi.h" #include "math.h" #include "stdlib.h" #include "string.h" #include "stdio.h" #include "fix_shake.h" +#include "lmptype.h" #include "atom.h" #include "atom_vec.h" #include "update.h" #include "respa.h" #include "modify.h" #include "domain.h" #include "force.h" #include "bond.h" #include "angle.h" #include "comm.h" #include "group.h" #include "fix_respa.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; #define BIG 1.0e20 #define MASSDELTA 0.1 #define MIN(a,b) ((a) < (b) ? (a) : (b)) #define MAX(a,b) ((a) > (b) ? (a) : (b)) /* ---------------------------------------------------------------------- */ FixShake::FixShake(LAMMPS *lmp, int narg, char **arg) : Fix(lmp, narg, arg) { MPI_Comm_rank(world,&me); MPI_Comm_size(world,&nprocs); PI = 4.0*atan(1.0); virial_flag = 1; create_attribute = 1; // error check if (atom->molecular == 0) error->all("Cannot use fix shake with non-molecular system"); // perform initial allocation of atom-based arrays // register with Atom class shake_flag = NULL; shake_atom = shake_type = NULL; xshake = NULL; grow_arrays(atom->nmax); atom->add_callback(0); // set comm size needed by this fix comm_forward = 3; // parse SHAKE args if (narg < 8) error->all("Illegal fix shake command"); tolerance = atof(arg[3]); max_iter = atoi(arg[4]); output_every = atoi(arg[5]); // parse SHAKE args for bond and angle types // will be used by find_clusters // store args for "b" "a" "t" as flags in (1:n) list for fast access // store args for "m" in list of length nmass for looping over // for "m" verify that atom masses have been set bond_flag = new int[atom->nbondtypes+1]; for (int i = 1; i <= atom->nbondtypes; i++) bond_flag[i] = 0; angle_flag = new int[atom->nangletypes+1]; for (int i = 1; i <= atom->nangletypes; i++) angle_flag[i] = 0; type_flag = new int[atom->ntypes+1]; for (int i = 1; i <= atom->ntypes; i++) type_flag[i] = 0; mass_list = new double[atom->ntypes]; nmass = 0; char mode = '\0'; int next = 6; while (next < narg) { if (strcmp(arg[next],"b") == 0) mode = 'b'; else if (strcmp(arg[next],"a") == 0) mode = 'a'; else if (strcmp(arg[next],"t") == 0) mode = 't'; else if (strcmp(arg[next],"m") == 0) { mode = 'm'; atom->check_mass(); } else if (mode == 'b') { int i = atoi(arg[next]); if (i < 1 || i > atom->nbondtypes) error->all("Invalid bond type index for fix shake"); bond_flag[i] = 1; } else if (mode == 'a') { int i = atoi(arg[next]); if (i < 1 || i > atom->nangletypes) error->all("Invalid angle type index for fix shake"); angle_flag[i] = 1; } else if (mode == 't') { int i = atoi(arg[next]); if (i < 1 || i > atom->ntypes) error->all("Invalid atom type index for fix shake"); type_flag[i] = 1; } else if (mode == 'm') { double massone = atof(arg[next]); if (massone == 0.0) error->all("Invalid atom mass for fix shake"); if (nmass == atom->ntypes) error->all("Too many masses for fix shake"); mass_list[nmass++] = massone; } else error->all("Illegal fix shake command"); next++; } // allocate bond and angle distance arrays, indexed from 1 to n bond_distance = new double[atom->nbondtypes+1]; angle_distance = new double[atom->nangletypes+1]; // allocate statistics arrays if (output_every) { int nb = atom->nbondtypes + 1; b_count = new int[nb]; b_count_all = new int[nb]; b_ave = new double[nb]; b_ave_all = new double[nb]; b_max = new double[nb]; b_max_all = new double[nb]; b_min = new double[nb]; b_min_all = new double[nb]; int na = atom->nangletypes + 1; a_count = new int[na]; a_count_all = new int[na]; a_ave = new double[na]; a_ave_all = new double[na]; a_max = new double[na]; a_max_all = new double[na]; a_min = new double[na]; a_min_all = new double[na]; } // identify all SHAKE clusters find_clusters(); // initialize list of SHAKE clusters to constrain maxlist = 0; list = NULL; } /* ---------------------------------------------------------------------- */ FixShake::~FixShake() { // unregister callbacks to this fix from Atom class atom->delete_callback(id,0); // set bond_type and angle_type back to positive for SHAKE clusters // must set for all SHAKE bonds and angles stored by each atom int **bond_type = atom->bond_type; int **angle_type = atom->angle_type; int nlocal = atom->nlocal; int n; for (int i = 0; i < nlocal; i++) { if (shake_flag[i] == 0) continue; else if (shake_flag[i] == 1) { n = bondfind(i,shake_atom[i][0],shake_atom[i][1]); if (n >= 0) bond_type[i][n] = -bond_type[i][n]; n = bondfind(i,shake_atom[i][0],shake_atom[i][2]); if (n >= 0) bond_type[i][n] = -bond_type[i][n]; n = anglefind(i,shake_atom[i][1],shake_atom[i][2]); if (n >= 0) angle_type[i][n] = -angle_type[i][n]; } else if (shake_flag[i] == 2) { n = bondfind(i,shake_atom[i][0],shake_atom[i][1]); if (n >= 0) bond_type[i][n] = -bond_type[i][n]; } else if (shake_flag[i] == 3) { n = bondfind(i,shake_atom[i][0],shake_atom[i][1]); if (n >= 0) bond_type[i][n] = -bond_type[i][n]; n = bondfind(i,shake_atom[i][0],shake_atom[i][2]); if (n >= 0) bond_type[i][n] = -bond_type[i][n]; } else if (shake_flag[i] == 4) { n = bondfind(i,shake_atom[i][0],shake_atom[i][1]); if (n >= 0) bond_type[i][n] = -bond_type[i][n]; n = bondfind(i,shake_atom[i][0],shake_atom[i][2]); if (n >= 0) bond_type[i][n] = -bond_type[i][n]; n = bondfind(i,shake_atom[i][0],shake_atom[i][3]); if (n >= 0) bond_type[i][n] = -bond_type[i][n]; } } // delete locally stored arrays memory->sfree(shake_flag); memory->destroy_2d_int_array(shake_atom); memory->destroy_2d_int_array(shake_type); memory->destroy_2d_double_array(xshake); delete [] bond_flag; delete [] angle_flag; delete [] type_flag; delete [] mass_list; delete [] bond_distance; delete [] angle_distance; if (output_every) { delete [] b_count; delete [] b_count_all; delete [] b_ave; delete [] b_ave_all; delete [] b_max; delete [] b_max_all; delete [] b_min; delete [] b_min_all; delete [] a_count; delete [] a_count_all; delete [] a_ave; delete [] a_ave_all; delete [] a_max; delete [] a_max_all; delete [] a_min; delete [] a_min_all; } memory->sfree(list); } /* ---------------------------------------------------------------------- */ int FixShake::setmask() { int mask = 0; mask |= PRE_NEIGHBOR; mask |= POST_FORCE; mask |= POST_FORCE_RESPA; return mask; } /* ---------------------------------------------------------------------- set bond and angle distances this init must happen after force->bond and force->angle inits ------------------------------------------------------------------------- */ void FixShake::init() { int i,m,flag,flag_all,type1,type2,bond1_type,bond2_type; double rsq,angle; // error if more than one shake fix int count = 0; for (i = 0; i < modify->nfix; i++) if (strcmp(modify->fix[i]->style,"shake") == 0) count++; if (count > 1) error->all("More than one fix shake"); // cannot use with minimization since SHAKE turns off bonds // that should contribute to potential energy if (update->whichflag == 2) error->all("Fix shake cannot be used with minimization"); // error if npt,nph fix comes before shake fix for (i = 0; i < modify->nfix; i++) { if (strcmp(modify->fix[i]->style,"npt") == 0) break; if (strcmp(modify->fix[i]->style,"nph") == 0) break; } if (i < modify->nfix) { for (int j = i; j < modify->nfix; j++) if (strcmp(modify->fix[j]->style,"shake") == 0) error->all("Shake fix must come before NPT/NPH fix"); } // if rRESPA, find associated fix that must exist // could have changed locations in fix list since created // set ptrs to rRESPA variables if (strcmp(update->integrate_style,"respa") == 0) { for (i = 0; i < modify->nfix; i++) if (strcmp(modify->fix[i]->style,"RESPA") == 0) ifix_respa = i; nlevels_respa = ((Respa *) update->integrate)->nlevels; loop_respa = ((Respa *) update->integrate)->loop; step_respa = ((Respa *) update->integrate)->step; } // set equilibrium bond distances if (force->bond == NULL) error->all("Bond potential must be defined for SHAKE"); for (i = 1; i <= atom->nbondtypes; i++) bond_distance[i] = force->bond->equilibrium_distance(i); // set equilibrium angle distances int nlocal = atom->nlocal; for (i = 1; i <= atom->nangletypes; i++) { if (angle_flag[i] == 0) continue; if (force->angle == NULL) error->all("Angle potential must be defined for SHAKE"); // scan all atoms for a SHAKE angle cluster // extract bond types for the 2 bonds in the cluster // bond types must be same in all clusters of this angle type, // else set error flag flag = 0; bond1_type = bond2_type = 0; for (m = 0; m < nlocal; m++) { if (shake_flag[m] != 1) continue; if (shake_type[m][2] != i) continue; type1 = MIN(shake_type[m][0],shake_type[m][1]); type2 = MAX(shake_type[m][0],shake_type[m][1]); if (bond1_type > 0) { if (type1 != bond1_type || type2 != bond2_type) { flag = 1; break; } } bond1_type = type1; bond2_type = type2; } // error check for any bond types that are not the same MPI_Allreduce(&flag,&flag_all,1,MPI_INT,MPI_MAX,world); if (flag_all) error->all("Shake angles have different bond types"); // insure all procs have bond types MPI_Allreduce(&bond1_type,&flag_all,1,MPI_INT,MPI_MAX,world); bond1_type = flag_all; MPI_Allreduce(&bond2_type,&flag_all,1,MPI_INT,MPI_MAX,world); bond2_type = flag_all; // if bond types are 0, no SHAKE angles of this type exist // just skip this angle if (bond1_type == 0) { angle_distance[i] = 0.0; continue; } // compute the angle distance as a function of 2 bond distances angle = force->angle->equilibrium_angle(i); rsq = 2.0*bond_distance[bond1_type]*bond_distance[bond2_type] * (1.0-cos(angle)); angle_distance[i] = sqrt(rsq); } } /* ---------------------------------------------------------------------- SHAKE as pre-integrator constraint ------------------------------------------------------------------------- */ void FixShake::setup(int vflag) { pre_neighbor(); if (output_every) stats(); // setup SHAKE output - int ntimestep = update->ntimestep; + bigint ntimestep = update->ntimestep; next_output = ntimestep + output_every; if (output_every == 0) next_output = update->laststep + 1; if (output_every && ntimestep % output_every != 0) next_output = (ntimestep/output_every)*output_every + output_every; // half timestep constraint on pre-step, full timestep thereafter if (strcmp(update->integrate_style,"verlet") == 0) { dtv = update->dt; dtfsq = 0.5 * update->dt * update->dt * force->ftm2v; post_force(vflag); dtfsq = update->dt * update->dt * force->ftm2v; } else { dtv = step_respa[0]; dtf_innerhalf = 0.5 * step_respa[0] * force->ftm2v; dtf_inner = dtf_innerhalf; ((Respa *) update->integrate)->copy_flevel_f(nlevels_respa-1); post_force_respa(vflag,nlevels_respa-1,0); ((Respa *) update->integrate)->copy_f_flevel(nlevels_respa-1); dtf_inner = step_respa[0] * force->ftm2v; } } /* ---------------------------------------------------------------------- build list of SHAKE clusters to constrain if one or more atoms in cluster are on this proc, this proc lists the cluster exactly once ------------------------------------------------------------------------- */ void FixShake::pre_neighbor() { int atom1,atom2,atom3,atom4; // local copies of atom quantities // used by SHAKE until next re-neighboring x = atom->x; v = atom->v; f = atom->f; mass = atom->mass; rmass = atom->rmass; type = atom->type; nlocal = atom->nlocal; // extend size of SHAKE list if necessary if (nlocal > maxlist) { maxlist = nlocal; memory->sfree(list); list = (int *) memory->smalloc(maxlist*sizeof(int),"shake:list"); } // build list of SHAKE clusters I compute nlist = 0; for (int i = 0; i < nlocal; i++) if (shake_flag[i]) { if (shake_flag[i] == 2) { atom1 = atom->map(shake_atom[i][0]); atom2 = atom->map(shake_atom[i][1]); if (atom1 == -1 || atom2 == -1) { - char str[128]; - sprintf(str,"Shake atoms %d %d missing on proc %d at step %d", + char str[128],fstr[64]; + sprintf(fstr,"Shake atoms %%d %%d missing on proc %%d at step %s", + BIGINT_FORMAT); + sprintf(str,fstr, shake_atom[i][0],shake_atom[i][1],me,update->ntimestep); error->one(str); } if (i <= atom1 && i <= atom2) list[nlist++] = i; } else if (shake_flag[i] % 2 == 1) { atom1 = atom->map(shake_atom[i][0]); atom2 = atom->map(shake_atom[i][1]); atom3 = atom->map(shake_atom[i][2]); if (atom1 == -1 || atom2 == -1 || atom3 == -1) { - char str[128]; - sprintf(str,"Shake atoms %d %d %d missing on proc %d at step %d", + char str[128],fstr[64]; + sprintf(fstr,"Shake atoms %%d %%d %%d missing on proc %%d at step %s", + BIGINT_FORMAT); + sprintf(str,fstr, shake_atom[i][0],shake_atom[i][1],shake_atom[i][2], me,update->ntimestep); error->one(str); } if (i <= atom1 && i <= atom2 && i <= atom3) list[nlist++] = i; } else { atom1 = atom->map(shake_atom[i][0]); atom2 = atom->map(shake_atom[i][1]); atom3 = atom->map(shake_atom[i][2]); atom4 = atom->map(shake_atom[i][3]); if (atom1 == -1 || atom2 == -1 || atom3 == -1 || atom4 == -1) { - char str[128]; - sprintf(str,"Shake atoms %d %d %d %d missing on proc %d at step %d", + char str[128],fstr[64]; + sprintf(fstr, + "Shake atoms %%d %%d %%d %%d missing on proc %%d at step %s", + BIGINT_FORMAT); + sprintf(str,fstr, shake_atom[i][0],shake_atom[i][1], shake_atom[i][2],shake_atom[i][3], me,update->ntimestep); error->one(str); } if (i <= atom1 && i <= atom2 && i <= atom3 && i <= atom4) list[nlist++] = i; } } } /* ---------------------------------------------------------------------- compute the force adjustment for SHAKE constraint ------------------------------------------------------------------------- */ void FixShake::post_force(int vflag) { if (update->ntimestep == next_output) stats(); // xshake = unconstrained move with current v,f // communicate results if necessary unconstrained_update(); if (nprocs > 1) comm->forward_comm_fix(this); // virial setup if (vflag) v_setup(vflag); else evflag = 0; // loop over clusters to add constraint forces int m; for (int i = 0; i < nlist; i++) { m = list[i]; if (shake_flag[m] == 2) shake2(m); else if (shake_flag[m] == 3) shake3(m); else if (shake_flag[m] == 4) shake4(m); else shake3angle(m); } } /* ---------------------------------------------------------------------- enforce SHAKE constraints from rRESPA xshake prediction portion is different than Verlet ------------------------------------------------------------------------- */ void FixShake::post_force_respa(int vflag, int ilevel, int iloop) { // call stats only on outermost level if (ilevel == nlevels_respa-1 && update->ntimestep == next_output) stats(); // enforce SHAKE constraints on every loop iteration of every rRESPA level // except last loop iteration of inner levels if (ilevel < nlevels_respa-1 && iloop == loop_respa[ilevel]-1) return; // xshake = unconstrained move with current v,f as function of level // communicate results if necessary unconstrained_update_respa(ilevel); if (nprocs > 1) comm->forward_comm_fix(this); // virial setup, only need to compute on outermost level if (ilevel == nlevels_respa-1 && vflag) v_setup(vflag); else evflag = 0; // loop over clusters to add constraint forces int m; for (int i = 0; i < nlist; i++) { m = list[i]; if (shake_flag[m] == 2) shake2(m); else if (shake_flag[m] == 3) shake3(m); else if (shake_flag[m] == 4) shake4(m); else shake3angle(m); } } /* ---------------------------------------------------------------------- count # of degrees-of-freedom removed by SHAKE for atoms in igroup ------------------------------------------------------------------------- */ int FixShake::dof(int igroup) { int groupbit = group->bitmask[igroup]; int *mask = atom->mask; int *tag = atom->tag; int nlocal = atom->nlocal; // count dof in a cluster if and only if // the central atom is in group and atom i is the central atom int n = 0; for (int i = 0; i < nlocal; i++) { if (!(mask[i] & groupbit)) continue; if (shake_flag[i] == 0) continue; if (shake_atom[i][0] != tag[i]) continue; if (shake_flag[i] == 1) n += 3; else if (shake_flag[i] == 2) n += 1; else if (shake_flag[i] == 3) n += 2; else if (shake_flag[i] == 4) n += 3; } int nall; MPI_Allreduce(&n,&nall,1,MPI_INT,MPI_SUM,world); return nall; } /* ---------------------------------------------------------------------- identify whether each atom is in a SHAKE cluster only include atoms in fix group and those bonds/angles specified in input test whether all clusters are valid set shake_flag, shake_atom, shake_type values set bond,angle types negative so will be ignored in neighbor lists ------------------------------------------------------------------------- */ void FixShake::find_clusters() { int i,j,m,n; int flag,flag_all,messtag,loop,nbuf,nbufmax,size; double massone; int *buf,*bufcopy; MPI_Request request; MPI_Status status; if (me == 0 && screen) fprintf(screen,"Finding SHAKE clusters ...\n"); // local copies of atom ptrs int *tag = atom->tag; int *type = atom->type; int *mask = atom->mask; double *mass = atom->mass; double *rmass = atom->rmass; int **bond_type = atom->bond_type; int **angle_type = atom->angle_type; int **nspecial = atom->nspecial; int **special = atom->special; int nlocal = atom->nlocal; int angles_allow = atom->avec->angles_allow; // setup ring of procs int next = me + 1; int prev = me -1; if (next == nprocs) next = 0; if (prev < 0) prev = nprocs - 1; // ----------------------------------------------------- // allocate arrays for self (1d) and bond partners (2d) // max = max # of bond partners for owned atoms = 2nd dim of partner arrays // npartner[i] = # of bonds attached to atom i // nshake[i] = # of SHAKE bonds attached to atom i // partner_tag[i][] = global IDs of each partner // partner_mask[i][] = mask of each partner // partner_type[i][] = type of each partner // partner_massflag[i][] = 1 if partner meets mass criterion, 0 if not // partner_bondtype[i][] = type of bond attached to each partner // partner_shake[i][] = 1 if SHAKE bonded to partner, 0 if not // partner_nshake[i][] = nshake value for each partner // ----------------------------------------------------- int max = 0; for (i = 0; i < nlocal; i++) max = MAX(max,nspecial[i][0]); int *npartner = (int *) memory->smalloc(nlocal*sizeof(double),"shake:npartner"); int *nshake = (int *) memory->smalloc(nlocal*sizeof(double),"shake:nshake"); int **partner_tag = memory->create_2d_int_array(nlocal,max,"shake:partner_tag"); int **partner_mask = memory->create_2d_int_array(nlocal,max,"shake:partner_mask"); int **partner_type = memory->create_2d_int_array(nlocal,max,"shake:partner_type"); int **partner_massflag = memory->create_2d_int_array(nlocal,max,"shake:partner_massflag"); int **partner_bondtype = memory->create_2d_int_array(nlocal,max,"shake:partner_bondtype"); int **partner_shake = memory->create_2d_int_array(nlocal,max,"shake:partner_shake"); int **partner_nshake = memory->create_2d_int_array(nlocal,max,"shake:partner_nshake"); // ----------------------------------------------------- // set npartner and partner_tag from special arrays // ----------------------------------------------------- for (i = 0; i < nlocal; i++) { npartner[i] = nspecial[i][0]; for (j = 0; j < npartner[i]; j++) partner_tag[i][j] = special[i][j]; } // ----------------------------------------------------- // set partner_mask, partner_type, partner_massflag, partner_bondtype // for bonded partners // requires communication for off-proc partners // ----------------------------------------------------- // fill in mask, type, massflag, bondtype if own bond partner // info to store in buf for each off-proc bond = nper = 6 // 2 atoms IDs in bond, space for mask, type, massflag, bondtype // nbufmax = largest buffer needed to hold info from any proc int nper = 6; nbuf = 0; for (i = 0; i < nlocal; i++) { for (j = 0; j < npartner[i]; j++) { partner_mask[i][j] = 0; partner_type[i][j] = 0; partner_massflag[i][j] = 0; partner_bondtype[i][j] = 0; m = atom->map(partner_tag[i][j]); if (m >= 0 && m < nlocal) { partner_mask[i][j] = mask[m]; partner_type[i][j] = type[m]; if (nmass) { if (rmass) massone = rmass[m]; else massone = mass[type[m]]; partner_massflag[i][j] = masscheck(massone); } n = bondfind(i,tag[i],partner_tag[i][j]); if (n >= 0) partner_bondtype[i][j] = bond_type[i][n]; else { n = bondfind(m,tag[i],partner_tag[i][j]); if (n >= 0) partner_bondtype[i][j] = bond_type[m][n]; } } else nbuf += nper; } } MPI_Allreduce(&nbuf,&nbufmax,1,MPI_INT,MPI_MAX,world); buf = new int[nbufmax]; bufcopy = new int[nbufmax]; // fill buffer with info size = 0; for (i = 0; i < nlocal; i++) { for (j = 0; j < npartner[i]; j++) { m = atom->map(partner_tag[i][j]); if (m < 0 || m >= nlocal) { buf[size] = tag[i]; buf[size+1] = partner_tag[i][j]; buf[size+2] = 0; buf[size+3] = 0; buf[size+4] = 0; n = bondfind(i,tag[i],partner_tag[i][j]); if (n >= 0) buf[size+5] = bond_type[i][n]; else buf[size+5] = 0; size += nper; } } } // cycle buffer around ring of procs back to self // when receive buffer, scan bond partner IDs for atoms I own // if I own partner: // fill in mask and type and massflag // search for bond with 1st atom and fill in bondtype messtag = 1; for (loop = 0; loop < nprocs; loop++) { i = 0; while (i < size) { m = atom->map(buf[i+1]); if (m >= 0 && m < nlocal) { buf[i+2] = mask[m]; buf[i+3] = type[m]; if (nmass) { if (rmass) massone = rmass[m]; else massone = mass[type[m]]; buf[i+4] = masscheck(massone); } if (buf[i+5] == 0) { n = bondfind(m,buf[i],buf[i+1]); if (n >= 0) buf[i+5] = bond_type[m][n]; } } i += nper; } if (me != next) { MPI_Irecv(bufcopy,nbufmax,MPI_INT,prev,messtag,world,&request); MPI_Send(buf,size,MPI_INT,next,messtag,world); MPI_Wait(&request,&status); MPI_Get_count(&status,MPI_INT,&size); for (j = 0; j < size; j++) buf[j] = bufcopy[j]; } } // store partner info returned to me m = 0; while (m < size) { i = atom->map(buf[m]); for (j = 0; j < npartner[i]; j++) if (buf[m+1] == partner_tag[i][j]) break; partner_mask[i][j] = buf[m+2]; partner_type[i][j] = buf[m+3]; partner_massflag[i][j] = buf[m+4]; partner_bondtype[i][j] = buf[m+5]; m += nper; } delete [] buf; delete [] bufcopy; // error check for unfilled partner info // if partner_type not set, is an error // partner_bondtype may not be set if special list is not consistent // with bondatom (e.g. due to delete_bonds command) // this is OK if one or both atoms are not in fix group, since // bond won't be SHAKEn anyway // else it's an error flag = 0; for (i = 0; i < nlocal; i++) for (j = 0; j < npartner[i]; j++) { if (partner_type[i][j] == 0) flag = 1; if (!(mask[i] & groupbit)) continue; if (!(partner_mask[i][j] & groupbit)) continue; if (partner_bondtype[i][j] == 0) flag = 1; } MPI_Allreduce(&flag,&flag_all,1,MPI_INT,MPI_SUM,world); if (flag_all) error->all("Did not find fix shake partner info"); // ----------------------------------------------------- // identify SHAKEable bonds // set nshake[i] = # of SHAKE bonds attached to atom i // set partner_shake[i][] = 1 if SHAKE bonded to partner, 0 if not // both atoms must be in group, bondtype must be > 0 // check if bondtype is in input bond_flag // check if type of either atom is in input type_flag // check if mass of either atom is in input mass_list // ----------------------------------------------------- int np; for (i = 0; i < nlocal; i++) { nshake[i] = 0; np = npartner[i]; for (j = 0; j < np; j++) { partner_shake[i][j] = 0; if (!(mask[i] & groupbit)) continue; if (!(partner_mask[i][j] & groupbit)) continue; if (partner_bondtype[i][j] <= 0) continue; if (bond_flag[partner_bondtype[i][j]]) { partner_shake[i][j] = 1; nshake[i]++; continue; } if (type_flag[type[i]] || type_flag[partner_type[i][j]]) { partner_shake[i][j] = 1; nshake[i]++; continue; } if (nmass) { if (partner_massflag[i][j]) { partner_shake[i][j] = 1; nshake[i]++; continue; } else { if (rmass) massone = rmass[i]; else massone = mass[type[i]]; if (masscheck(massone)) { partner_shake[i][j] = 1; nshake[i]++; continue; } } } } } // ----------------------------------------------------- // set partner_nshake for bonded partners // requires communication for off-proc partners // ----------------------------------------------------- // fill in partner_nshake if own bond partner // info to store in buf for each off-proc bond = // 2 atoms IDs in bond, space for nshake value // nbufmax = largest buffer needed to hold info from any proc nbuf = 0; for (i = 0; i < nlocal; i++) { for (j = 0; j < npartner[i]; j++) { m = atom->map(partner_tag[i][j]); if (m >= 0 && m < nlocal) partner_nshake[i][j] = nshake[m]; else nbuf += 3; } } MPI_Allreduce(&nbuf,&nbufmax,1,MPI_INT,MPI_MAX,world); buf = new int[nbufmax]; bufcopy = new int[nbufmax]; // fill buffer with info size = 0; for (i = 0; i < nlocal; i++) { for (j = 0; j < npartner[i]; j++) { m = atom->map(partner_tag[i][j]); if (m < 0 || m >= nlocal) { buf[size] = tag[i]; buf[size+1] = partner_tag[i][j]; size += 3; } } } // cycle buffer around ring of procs back to self // when receive buffer, scan bond partner IDs for atoms I own // if I own partner, fill in nshake value messtag = 2; for (loop = 0; loop < nprocs; loop++) { i = 0; while (i < size) { m = atom->map(buf[i+1]); if (m >= 0 && m < nlocal) buf[i+2] = nshake[m]; i += 3; } if (me != next) { MPI_Irecv(bufcopy,nbufmax,MPI_INT,prev,messtag,world,&request); MPI_Send(buf,size,MPI_INT,next,messtag,world); MPI_Wait(&request,&status); MPI_Get_count(&status,MPI_INT,&size); for (j = 0; j < size; j++) buf[j] = bufcopy[j]; } } // store partner info returned to me m = 0; while (m < size) { i = atom->map(buf[m]); for (j = 0; j < npartner[i]; j++) if (buf[m+1] == partner_tag[i][j]) break; partner_nshake[i][j] = buf[m+2]; m += 3; } delete [] buf; delete [] bufcopy; // ----------------------------------------------------- // error checks // no atom with nshake > 3 // no connected atoms which both have nshake > 1 // ----------------------------------------------------- flag = 0; for (i = 0; i < nlocal; i++) if (nshake[i] > 3) flag = 1; MPI_Allreduce(&flag,&flag_all,1,MPI_INT,MPI_SUM,world); if (flag_all) error->all("Shake cluster of more than 4 atoms"); flag = 0; for (i = 0; i < nlocal; i++) { if (nshake[i] <= 1) continue; for (j = 0; j < npartner[i]; j++) if (partner_shake[i][j] && partner_nshake[i][j] > 1) flag = 1; } MPI_Allreduce(&flag,&flag_all,1,MPI_INT,MPI_SUM,world); if (flag_all) error->all("Shake clusters are connected"); // ----------------------------------------------------- // set SHAKE arrays that are stored with atoms & add angle constraints // zero shake arrays for all owned atoms // if I am central atom set shake_flag & shake_atom & shake_type // for 2-atom clusters, I am central atom if my atom ID < partner ID // for 3-atom clusters, test for angle constraint // angle will be stored by this atom if it exists // if angle type matches angle_flag, then it is angle-constrained // shake_flag[] = 0 if atom not in SHAKE cluster // 2,3,4 = size of bond-only cluster // 1 = 3-atom angle cluster // shake_atom[][] = global IDs of 2,3,4 atoms in cluster // central atom is 1st // for 2-atom cluster, lowest ID is 1st // shake_type[][] = bondtype of each bond in cluster // for 3-atom angle cluster, 3rd value is angletype // ----------------------------------------------------- for (i = 0; i < nlocal; i++) { shake_flag[i] = 0; shake_atom[i][0] = 0; shake_atom[i][1] = 0; shake_atom[i][2] = 0; shake_atom[i][3] = 0; shake_type[i][0] = 0; shake_type[i][1] = 0; shake_type[i][2] = 0; if (nshake[i] == 1) { for (j = 0; j < npartner[i]; j++) if (partner_shake[i][j]) break; if (partner_nshake[i][j] == 1 && tag[i] < partner_tag[i][j]) { shake_flag[i] = 2; shake_atom[i][0] = tag[i]; shake_atom[i][1] = partner_tag[i][j]; shake_type[i][0] = partner_bondtype[i][j]; } } if (nshake[i] > 1) { shake_flag[i] = 1; shake_atom[i][0] = tag[i]; for (j = 0; j < npartner[i]; j++) if (partner_shake[i][j]) { m = shake_flag[i]; shake_atom[i][m] = partner_tag[i][j]; shake_type[i][m-1] = partner_bondtype[i][j]; shake_flag[i]++; } } if (nshake[i] == 2 && angles_allow) { n = anglefind(i,shake_atom[i][1],shake_atom[i][2]); if (n < 0) continue; if (angle_type[i][n] < 0) continue; if (angle_flag[angle_type[i][n]]) { shake_flag[i] = 1; shake_type[i][2] = angle_type[i][n]; } } } // ----------------------------------------------------- // set shake_flag,shake_atom,shake_type for non-central atoms // requires communication for off-proc atoms // ----------------------------------------------------- // fill in shake arrays for each bond partner I own // info to store in buf for each off-proc bond = // all values from shake_flag, shake_atom, shake_type // nbufmax = largest buffer needed to hold info from any proc nbuf = 0; for (i = 0; i < nlocal; i++) { if (shake_flag[i] == 0) continue; for (j = 0; j < npartner[i]; j++) { if (partner_shake[i][j] == 0) continue; m = atom->map(partner_tag[i][j]); if (m >= 0 && m < nlocal) { shake_flag[m] = shake_flag[i]; shake_atom[m][0] = shake_atom[i][0]; shake_atom[m][1] = shake_atom[i][1]; shake_atom[m][2] = shake_atom[i][2]; shake_atom[m][3] = shake_atom[i][3]; shake_type[m][0] = shake_type[i][0]; shake_type[m][1] = shake_type[i][1]; shake_type[m][2] = shake_type[i][2]; } else nbuf += 9; } } MPI_Allreduce(&nbuf,&nbufmax,1,MPI_INT,MPI_MAX,world); buf = new int[nbufmax]; bufcopy = new int[nbufmax]; // fill buffer with info size = 0; for (i = 0; i < nlocal; i++) { if (shake_flag[i] == 0) continue; for (j = 0; j < npartner[i]; j++) { if (partner_shake[i][j] == 0) continue; m = atom->map(partner_tag[i][j]); if (m < 0 || m >= nlocal) { buf[size] = partner_tag[i][j]; buf[size+1] = shake_flag[i]; buf[size+2] = shake_atom[i][0]; buf[size+3] = shake_atom[i][1]; buf[size+4] = shake_atom[i][2]; buf[size+5] = shake_atom[i][3]; buf[size+6] = shake_type[i][0]; buf[size+7] = shake_type[i][1]; buf[size+8] = shake_type[i][2]; size += 9; } } } // cycle buffer around ring of procs back to self // when receive buffer, scan for ID that I own // if I own ID, fill in shake array values messtag = 3; for (loop = 0; loop < nprocs; loop++) { i = 0; while (i < size) { m = atom->map(buf[i]); if (m >= 0 && m < nlocal) { shake_flag[m] = buf[i+1]; shake_atom[m][0] = buf[i+2]; shake_atom[m][1] = buf[i+3]; shake_atom[m][2] = buf[i+4]; shake_atom[m][3] = buf[i+5]; shake_type[m][0] = buf[i+6]; shake_type[m][1] = buf[i+7]; shake_type[m][2] = buf[i+8]; } i += 9; } if (me != next) { MPI_Irecv(bufcopy,nbufmax,MPI_INT,prev,messtag,world,&request); MPI_Send(buf,size,MPI_INT,next,messtag,world); MPI_Wait(&request,&status); MPI_Get_count(&status,MPI_INT,&size); for (j = 0; j < size; j++) buf[j] = bufcopy[j]; } } delete [] buf; delete [] bufcopy; // ----------------------------------------------------- // free local memory // ----------------------------------------------------- memory->sfree(npartner); memory->sfree(nshake); memory->destroy_2d_int_array(partner_tag); memory->destroy_2d_int_array(partner_mask); memory->destroy_2d_int_array(partner_type); memory->destroy_2d_int_array(partner_massflag); memory->destroy_2d_int_array(partner_bondtype); memory->destroy_2d_int_array(partner_shake); memory->destroy_2d_int_array(partner_nshake); // ----------------------------------------------------- // set bond_type and angle_type negative for SHAKE clusters // must set for all SHAKE bonds and angles stored by each atom // ----------------------------------------------------- for (i = 0; i < nlocal; i++) { if (shake_flag[i] == 0) continue; else if (shake_flag[i] == 1) { n = bondfind(i,shake_atom[i][0],shake_atom[i][1]); if (n >= 0) bond_type[i][n] = -bond_type[i][n]; n = bondfind(i,shake_atom[i][0],shake_atom[i][2]); if (n >= 0) bond_type[i][n] = -bond_type[i][n]; n = anglefind(i,shake_atom[i][1],shake_atom[i][2]); if (n >= 0) angle_type[i][n] = -angle_type[i][n]; } else if (shake_flag[i] == 2) { n = bondfind(i,shake_atom[i][0],shake_atom[i][1]); if (n >= 0) bond_type[i][n] = -bond_type[i][n]; } else if (shake_flag[i] == 3) { n = bondfind(i,shake_atom[i][0],shake_atom[i][1]); if (n >= 0) bond_type[i][n] = -bond_type[i][n]; n = bondfind(i,shake_atom[i][0],shake_atom[i][2]); if (n >= 0) bond_type[i][n] = -bond_type[i][n]; } else if (shake_flag[i] == 4) { n = bondfind(i,shake_atom[i][0],shake_atom[i][1]); if (n >= 0) bond_type[i][n] = -bond_type[i][n]; n = bondfind(i,shake_atom[i][0],shake_atom[i][2]); if (n >= 0) bond_type[i][n] = -bond_type[i][n]; n = bondfind(i,shake_atom[i][0],shake_atom[i][3]); if (n >= 0) bond_type[i][n] = -bond_type[i][n]; } } // ----------------------------------------------------- // print info on SHAKE clusters // ----------------------------------------------------- int count1,count2,count3,count4; count1 = count2 = count3 = count4 = 0; for (i = 0; i < nlocal; i++) { if (shake_flag[i] == 1) count1++; else if (shake_flag[i] == 2) count2++; else if (shake_flag[i] == 3) count3++; else if (shake_flag[i] == 4) count4++; } int tmp; tmp = count1; MPI_Allreduce(&tmp,&count1,1,MPI_INT,MPI_SUM,world); tmp = count2; MPI_Allreduce(&tmp,&count2,1,MPI_INT,MPI_SUM,world); tmp = count3; MPI_Allreduce(&tmp,&count3,1,MPI_INT,MPI_SUM,world); tmp = count4; MPI_Allreduce(&tmp,&count4,1,MPI_INT,MPI_SUM,world); if (me == 0) { if (screen) { fprintf(screen," %d = # of size 2 clusters\n",count2/2); fprintf(screen," %d = # of size 3 clusters\n",count3/3); fprintf(screen," %d = # of size 4 clusters\n",count4/4); fprintf(screen," %d = # of frozen angles\n",count1/3); } if (logfile) { fprintf(logfile," %d = # of size 2 clusters\n",count2/2); fprintf(logfile," %d = # of size 3 clusters\n",count3/3); fprintf(logfile," %d = # of size 4 clusters\n",count4/4); fprintf(logfile," %d = # of frozen angles\n",count1/3); } } } /* ---------------------------------------------------------------------- check if massone is within MASSDELTA of any mass in mass_list return 1 if yes, 0 if not ------------------------------------------------------------------------- */ int FixShake::masscheck(double massone) { for (int i = 0; i < nmass; i++) if (fabs(mass_list[i]-massone) <= MASSDELTA) return 1; return 0; } /* ---------------------------------------------------------------------- update the unconstrained position of each atom only for SHAKE clusters, else set to 0.0 assumes NVE update, seems to be accurate enough for NVT,NPT,NPH as well ------------------------------------------------------------------------- */ void FixShake::unconstrained_update() { double dtfmsq; if (rmass) { for (int i = 0; i < nlocal; i++) { if (shake_flag[i]) { dtfmsq = dtfsq / rmass[i]; xshake[i][0] = x[i][0] + dtv*v[i][0] + dtfmsq*f[i][0]; xshake[i][1] = x[i][1] + dtv*v[i][1] + dtfmsq*f[i][1]; xshake[i][2] = x[i][2] + dtv*v[i][2] + dtfmsq*f[i][2]; } else xshake[i][2] = xshake[i][1] = xshake[i][0] = 0.0; } } else { for (int i = 0; i < nlocal; i++) { if (shake_flag[i]) { dtfmsq = dtfsq / mass[type[i]]; xshake[i][0] = x[i][0] + dtv*v[i][0] + dtfmsq*f[i][0]; xshake[i][1] = x[i][1] + dtv*v[i][1] + dtfmsq*f[i][1]; xshake[i][2] = x[i][2] + dtv*v[i][2] + dtfmsq*f[i][2]; } else xshake[i][2] = xshake[i][1] = xshake[i][0] = 0.0; } } } /* ---------------------------------------------------------------------- update the unconstrained position of each atom in a rRESPA step only for SHAKE clusters, else set to 0.0 assumes NVE update, seems to be accurate enough for NVT,NPT,NPH as well ------------------------------------------------------------------------- */ void FixShake::unconstrained_update_respa(int ilevel) { // xshake = atom coords after next x update in innermost loop // depends on rRESPA level // for levels > 0 this includes more than one velocity update // xshake = predicted position from call to this routine at level N = // x + dt0 (v + dtN/m fN + 1/2 dt(N-1)/m f(N-1) + ... + 1/2 dt0/m f0) // also set dtfsq = dt0*dtN so that shake2,shake3,etc can use it double ***f_level = ((FixRespa *) modify->fix[ifix_respa])->f_level; dtfsq = dtf_inner * step_respa[ilevel]; double invmass,dtfmsq; int jlevel; if (rmass) { for (int i = 0; i < nlocal; i++) { if (shake_flag[i]) { invmass = 1.0 / rmass[i]; dtfmsq = dtfsq * invmass; xshake[i][0] = x[i][0] + dtv*v[i][0] + dtfmsq*f[i][0]; xshake[i][1] = x[i][1] + dtv*v[i][1] + dtfmsq*f[i][1]; xshake[i][2] = x[i][2] + dtv*v[i][2] + dtfmsq*f[i][2]; for (jlevel = 0; jlevel < ilevel; jlevel++) { dtfmsq = dtf_innerhalf * step_respa[jlevel] * invmass; xshake[i][0] += dtfmsq*f_level[i][jlevel][0]; xshake[i][1] += dtfmsq*f_level[i][jlevel][1]; xshake[i][2] += dtfmsq*f_level[i][jlevel][2]; } } else xshake[i][2] = xshake[i][1] = xshake[i][0] = 0.0; } } else { for (int i = 0; i < nlocal; i++) { if (shake_flag[i]) { invmass = 1.0 / mass[type[i]]; dtfmsq = dtfsq * invmass; xshake[i][0] = x[i][0] + dtv*v[i][0] + dtfmsq*f[i][0]; xshake[i][1] = x[i][1] + dtv*v[i][1] + dtfmsq*f[i][1]; xshake[i][2] = x[i][2] + dtv*v[i][2] + dtfmsq*f[i][2]; for (jlevel = 0; jlevel < ilevel; jlevel++) { dtfmsq = dtf_innerhalf * step_respa[jlevel] * invmass; xshake[i][0] += dtfmsq*f_level[i][jlevel][0]; xshake[i][1] += dtfmsq*f_level[i][jlevel][1]; xshake[i][2] += dtfmsq*f_level[i][jlevel][2]; } } else xshake[i][2] = xshake[i][1] = xshake[i][0] = 0.0; } } } /* ---------------------------------------------------------------------- */ void FixShake::shake2(int m) { int nlist,list[2]; double v[6]; double invmass0,invmass1; // local atom IDs and constraint distances int i0 = atom->map(shake_atom[m][0]); int i1 = atom->map(shake_atom[m][1]); double bond1 = bond_distance[shake_type[m][0]]; // r01 = distance vec between atoms, with PBC double r01[3]; r01[0] = x[i0][0] - x[i1][0]; r01[1] = x[i0][1] - x[i1][1]; r01[2] = x[i0][2] - x[i1][2]; domain->minimum_image(r01); // s01 = distance vec after unconstrained update, with PBC double s01[3]; s01[0] = xshake[i0][0] - xshake[i1][0]; s01[1] = xshake[i0][1] - xshake[i1][1]; s01[2] = xshake[i0][2] - xshake[i1][2]; domain->minimum_image(s01); // scalar distances between atoms double r01sq = r01[0]*r01[0] + r01[1]*r01[1] + r01[2]*r01[2]; double s01sq = s01[0]*s01[0] + s01[1]*s01[1] + s01[2]*s01[2]; // a,b,c = coeffs in quadratic equation for lamda if (rmass) { invmass0 = 1.0/rmass[i0]; invmass1 = 1.0/rmass[i1]; } else { invmass0 = 1.0/mass[type[i0]]; invmass1 = 1.0/mass[type[i1]]; } double a = (invmass0+invmass1)*(invmass0+invmass1) * r01sq; double b = 2.0 * (invmass0+invmass1) * (s01[0]*r01[0] + s01[1]*r01[1] + s01[2]*r01[2]); double c = s01sq - bond1*bond1; // error check double determ = b*b - 4.0*a*c; if (determ < 0.0) { error->warning("Shake determinant < 0.0",0); determ = 0.0; } // exact quadratic solution for lamda double lamda,lamda1,lamda2; lamda1 = (-b+sqrt(determ)) / (2.0*a); lamda2 = (-b-sqrt(determ)) / (2.0*a); if (fabs(lamda1) <= fabs(lamda2)) lamda = lamda1; else lamda = lamda2; // update forces if atom is owned by this processor lamda /= dtfsq; if (i0 < nlocal) { f[i0][0] += lamda*r01[0]; f[i0][1] += lamda*r01[1]; f[i0][2] += lamda*r01[2]; } if (i1 < nlocal) { f[i1][0] -= lamda*r01[0]; f[i1][1] -= lamda*r01[1]; f[i1][2] -= lamda*r01[2]; } if (evflag) { nlist = 0; if (i0 < nlocal) list[nlist++] = i0; if (i1 < nlocal) list[nlist++] = i1; v[0] = lamda*r01[0]*r01[0]; v[1] = lamda*r01[1]*r01[1]; v[2] = lamda*r01[2]*r01[2]; v[3] = lamda*r01[0]*r01[1]; v[4] = lamda*r01[0]*r01[2]; v[5] = lamda*r01[1]*r01[2]; v_tally(nlist,list,2.0,v); } } /* ---------------------------------------------------------------------- */ void FixShake::shake3(int m) { int nlist,list[3]; double v[6]; double invmass0,invmass1,invmass2; // local atom IDs and constraint distances int i0 = atom->map(shake_atom[m][0]); int i1 = atom->map(shake_atom[m][1]); int i2 = atom->map(shake_atom[m][2]); double bond1 = bond_distance[shake_type[m][0]]; double bond2 = bond_distance[shake_type[m][1]]; // r01,r02 = distance vec between atoms, with PBC double r01[3]; r01[0] = x[i0][0] - x[i1][0]; r01[1] = x[i0][1] - x[i1][1]; r01[2] = x[i0][2] - x[i1][2]; domain->minimum_image(r01); double r02[3]; r02[0] = x[i0][0] - x[i2][0]; r02[1] = x[i0][1] - x[i2][1]; r02[2] = x[i0][2] - x[i2][2]; domain->minimum_image(r02); // s01,s02 = distance vec after unconstrained update, with PBC double s01[3]; s01[0] = xshake[i0][0] - xshake[i1][0]; s01[1] = xshake[i0][1] - xshake[i1][1]; s01[2] = xshake[i0][2] - xshake[i1][2]; domain->minimum_image(s01); double s02[3]; s02[0] = xshake[i0][0] - xshake[i2][0]; s02[1] = xshake[i0][1] - xshake[i2][1]; s02[2] = xshake[i0][2] - xshake[i2][2]; domain->minimum_image(s02); // scalar distances between atoms double r01sq = r01[0]*r01[0] + r01[1]*r01[1] + r01[2]*r01[2]; double r02sq = r02[0]*r02[0] + r02[1]*r02[1] + r02[2]*r02[2]; double s01sq = s01[0]*s01[0] + s01[1]*s01[1] + s01[2]*s01[2]; double s02sq = s02[0]*s02[0] + s02[1]*s02[1] + s02[2]*s02[2]; // matrix coeffs and rhs for lamda equations if (rmass) { invmass0 = 1.0/rmass[i0]; invmass1 = 1.0/rmass[i1]; invmass2 = 1.0/rmass[i2]; } else { invmass0 = 1.0/mass[type[i0]]; invmass1 = 1.0/mass[type[i1]]; invmass2 = 1.0/mass[type[i2]]; } double a11 = 2.0 * (invmass0+invmass1) * (s01[0]*r01[0] + s01[1]*r01[1] + s01[2]*r01[2]); double a12 = 2.0 * invmass0 * (s01[0]*r02[0] + s01[1]*r02[1] + s01[2]*r02[2]); double a21 = 2.0 * invmass0 * (s02[0]*r01[0] + s02[1]*r01[1] + s02[2]*r01[2]); double a22 = 2.0 * (invmass0+invmass2) * (s02[0]*r02[0] + s02[1]*r02[1] + s02[2]*r02[2]); // inverse of matrix double determ = a11*a22 - a12*a21; if (determ == 0.0) error->one("Shake determinant = 0.0"); double determinv = 1.0/determ; double a11inv = a22*determinv; double a12inv = -a12*determinv; double a21inv = -a21*determinv; double a22inv = a11*determinv; // quadratic correction coeffs double r0102 = (r01[0]*r02[0] + r01[1]*r02[1] + r01[2]*r02[2]); double quad1_0101 = (invmass0+invmass1)*(invmass0+invmass1) * r01sq; double quad1_0202 = invmass0*invmass0 * r02sq; double quad1_0102 = 2.0 * (invmass0+invmass1)*invmass0 * r0102; double quad2_0202 = (invmass0+invmass2)*(invmass0+invmass2) * r02sq; double quad2_0101 = invmass0*invmass0 * r01sq; double quad2_0102 = 2.0 * (invmass0+invmass2)*invmass0 * r0102; // iterate until converged double lamda01 = 0.0; double lamda02 = 0.0; int niter = 0; int done = 0; double quad1,quad2,b1,b2,lamda01_new,lamda02_new; while (!done && niter < max_iter) { quad1 = quad1_0101 * lamda01*lamda01 + quad1_0202 * lamda02*lamda02 + quad1_0102 * lamda01*lamda02; quad2 = quad2_0101 * lamda01*lamda01 + quad2_0202 * lamda02*lamda02 + quad2_0102 * lamda01*lamda02; b1 = bond1*bond1 - s01sq - quad1; b2 = bond2*bond2 - s02sq - quad2; lamda01_new = a11inv*b1 + a12inv*b2; lamda02_new = a21inv*b1 + a22inv*b2; done = 1; if (fabs(lamda01_new-lamda01) > tolerance) done = 0; if (fabs(lamda02_new-lamda02) > tolerance) done = 0; lamda01 = lamda01_new; lamda02 = lamda02_new; niter++; } // update forces if atom is owned by this processor lamda01 = lamda01/dtfsq; lamda02 = lamda02/dtfsq; if (i0 < nlocal) { f[i0][0] += lamda01*r01[0] + lamda02*r02[0]; f[i0][1] += lamda01*r01[1] + lamda02*r02[1]; f[i0][2] += lamda01*r01[2] + lamda02*r02[2]; } if (i1 < nlocal) { f[i1][0] -= lamda01*r01[0]; f[i1][1] -= lamda01*r01[1]; f[i1][2] -= lamda01*r01[2]; } if (i2 < nlocal) { f[i2][0] -= lamda02*r02[0]; f[i2][1] -= lamda02*r02[1]; f[i2][2] -= lamda02*r02[2]; } if (evflag) { nlist = 0; if (i0 < nlocal) list[nlist++] = i0; if (i1 < nlocal) list[nlist++] = i1; if (i2 < nlocal) list[nlist++] = i2; v[0] = lamda01*r01[0]*r01[0] + lamda02*r02[0]*r02[0]; v[1] = lamda01*r01[1]*r01[1] + lamda02*r02[1]*r02[1]; v[2] = lamda01*r01[2]*r01[2] + lamda02*r02[2]*r02[2]; v[3] = lamda01*r01[0]*r01[1] + lamda02*r02[0]*r02[1]; v[4] = lamda01*r01[0]*r01[2] + lamda02*r02[0]*r02[2]; v[5] = lamda01*r01[1]*r01[2] + lamda02*r02[1]*r02[2]; v_tally(nlist,list,3.0,v); } } /* ---------------------------------------------------------------------- */ void FixShake::shake4(int m) { int nlist,list[4]; double v[6]; double invmass0,invmass1,invmass2,invmass3; // local atom IDs and constraint distances int i0 = atom->map(shake_atom[m][0]); int i1 = atom->map(shake_atom[m][1]); int i2 = atom->map(shake_atom[m][2]); int i3 = atom->map(shake_atom[m][3]); double bond1 = bond_distance[shake_type[m][0]]; double bond2 = bond_distance[shake_type[m][1]]; double bond3 = bond_distance[shake_type[m][2]]; // r01,r02,r03 = distance vec between atoms, with PBC double r01[3]; r01[0] = x[i0][0] - x[i1][0]; r01[1] = x[i0][1] - x[i1][1]; r01[2] = x[i0][2] - x[i1][2]; domain->minimum_image(r01); double r02[3]; r02[0] = x[i0][0] - x[i2][0]; r02[1] = x[i0][1] - x[i2][1]; r02[2] = x[i0][2] - x[i2][2]; domain->minimum_image(r02); double r03[3]; r03[0] = x[i0][0] - x[i3][0]; r03[1] = x[i0][1] - x[i3][1]; r03[2] = x[i0][2] - x[i3][2]; domain->minimum_image(r03); // s01,s02,s03 = distance vec after unconstrained update, with PBC double s01[3]; s01[0] = xshake[i0][0] - xshake[i1][0]; s01[1] = xshake[i0][1] - xshake[i1][1]; s01[2] = xshake[i0][2] - xshake[i1][2]; domain->minimum_image(s01); double s02[3]; s02[0] = xshake[i0][0] - xshake[i2][0]; s02[1] = xshake[i0][1] - xshake[i2][1]; s02[2] = xshake[i0][2] - xshake[i2][2]; domain->minimum_image(s02); double s03[3]; s03[0] = xshake[i0][0] - xshake[i3][0]; s03[1] = xshake[i0][1] - xshake[i3][1]; s03[2] = xshake[i0][2] - xshake[i3][2]; domain->minimum_image(s03); // scalar distances between atoms double r01sq = r01[0]*r01[0] + r01[1]*r01[1] + r01[2]*r01[2]; double r02sq = r02[0]*r02[0] + r02[1]*r02[1] + r02[2]*r02[2]; double r03sq = r03[0]*r03[0] + r03[1]*r03[1] + r03[2]*r03[2]; double s01sq = s01[0]*s01[0] + s01[1]*s01[1] + s01[2]*s01[2]; double s02sq = s02[0]*s02[0] + s02[1]*s02[1] + s02[2]*s02[2]; double s03sq = s03[0]*s03[0] + s03[1]*s03[1] + s03[2]*s03[2]; // matrix coeffs and rhs for lamda equations if (rmass) { invmass0 = 1.0/rmass[i0]; invmass1 = 1.0/rmass[i1]; invmass2 = 1.0/rmass[i2]; invmass3 = 1.0/rmass[i3]; } else { invmass0 = 1.0/mass[type[i0]]; invmass1 = 1.0/mass[type[i1]]; invmass2 = 1.0/mass[type[i2]]; invmass3 = 1.0/mass[type[i3]]; } double a11 = 2.0 * (invmass0+invmass1) * (s01[0]*r01[0] + s01[1]*r01[1] + s01[2]*r01[2]); double a12 = 2.0 * invmass0 * (s01[0]*r02[0] + s01[1]*r02[1] + s01[2]*r02[2]); double a13 = 2.0 * invmass0 * (s01[0]*r03[0] + s01[1]*r03[1] + s01[2]*r03[2]); double a21 = 2.0 * invmass0 * (s02[0]*r01[0] + s02[1]*r01[1] + s02[2]*r01[2]); double a22 = 2.0 * (invmass0+invmass2) * (s02[0]*r02[0] + s02[1]*r02[1] + s02[2]*r02[2]); double a23 = 2.0 * invmass0 * (s02[0]*r03[0] + s02[1]*r03[1] + s02[2]*r03[2]); double a31 = 2.0 * invmass0 * (s03[0]*r01[0] + s03[1]*r01[1] + s03[2]*r01[2]); double a32 = 2.0 * invmass0 * (s03[0]*r02[0] + s03[1]*r02[1] + s03[2]*r02[2]); double a33 = 2.0 * (invmass0+invmass3) * (s03[0]*r03[0] + s03[1]*r03[1] + s03[2]*r03[2]); // inverse of matrix; double determ = a11*a22*a33 + a12*a23*a31 + a13*a21*a32 - a11*a23*a32 - a12*a21*a33 - a13*a22*a31; if (determ == 0.0) error->one("Shake determinant = 0.0"); double determinv = 1.0/determ; double a11inv = determinv * (a22*a33 - a23*a32); double a12inv = -determinv * (a12*a33 - a13*a32); double a13inv = determinv * (a12*a23 - a13*a22); double a21inv = -determinv * (a21*a33 - a23*a31); double a22inv = determinv * (a11*a33 - a13*a31); double a23inv = -determinv * (a11*a23 - a13*a21); double a31inv = determinv * (a21*a32 - a22*a31); double a32inv = -determinv * (a11*a32 - a12*a31); double a33inv = determinv * (a11*a22 - a12*a21); // quadratic correction coeffs double r0102 = (r01[0]*r02[0] + r01[1]*r02[1] + r01[2]*r02[2]); double r0103 = (r01[0]*r03[0] + r01[1]*r03[1] + r01[2]*r03[2]); double r0203 = (r02[0]*r03[0] + r02[1]*r03[1] + r02[2]*r03[2]); double quad1_0101 = (invmass0+invmass1)*(invmass0+invmass1) * r01sq; double quad1_0202 = invmass0*invmass0 * r02sq; double quad1_0303 = invmass0*invmass0 * r03sq; double quad1_0102 = 2.0 * (invmass0+invmass1)*invmass0 * r0102; double quad1_0103 = 2.0 * (invmass0+invmass1)*invmass0 * r0103; double quad1_0203 = 2.0 * invmass0*invmass0 * r0203; double quad2_0101 = invmass0*invmass0 * r01sq; double quad2_0202 = (invmass0+invmass2)*(invmass0+invmass2) * r02sq; double quad2_0303 = invmass0*invmass0 * r03sq; double quad2_0102 = 2.0 * (invmass0+invmass2)*invmass0 * r0102; double quad2_0103 = 2.0 * invmass0*invmass0 * r0103; double quad2_0203 = 2.0 * (invmass0+invmass2)*invmass0 * r0203; double quad3_0101 = invmass0*invmass0 * r01sq; double quad3_0202 = invmass0*invmass0 * r02sq; double quad3_0303 = (invmass0+invmass3)*(invmass0+invmass3) * r03sq; double quad3_0102 = 2.0 * invmass0*invmass0 * r0102; double quad3_0103 = 2.0 * (invmass0+invmass3)*invmass0 * r0103; double quad3_0203 = 2.0 * (invmass0+invmass3)*invmass0 * r0203; // iterate until converged double lamda01 = 0.0; double lamda02 = 0.0; double lamda03 = 0.0; int niter = 0; int done = 0; double quad1,quad2,quad3,b1,b2,b3,lamda01_new,lamda02_new,lamda03_new; while (!done && niter < max_iter) { quad1 = quad1_0101 * lamda01*lamda01 + quad1_0202 * lamda02*lamda02 + quad1_0303 * lamda03*lamda03 + quad1_0102 * lamda01*lamda02 + quad1_0103 * lamda01*lamda03 + quad1_0203 * lamda02*lamda03; quad2 = quad2_0101 * lamda01*lamda01 + quad2_0202 * lamda02*lamda02 + quad2_0303 * lamda03*lamda03 + quad2_0102 * lamda01*lamda02 + quad2_0103 * lamda01*lamda03 + quad2_0203 * lamda02*lamda03; quad3 = quad3_0101 * lamda01*lamda01 + quad3_0202 * lamda02*lamda02 + quad3_0303 * lamda03*lamda03 + quad3_0102 * lamda01*lamda02 + quad3_0103 * lamda01*lamda03 + quad3_0203 * lamda02*lamda03; b1 = bond1*bond1 - s01sq - quad1; b2 = bond2*bond2 - s02sq - quad2; b3 = bond3*bond3 - s03sq - quad3; lamda01_new = a11inv*b1 + a12inv*b2 + a13inv*b3; lamda02_new = a21inv*b1 + a22inv*b2 + a23inv*b3; lamda03_new = a31inv*b1 + a32inv*b2 + a33inv*b3; done = 1; if (fabs(lamda01_new-lamda01) > tolerance) done = 0; if (fabs(lamda02_new-lamda02) > tolerance) done = 0; if (fabs(lamda03_new-lamda03) > tolerance) done = 0; lamda01 = lamda01_new; lamda02 = lamda02_new; lamda03 = lamda03_new; niter++; } // update forces if atom is owned by this processor lamda01 = lamda01/dtfsq; lamda02 = lamda02/dtfsq; lamda03 = lamda03/dtfsq; if (i0 < nlocal) { f[i0][0] += lamda01*r01[0] + lamda02*r02[0] + lamda03*r03[0]; f[i0][1] += lamda01*r01[1] + lamda02*r02[1] + lamda03*r03[1]; f[i0][2] += lamda01*r01[2] + lamda02*r02[2] + lamda03*r03[2]; } if (i1 < nlocal) { f[i1][0] -= lamda01*r01[0]; f[i1][1] -= lamda01*r01[1]; f[i1][2] -= lamda01*r01[2]; } if (i2 < nlocal) { f[i2][0] -= lamda02*r02[0]; f[i2][1] -= lamda02*r02[1]; f[i2][2] -= lamda02*r02[2]; } if (i3 < nlocal) { f[i3][0] -= lamda03*r03[0]; f[i3][1] -= lamda03*r03[1]; f[i3][2] -= lamda03*r03[2]; } if (evflag) { nlist = 0; if (i0 < nlocal) list[nlist++] = i0; if (i1 < nlocal) list[nlist++] = i1; if (i2 < nlocal) list[nlist++] = i2; if (i3 < nlocal) list[nlist++] = i3; v[0] = lamda01*r01[0]*r01[0]+lamda02*r02[0]*r02[0]+lamda03*r03[0]*r03[0]; v[1] = lamda01*r01[1]*r01[1]+lamda02*r02[1]*r02[1]+lamda03*r03[1]*r03[1]; v[2] = lamda01*r01[2]*r01[2]+lamda02*r02[2]*r02[2]+lamda03*r03[2]*r03[2]; v[3] = lamda01*r01[0]*r01[1]+lamda02*r02[0]*r02[1]+lamda03*r03[0]*r03[1]; v[4] = lamda01*r01[0]*r01[2]+lamda02*r02[0]*r02[2]+lamda03*r03[0]*r03[2]; v[5] = lamda01*r01[1]*r01[2]+lamda02*r02[1]*r02[2]+lamda03*r03[1]*r03[2]; v_tally(nlist,list,4.0,v); } } /* ---------------------------------------------------------------------- */ void FixShake::shake3angle(int m) { int nlist,list[3]; double v[6]; double invmass0,invmass1,invmass2; // local atom IDs and constraint distances int i0 = atom->map(shake_atom[m][0]); int i1 = atom->map(shake_atom[m][1]); int i2 = atom->map(shake_atom[m][2]); double bond1 = bond_distance[shake_type[m][0]]; double bond2 = bond_distance[shake_type[m][1]]; double bond12 = angle_distance[shake_type[m][2]]; // r01,r02,r12 = distance vec between atoms, with PBC double r01[3]; r01[0] = x[i0][0] - x[i1][0]; r01[1] = x[i0][1] - x[i1][1]; r01[2] = x[i0][2] - x[i1][2]; domain->minimum_image(r01); double r02[3]; r02[0] = x[i0][0] - x[i2][0]; r02[1] = x[i0][1] - x[i2][1]; r02[2] = x[i0][2] - x[i2][2]; domain->minimum_image(r02); double r12[3]; r12[0] = x[i1][0] - x[i2][0]; r12[1] = x[i1][1] - x[i2][1]; r12[2] = x[i1][2] - x[i2][2]; domain->minimum_image(r12); // s01,s02,s12 = distance vec after unconstrained update, with PBC double s01[3]; s01[0] = xshake[i0][0] - xshake[i1][0]; s01[1] = xshake[i0][1] - xshake[i1][1]; s01[2] = xshake[i0][2] - xshake[i1][2]; domain->minimum_image(s01); double s02[3]; s02[0] = xshake[i0][0] - xshake[i2][0]; s02[1] = xshake[i0][1] - xshake[i2][1]; s02[2] = xshake[i0][2] - xshake[i2][2]; domain->minimum_image(s02); double s12[3]; s12[0] = xshake[i1][0] - xshake[i2][0]; s12[1] = xshake[i1][1] - xshake[i2][1]; s12[2] = xshake[i1][2] - xshake[i2][2]; domain->minimum_image(s12); // scalar distances between atoms double r01sq = r01[0]*r01[0] + r01[1]*r01[1] + r01[2]*r01[2]; double r02sq = r02[0]*r02[0] + r02[1]*r02[1] + r02[2]*r02[2]; double r12sq = r12[0]*r12[0] + r12[1]*r12[1] + r12[2]*r12[2]; double s01sq = s01[0]*s01[0] + s01[1]*s01[1] + s01[2]*s01[2]; double s02sq = s02[0]*s02[0] + s02[1]*s02[1] + s02[2]*s02[2]; double s12sq = s12[0]*s12[0] + s12[1]*s12[1] + s12[2]*s12[2]; // matrix coeffs and rhs for lamda equations if (rmass) { invmass0 = 1.0/rmass[i0]; invmass1 = 1.0/rmass[i1]; invmass2 = 1.0/rmass[i2]; } else { invmass0 = 1.0/mass[type[i0]]; invmass1 = 1.0/mass[type[i1]]; invmass2 = 1.0/mass[type[i2]]; } double a11 = 2.0 * (invmass0+invmass1) * (s01[0]*r01[0] + s01[1]*r01[1] + s01[2]*r01[2]); double a12 = 2.0 * invmass0 * (s01[0]*r02[0] + s01[1]*r02[1] + s01[2]*r02[2]); double a13 = - 2.0 * invmass1 * (s01[0]*r12[0] + s01[1]*r12[1] + s01[2]*r12[2]); double a21 = 2.0 * invmass0 * (s02[0]*r01[0] + s02[1]*r01[1] + s02[2]*r01[2]); double a22 = 2.0 * (invmass0+invmass2) * (s02[0]*r02[0] + s02[1]*r02[1] + s02[2]*r02[2]); double a23 = 2.0 * invmass2 * (s02[0]*r12[0] + s02[1]*r12[1] + s02[2]*r12[2]); double a31 = - 2.0 * invmass1 * (s12[0]*r01[0] + s12[1]*r01[1] + s12[2]*r01[2]); double a32 = 2.0 * invmass2 * (s12[0]*r02[0] + s12[1]*r02[1] + s12[2]*r02[2]); double a33 = 2.0 * (invmass1+invmass2) * (s12[0]*r12[0] + s12[1]*r12[1] + s12[2]*r12[2]); // inverse of matrix double determ = a11*a22*a33 + a12*a23*a31 + a13*a21*a32 - a11*a23*a32 - a12*a21*a33 - a13*a22*a31; if (determ == 0.0) error->one("Shake determinant = 0.0"); double determinv = 1.0/determ; double a11inv = determinv * (a22*a33 - a23*a32); double a12inv = -determinv * (a12*a33 - a13*a32); double a13inv = determinv * (a12*a23 - a13*a22); double a21inv = -determinv * (a21*a33 - a23*a31); double a22inv = determinv * (a11*a33 - a13*a31); double a23inv = -determinv * (a11*a23 - a13*a21); double a31inv = determinv * (a21*a32 - a22*a31); double a32inv = -determinv * (a11*a32 - a12*a31); double a33inv = determinv * (a11*a22 - a12*a21); // quadratic correction coeffs double r0102 = (r01[0]*r02[0] + r01[1]*r02[1] + r01[2]*r02[2]); double r0112 = (r01[0]*r12[0] + r01[1]*r12[1] + r01[2]*r12[2]); double r0212 = (r02[0]*r12[0] + r02[1]*r12[1] + r02[2]*r12[2]); double quad1_0101 = (invmass0+invmass1)*(invmass0+invmass1) * r01sq; double quad1_0202 = invmass0*invmass0 * r02sq; double quad1_1212 = invmass1*invmass1 * r12sq; double quad1_0102 = 2.0 * (invmass0+invmass1)*invmass0 * r0102; double quad1_0112 = - 2.0 * (invmass0+invmass1)*invmass1 * r0112; double quad1_0212 = - 2.0 * invmass0*invmass1 * r0212; double quad2_0101 = invmass0*invmass0 * r01sq; double quad2_0202 = (invmass0+invmass2)*(invmass0+invmass2) * r02sq; double quad2_1212 = invmass2*invmass2 * r12sq; double quad2_0102 = 2.0 * (invmass0+invmass2)*invmass0 * r0102; double quad2_0112 = 2.0 * invmass0*invmass2 * r0112; double quad2_0212 = 2.0 * (invmass0+invmass2)*invmass2 * r0212; double quad3_0101 = invmass1*invmass1 * r01sq; double quad3_0202 = invmass2*invmass2 * r02sq; double quad3_1212 = (invmass1+invmass2)*(invmass1+invmass2) * r12sq; double quad3_0102 = - 2.0 * invmass1*invmass2 * r0102; double quad3_0112 = - 2.0 * (invmass1+invmass2)*invmass1 * r0112; double quad3_0212 = 2.0 * (invmass1+invmass2)*invmass2 * r0212; // iterate until converged double lamda01 = 0.0; double lamda02 = 0.0; double lamda12 = 0.0; int niter = 0; int done = 0; double quad1,quad2,quad3,b1,b2,b3,lamda01_new,lamda02_new,lamda12_new; while (!done && niter < max_iter) { quad1 = quad1_0101 * lamda01*lamda01 + quad1_0202 * lamda02*lamda02 + quad1_1212 * lamda12*lamda12 + quad1_0102 * lamda01*lamda02 + quad1_0112 * lamda01*lamda12 + quad1_0212 * lamda02*lamda12; quad2 = quad2_0101 * lamda01*lamda01 + quad2_0202 * lamda02*lamda02 + quad2_1212 * lamda12*lamda12 + quad2_0102 * lamda01*lamda02 + quad2_0112 * lamda01*lamda12 + quad2_0212 * lamda02*lamda12; quad3 = quad3_0101 * lamda01*lamda01 + quad3_0202 * lamda02*lamda02 + quad3_1212 * lamda12*lamda12 + quad3_0102 * lamda01*lamda02 + quad3_0112 * lamda01*lamda12 + quad3_0212 * lamda02*lamda12; b1 = bond1*bond1 - s01sq - quad1; b2 = bond2*bond2 - s02sq - quad2; b3 = bond12*bond12 - s12sq - quad3; lamda01_new = a11inv*b1 + a12inv*b2 + a13inv*b3; lamda02_new = a21inv*b1 + a22inv*b2 + a23inv*b3; lamda12_new = a31inv*b1 + a32inv*b2 + a33inv*b3; done = 1; if (fabs(lamda01_new-lamda01) > tolerance) done = 0; if (fabs(lamda02_new-lamda02) > tolerance) done = 0; if (fabs(lamda12_new-lamda12) > tolerance) done = 0; lamda01 = lamda01_new; lamda02 = lamda02_new; lamda12 = lamda12_new; niter++; } // update forces if atom is owned by this processor lamda01 = lamda01/dtfsq; lamda02 = lamda02/dtfsq; lamda12 = lamda12/dtfsq; if (i0 < nlocal) { f[i0][0] += lamda01*r01[0] + lamda02*r02[0]; f[i0][1] += lamda01*r01[1] + lamda02*r02[1]; f[i0][2] += lamda01*r01[2] + lamda02*r02[2]; } if (i1 < nlocal) { f[i1][0] -= lamda01*r01[0] - lamda12*r12[0]; f[i1][1] -= lamda01*r01[1] - lamda12*r12[1]; f[i1][2] -= lamda01*r01[2] - lamda12*r12[2]; } if (i2 < nlocal) { f[i2][0] -= lamda02*r02[0] + lamda12*r12[0]; f[i2][1] -= lamda02*r02[1] + lamda12*r12[1]; f[i2][2] -= lamda02*r02[2] + lamda12*r12[2]; } if (evflag) { nlist = 0; if (i0 < nlocal) list[nlist++] = i0; if (i1 < nlocal) list[nlist++] = i1; if (i2 < nlocal) list[nlist++] = i2; v[0] = lamda01*r01[0]*r01[0]+lamda02*r02[0]*r02[0]+lamda12*r12[0]*r12[0]; v[1] = lamda01*r01[1]*r01[1]+lamda02*r02[1]*r02[1]+lamda12*r12[1]*r12[1]; v[2] = lamda01*r01[2]*r01[2]+lamda02*r02[2]*r02[2]+lamda12*r12[2]*r12[2]; v[3] = lamda01*r01[0]*r01[1]+lamda02*r02[0]*r02[1]+lamda12*r12[0]*r12[1]; v[4] = lamda01*r01[0]*r01[2]+lamda02*r02[0]*r02[2]+lamda12*r12[0]*r12[2]; v[5] = lamda01*r01[1]*r01[2]+lamda02*r02[1]*r02[2]+lamda12*r12[1]*r12[2]; v_tally(nlist,list,3.0,v); } } /* ---------------------------------------------------------------------- print-out bond & angle statistics ------------------------------------------------------------------------- */ void FixShake::stats() { int i,j,m,n,iatom,jatom,katom; double delx,dely,delz; double r,r1,r2,r3,angle; // zero out accumulators int nb = atom->nbondtypes + 1; int na = atom->nangletypes + 1; for (i = 0; i < nb; i++) { b_count[i] = 0; b_ave[i] = b_max[i] = 0.0; b_min[i] = BIG; } for (i = 0; i < na; i++) { a_count[i] = 0; a_ave[i] = a_max[i] = 0.0; a_min[i] = BIG; } // log stats for each bond & angle // OK to double count since are just averaging double **x = atom->x; int nlocal = atom->nlocal; for (i = 0; i < nlocal; i++) { if (shake_flag[i] == 0) continue; // bond stats n = shake_flag[i]; if (n == 1) n = 3; iatom = atom->map(shake_atom[i][0]); for (j = 1; j < n; j++) { jatom = atom->map(shake_atom[i][j]); delx = x[iatom][0] - x[jatom][0]; dely = x[iatom][1] - x[jatom][1]; delz = x[iatom][2] - x[jatom][2]; domain->minimum_image(delx,dely,delz); r = sqrt(delx*delx + dely*dely + delz*delz); m = shake_type[i][j-1]; b_count[m]++; b_ave[m] += r; b_max[m] = MAX(b_max[m],r); b_min[m] = MIN(b_min[m],r); } // angle stats if (shake_flag[i] == 1) { iatom = atom->map(shake_atom[i][0]); jatom = atom->map(shake_atom[i][1]); katom = atom->map(shake_atom[i][2]); delx = x[iatom][0] - x[jatom][0]; dely = x[iatom][1] - x[jatom][1]; delz = x[iatom][2] - x[jatom][2]; domain->minimum_image(delx,dely,delz); r1 = sqrt(delx*delx + dely*dely + delz*delz); delx = x[iatom][0] - x[katom][0]; dely = x[iatom][1] - x[katom][1]; delz = x[iatom][2] - x[katom][2]; domain->minimum_image(delx,dely,delz); r2 = sqrt(delx*delx + dely*dely + delz*delz); delx = x[jatom][0] - x[katom][0]; dely = x[jatom][1] - x[katom][1]; delz = x[jatom][2] - x[katom][2]; domain->minimum_image(delx,dely,delz); r3 = sqrt(delx*delx + dely*dely + delz*delz); angle = acos((r1*r1 + r2*r2 - r3*r3) / (2.0*r1*r2)); angle *= 180.0/PI; m = shake_type[i][2]; a_count[m]++; a_ave[m] += angle; a_max[m] = MAX(a_max[m],angle); a_min[m] = MIN(a_min[m],angle); } } // sum across all procs MPI_Allreduce(b_count,b_count_all,nb,MPI_INT,MPI_SUM,world); MPI_Allreduce(b_ave,b_ave_all,nb,MPI_DOUBLE,MPI_SUM,world); MPI_Allreduce(b_max,b_max_all,nb,MPI_DOUBLE,MPI_MAX,world); MPI_Allreduce(b_min,b_min_all,nb,MPI_DOUBLE,MPI_MIN,world); MPI_Allreduce(a_count,a_count_all,na,MPI_INT,MPI_SUM,world); MPI_Allreduce(a_ave,a_ave_all,na,MPI_DOUBLE,MPI_SUM,world); MPI_Allreduce(a_max,a_max_all,na,MPI_DOUBLE,MPI_MAX,world); MPI_Allreduce(a_min,a_min_all,na,MPI_DOUBLE,MPI_MIN,world); // print stats only for non-zero counts if (me == 0) { + char fstr[64]; + sprintf(fstr,"SHAKE stats (type/ave/delta) on step %s\n",BIGINT_FORMAT); if (screen) { - fprintf(screen,"SHAKE stats (type/ave/delta) on step %d\n", - update->ntimestep); + fprintf(screen,fstr,update->ntimestep); for (i = 1; i < nb; i++) if (b_count_all[i]) fprintf(screen," %d %g %g\n",i, b_ave_all[i]/b_count_all[i],b_max_all[i]-b_min_all[i]); for (i = 1; i < na; i++) if (a_count_all[i]) fprintf(screen," %d %g %g\n",i, a_ave_all[i]/a_count_all[i],a_max_all[i]-a_min_all[i]); } if (logfile) { - fprintf(logfile,"SHAKE stats (type/ave/delta) on step %d\n", - update->ntimestep); + fprintf(logfile,fstr,update->ntimestep); for (i = 0; i < nb; i++) if (b_count_all[i]) fprintf(logfile," %d %g %g\n",i, b_ave_all[i]/b_count_all[i],b_max_all[i]-b_min_all[i]); for (i = 0; i < na; i++) if (a_count_all[i]) fprintf(logfile," %d %g %g\n",i, a_ave_all[i]/a_count_all[i],a_max_all[i]-a_min_all[i]); } } // next timestep for stats next_output += output_every; } /* ---------------------------------------------------------------------- find a bond between global tags n1 and n2 stored with local atom i return -1 if don't find it return bond index if do find it ------------------------------------------------------------------------- */ int FixShake::bondfind(int i, int n1, int n2) { int *tag = atom->tag; int **bond_atom = atom->bond_atom; int nbonds = atom->num_bond[i]; int m; for (m = 0; m < nbonds; m++) { if (n1 == tag[i] && n2 == bond_atom[i][m]) break; if (n1 == bond_atom[i][m] && n2 == tag[i]) break; } if (m < nbonds) return m; return -1; } /* ---------------------------------------------------------------------- find an angle with global end atoms n1 and n2 stored with local atom i return -1 if don't find it return angle index if do find it ------------------------------------------------------------------------- */ int FixShake::anglefind(int i, int n1, int n2) { int **angle_atom1 = atom->angle_atom1; int **angle_atom3 = atom->angle_atom3; int nangles = atom->num_angle[i]; int m; for (m = 0; m < nangles; m++) { if (n1 == angle_atom1[i][m] && n2 == angle_atom3[i][m]) break; if (n1 == angle_atom3[i][m] && n2 == angle_atom1[i][m]) break; } if (m < nangles) return m; return -1; } /* ---------------------------------------------------------------------- memory usage of local atom-based arrays ------------------------------------------------------------------------- */ double FixShake::memory_usage() { int nmax = atom->nmax; double bytes = nmax * sizeof(int); bytes += nmax*4 * sizeof(int); bytes += nmax*3 * sizeof(int); bytes += nmax*3 * sizeof(double); bytes += maxvatom*6 * sizeof(double); return bytes; } /* ---------------------------------------------------------------------- allocate local atom-based arrays ------------------------------------------------------------------------- */ void FixShake::grow_arrays(int nmax) { shake_flag = (int *) memory->srealloc(shake_flag,nmax*sizeof(int),"shake:shake_flag"); shake_atom = memory->grow_2d_int_array(shake_atom,nmax,4,"shake:shake_atom"); shake_type = memory->grow_2d_int_array(shake_type,nmax,3,"shake:shake_type"); memory->destroy_2d_double_array(xshake); xshake = memory->create_2d_double_array(nmax,3,"shake:xshake"); } /* ---------------------------------------------------------------------- copy values within local atom-based arrays ------------------------------------------------------------------------- */ void FixShake::copy_arrays(int i, int j) { int flag = shake_flag[j] = shake_flag[i]; if (flag == 1) { shake_atom[j][0] = shake_atom[i][0]; shake_atom[j][1] = shake_atom[i][1]; shake_atom[j][2] = shake_atom[i][2]; shake_type[j][0] = shake_type[i][0]; shake_type[j][1] = shake_type[i][1]; shake_type[j][2] = shake_type[i][2]; } else if (flag == 2) { shake_atom[j][0] = shake_atom[i][0]; shake_atom[j][1] = shake_atom[i][1]; shake_type[j][0] = shake_type[i][0]; } else if (flag == 3) { shake_atom[j][0] = shake_atom[i][0]; shake_atom[j][1] = shake_atom[i][1]; shake_atom[j][2] = shake_atom[i][2]; shake_type[j][0] = shake_type[i][0]; shake_type[j][1] = shake_type[i][1]; } else if (flag == 4) { shake_atom[j][0] = shake_atom[i][0]; shake_atom[j][1] = shake_atom[i][1]; shake_atom[j][2] = shake_atom[i][2]; shake_atom[j][3] = shake_atom[i][3]; shake_type[j][0] = shake_type[i][0]; shake_type[j][1] = shake_type[i][1]; shake_type[j][2] = shake_type[i][2]; } } /* ---------------------------------------------------------------------- initialize one atom's array values, called when atom is created ------------------------------------------------------------------------- */ void FixShake::set_arrays(int i) { shake_flag[i] = 0; } /* ---------------------------------------------------------------------- pack values in local atom-based arrays for exchange with another proc ------------------------------------------------------------------------- */ int FixShake::pack_exchange(int i, double *buf) { int m = 0; buf[m++] = shake_flag[i]; int flag = shake_flag[i]; if (flag == 1) { buf[m++] = shake_atom[i][0]; buf[m++] = shake_atom[i][1]; buf[m++] = shake_atom[i][2]; buf[m++] = shake_type[i][0]; buf[m++] = shake_type[i][1]; buf[m++] = shake_type[i][2]; } else if (flag == 2) { buf[m++] = shake_atom[i][0]; buf[m++] = shake_atom[i][1]; buf[m++] = shake_type[i][0]; } else if (flag == 3) { buf[m++] = shake_atom[i][0]; buf[m++] = shake_atom[i][1]; buf[m++] = shake_atom[i][2]; buf[m++] = shake_type[i][0]; buf[m++] = shake_type[i][1]; } else if (flag == 4) { buf[m++] = shake_atom[i][0]; buf[m++] = shake_atom[i][1]; buf[m++] = shake_atom[i][2]; buf[m++] = shake_atom[i][3]; buf[m++] = shake_type[i][0]; buf[m++] = shake_type[i][1]; buf[m++] = shake_type[i][2]; } return m; } /* ---------------------------------------------------------------------- unpack values in local atom-based arrays from exchange with another proc ------------------------------------------------------------------------- */ int FixShake::unpack_exchange(int nlocal, double *buf) { int m = 0; int flag = shake_flag[nlocal] = static_cast<int> (buf[m++]); if (flag == 1) { shake_atom[nlocal][0] = static_cast<int> (buf[m++]); shake_atom[nlocal][1] = static_cast<int> (buf[m++]); shake_atom[nlocal][2] = static_cast<int> (buf[m++]); shake_type[nlocal][0] = static_cast<int> (buf[m++]); shake_type[nlocal][1] = static_cast<int> (buf[m++]); shake_type[nlocal][2] = static_cast<int> (buf[m++]); } else if (flag == 2) { shake_atom[nlocal][0] = static_cast<int> (buf[m++]); shake_atom[nlocal][1] = static_cast<int> (buf[m++]); shake_type[nlocal][0] = static_cast<int> (buf[m++]); } else if (flag == 3) { shake_atom[nlocal][0] = static_cast<int> (buf[m++]); shake_atom[nlocal][1] = static_cast<int> (buf[m++]); shake_atom[nlocal][2] = static_cast<int> (buf[m++]); shake_type[nlocal][0] = static_cast<int> (buf[m++]); shake_type[nlocal][1] = static_cast<int> (buf[m++]); } else if (flag == 4) { shake_atom[nlocal][0] = static_cast<int> (buf[m++]); shake_atom[nlocal][1] = static_cast<int> (buf[m++]); shake_atom[nlocal][2] = static_cast<int> (buf[m++]); shake_atom[nlocal][3] = static_cast<int> (buf[m++]); shake_type[nlocal][0] = static_cast<int> (buf[m++]); shake_type[nlocal][1] = static_cast<int> (buf[m++]); shake_type[nlocal][2] = static_cast<int> (buf[m++]); } return m; } /* ---------------------------------------------------------------------- */ int FixShake::pack_comm(int n, int *list, double *buf, int pbc_flag, int *pbc) { int i,j,m; double dx,dy,dz; m = 0; if (pbc_flag == 0) { for (i = 0; i < n; i++) { j = list[i]; buf[m++] = xshake[j][0]; buf[m++] = xshake[j][1]; buf[m++] = xshake[j][2]; } } else { if (domain->triclinic == 0) { dx = pbc[0]*domain->xprd; dy = pbc[1]*domain->yprd; dz = pbc[2]*domain->zprd; } else { dx = pbc[0]*domain->xprd + pbc[5]*domain->xy + pbc[4]*domain->xz; dy = pbc[1]*domain->yprd + pbc[3]*domain->yz; dz = pbc[2]*domain->zprd; } for (i = 0; i < n; i++) { j = list[i]; buf[m++] = xshake[j][0] + dx; buf[m++] = xshake[j][1] + dy; buf[m++] = xshake[j][2] + dz; } } return 3; } /* ---------------------------------------------------------------------- */ void FixShake::unpack_comm(int n, int first, double *buf) { int i,m,last; m = 0; last = first + n; for (i = first; i < last; i++) { xshake[i][0] = buf[m++]; xshake[i][1] = buf[m++]; xshake[i][2] = buf[m++]; } } /* ---------------------------------------------------------------------- */ void FixShake::reset_dt() { if (strcmp(update->integrate_style,"verlet") == 0) { dtv = update->dt; dtfsq = update->dt * update->dt * force->ftm2v; } else { dtv = step_respa[0]; dtf_innerhalf = 0.5 * step_respa[0] * force->ftm2v; dtf_inner = step_respa[0] * force->ftm2v; } } diff --git a/src/fix_shake.h b/src/fix_shake.h index ebef049db..fc919aaa1 100644 --- a/src/fix_shake.h +++ b/src/fix_shake.h @@ -1,118 +1,119 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ #ifdef FIX_CLASS FixStyle(shake,FixShake) #else #ifndef LMP_FIX_SHAKE_H #define LMP_FIX_SHAKE_H #include "fix.h" +#include "lmptype.h" namespace LAMMPS_NS { class FixShake : public Fix { public: FixShake(class LAMMPS *, int, char **); ~FixShake(); int setmask(); void init(); void setup(int); void pre_neighbor(); void post_force(int); void post_force_respa(int, int, int); double memory_usage(); void grow_arrays(int); void copy_arrays(int, int); void set_arrays(int); int pack_exchange(int, double *); int unpack_exchange(int, double *); int pack_comm(int, int *, double *, int, int *); void unpack_comm(int, int, double *); int dof(int); void reset_dt(); private: int me,nprocs; double PI; double tolerance; // SHAKE tolerance int max_iter; // max # of SHAKE iterations int output_every; // SHAKE stat output every so often - int next_output; // timestep for next output + bigint next_output; // timestep for next output // settings from input command int *bond_flag,*angle_flag; // bond/angle types to constrain int *type_flag; // constrain bonds to these types double *mass_list; // constrain bonds to these masses int nmass; // # of masses in mass_list double *bond_distance,*angle_distance; // constraint distances int ifix_respa; // rRESPA fix needed by SHAKE int nlevels_respa; // copies of needed rRESPA variables int *loop_respa; double *step_respa; double **x,**v,**f; // local ptrs to atom class quantities double *mass,*rmass; int *type; int nlocal; // atom-based arrays int *shake_flag; // 0 if atom not in SHAKE cluster // 1 = size 3 angle cluster // 2,3,4 = size of bond-only cluster int **shake_atom; // global IDs of atoms in cluster // central atom is 1st // lowest global ID is 1st for size 2 int **shake_type; // bondtype of each bond in cluster // for angle cluster, 3rd value // is angletype double **xshake; // unconstrained atom coords int vflag; // virial flag double dtv,dtfsq; // timesteps for trial move double dtf_inner,dtf_innerhalf; // timesteps for rRESPA trial move int *list; // list of clusters to SHAKE int nlist,maxlist; // size and max-size of list // stat quantities int *b_count,*b_count_all; // counts for each bond type double *b_ave,*b_max,*b_min; // ave/max/min dist for each bond type double *b_ave_all,*b_max_all,*b_min_all; // MPI summing arrays int *a_count,*a_count_all; // ditto for angle types double *a_ave,*a_max,*a_min; double *a_ave_all,*a_max_all,*a_min_all; void find_clusters(); int masscheck(double); void unconstrained_update(); void unconstrained_update_respa(int); void shake2(int); void shake3(int); void shake4(int); void shake3angle(int); void stats(); int bondfind(int, int, int); int anglefind(int, int, int); }; } #endif #endif diff --git a/src/fix_tmd.cpp b/src/fix_tmd.cpp index 1dd6bb383..f976fd18e 100644 --- a/src/fix_tmd.cpp +++ b/src/fix_tmd.cpp @@ -1,559 +1,561 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- Contributing authors: Paul Crozier (SNL) Christian Burisch (Bochum Univeristy, Germany) ------------------------------------------------------------------------- */ #include "mpi.h" #include "math.h" #include "stdlib.h" #include "string.h" #include "fix_tmd.h" +#include "lmptype.h" #include "atom.h" #include "update.h" #include "modify.h" #include "domain.h" #include "group.h" #include "respa.h" #include "force.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; #define CHUNK 1000 #define MAXLINE 256 /* ---------------------------------------------------------------------- */ FixTMD::FixTMD(LAMMPS *lmp, int narg, char **arg) : Fix(lmp, narg, arg) { if (narg < 6) error->all("Illegal fix tmd command"); rho_stop = atof(arg[3]); nfileevery = atoi(arg[5]); if (rho_stop < 0 || nfileevery < 0) error->all("Illegal fix tmd command"); if (nfileevery && narg != 7) error->all("Illegal fix tmd command"); MPI_Comm_rank(world,&me); // perform initial allocation of atom-based arrays // register with Atom class xf = NULL; xold = NULL; grow_arrays(atom->nmax); atom->add_callback(0); // make sure an atom map exists before reading in target coordinates if (atom->map_style == 0) error->all("Cannot use fix TMD unless atom map exists"); // read from arg[4] and store coordinates of final target in xf readfile(arg[4]); // open arg[6] statistics file and write header if (nfileevery) { if (narg != 7) error->all("Illegal fix tmd command"); if (me == 0) { fp = fopen(arg[6],"w"); if (fp == NULL) { char str[128]; sprintf(str,"Cannot open fix tmd file %s",arg[6]); error->one(str); } fprintf(fp,"%s %s\n","# Step rho_target rho_old gamma_back", "gamma_forward lambda work_lambda work_analytical"); } } masstotal = group->mass(igroup); // rho_start = initial rho // xold = initial x or 0.0 if not in group int *mask = atom->mask; int *type = atom->type; int *image = atom->image; double **x = atom->x; double *mass = atom->mass; int nlocal = atom->nlocal; double xprd = domain->xprd; double yprd = domain->yprd; double zprd = domain->zprd; double dx,dy,dz; int xbox,ybox,zbox; rho_start = 0.0; for (int i = 0; i < nlocal; i++) { if (mask[i] & groupbit) { xbox = (image[i] & 1023) - 512; ybox = (image[i] >> 10 & 1023) - 512; zbox = (image[i] >> 20) - 512; dx = x[i][0] + xbox*xprd - xf[i][0]; dy = x[i][1] + ybox*yprd - xf[i][1]; dz = x[i][2] + zbox*zprd - xf[i][2]; rho_start += mass[type[i]]*(dx*dx + dy*dy + dz*dz); xold[i][0] = x[i][0] + xbox*xprd; xold[i][1] = x[i][1] + ybox*yprd; xold[i][2] = x[i][2] + zbox*zprd; } else xold[i][0] = xold[i][1] = xold[i][2] = 0.0; } double rho_start_total; MPI_Allreduce(&rho_start,&rho_start_total,1,MPI_DOUBLE,MPI_SUM,world); rho_start = sqrt(rho_start_total/masstotal); rho_old = rho_start; work_lambda = 0.0; work_analytical = 0.0; previous_stat = 0; } /* ---------------------------------------------------------------------- */ FixTMD::~FixTMD() { if (nfileevery && me == 0) fclose(fp); // unregister callbacks to this fix from Atom class atom->delete_callback(id,0); // delete locally stored arrays memory->destroy_2d_double_array(xf); memory->destroy_2d_double_array(xold); } /* ---------------------------------------------------------------------- */ int FixTMD::setmask() { int mask = 0; mask |= INITIAL_INTEGRATE; mask |= INITIAL_INTEGRATE_RESPA; return mask; } /* ---------------------------------------------------------------------- */ void FixTMD::init() { // check that no integrator fix comes after a TMD fix int flag = 0; for (int i = 0; i < modify->nfix; i++) { if (strcmp(modify->fix[i]->style,"tmd") == 0) flag = 1; if (flag && strcmp(modify->fix[i]->style,"nve") == 0) flag = 2; if (flag && strcmp(modify->fix[i]->style,"nvt") == 0) flag = 2; if (flag && strcmp(modify->fix[i]->style,"npt") == 0) flag = 2; if (flag && strcmp(modify->fix[i]->style,"nph") == 0) flag = 2; } if (flag == 2) error->all("Fix tmd must come after integration fixes"); // timesteps dtv = update->dt; dtf = update->dt * force->ftm2v; if (strcmp(update->integrate_style,"respa") == 0) step_respa = ((Respa *) update->integrate)->step; } /* ---------------------------------------------------------------------- */ void FixTMD::initial_integrate(int vflag) { double a,b,c,d,e; double dx,dy,dz,dxkt,dykt,dzkt; double dxold,dyold,dzold,xback,yback,zback; double gamma_forward,gamma_back,gamma_max,lambda; double kt,fr,kttotal,frtotal,dtfm; double xprd = domain->xprd; double yprd = domain->yprd; double zprd = domain->zprd; double **x = atom->x; double **v = atom->v; double **f = atom->f; double *mass = atom->mass; int *image = atom->image; int *type = atom->type; int *mask = atom->mask; int nlocal = atom->nlocal; int xbox,ybox,zbox; double delta = update->ntimestep - update->beginstep; delta /= update->endstep - update->beginstep; double rho_target = rho_start + delta * (rho_stop - rho_start); // compute the Lagrange multiplier a = b = e = 0.0; for (int i = 0; i < nlocal; i++) { if (mask[i] & groupbit) { dxold = xold[i][0] - xf[i][0]; dyold = xold[i][1] - xf[i][1]; dzold = xold[i][2] - xf[i][2]; xbox = (image[i] & 1023) - 512; ybox = (image[i] >> 10 & 1023) - 512; zbox = (image[i] >> 20) - 512; dx = x[i][0] + xbox*xprd - xf[i][0]; dy = x[i][1] + ybox*yprd - xf[i][1]; dz = x[i][2] + zbox*zprd - xf[i][2]; a += mass[type[i]]*(dxold*dxold + dyold*dyold + dzold*dzold); b += mass[type[i]]*(dx *dxold + dy *dyold + dz *dzold); e += mass[type[i]]*(dx *dx + dy *dy + dz *dz); } } double abe[3],abetotal[3]; abe[0] = a; abe[1] = b; abe[2] = e; MPI_Allreduce(abe,abetotal,3,MPI_DOUBLE,MPI_SUM,world); a = abetotal[0]/masstotal; b = 2.0*abetotal[1]/masstotal; e = abetotal[2]/masstotal; c = e - rho_old*rho_old; d = b*b - 4*a*c; if (d < 0) d = 0; if (b >= 0) gamma_max = (-b - sqrt(d))/(2*a); else gamma_max = (-b + sqrt(d))/(2*a); gamma_back = c/(a*gamma_max); if (a == 0.0) gamma_back = 0; c = e - rho_target*rho_target; d = b*b - 4*a*c; if (d < 0) d = 0; if (b >= 0) gamma_max = (-b - sqrt(d))/(2*a); else gamma_max = (-b + sqrt(d))/(2*a); gamma_forward = c/(a*gamma_max); if (a == 0.0) gamma_forward = 0; fr = kt = 0.0; for (int i = 0; i < nlocal; i++) { if (mask[i] & groupbit) { dxold = xold[i][0] - xf[i][0]; dyold = xold[i][1] - xf[i][1]; dzold = xold[i][2] - xf[i][2]; xbox = (image[i] & 1023) - 512; ybox = (image[i] >> 10 & 1023) - 512; zbox = (image[i] >> 20) - 512; xback = x[i][0] + xbox*xprd + gamma_back*dxold; yback = x[i][1] + ybox*yprd + gamma_back*dyold; zback = x[i][2] + zbox*zprd + gamma_back*dzold; dxkt = xback - xold[i][0]; dykt = yback - xold[i][1]; dzkt = zback - xold[i][2]; kt += mass[type[i]]*(dxkt*dxkt + dykt*dykt + dzkt*dzkt); fr += f[i][0]*dxold + f[i][1]*dyold + f[i][2]*dzold; } } double r[2],rtotal[2]; r[0] = fr; r[1] = kt; MPI_Allreduce(r,rtotal,2,MPI_DOUBLE,MPI_SUM,world); frtotal = rtotal[0]; kttotal = rtotal[1]; // stat write of mean constraint force based on previous time step constraint if (nfileevery && me == 0) { work_analytical += (-frtotal - kttotal/dtv/dtf)*(rho_target - rho_old)/rho_old; lambda = gamma_back*rho_old*masstotal/dtv/dtf; work_lambda += lambda*(rho_target - rho_old); if (!(update->ntimestep % nfileevery) && (previous_stat != update->ntimestep)) { - fprintf(fp,"%d %g %g %g %g %g %g %g\n", - update->ntimestep,rho_target,rho_old, + char fstr[64]; + sprintf(fstr,"%s %%g %%g %%g %%g %%g %%g %%g\n",BIGINT_FORMAT); + fprintf(fp,fstr,update->ntimestep,rho_target,rho_old, gamma_back,gamma_forward,lambda,work_lambda,work_analytical); fflush(fp); previous_stat = update->ntimestep; } } rho_old = rho_target; // apply the constraint and save constrained positions for next step for (int i = 0; i < nlocal; i++) { if (mask[i] & groupbit) { dtfm = dtf / mass[type[i]]; dxold = xold[i][0] - xf[i][0]; x[i][0] += gamma_forward*dxold; v[i][0] += gamma_forward*dxold/dtv; f[i][0] += gamma_forward*dxold/dtv/dtfm; dyold = xold[i][1] - xf[i][1]; x[i][1] += gamma_forward*dyold; v[i][1] += gamma_forward*dyold/dtv; f[i][1] += gamma_forward*dyold/dtv/dtfm; dzold = xold[i][2] - xf[i][2]; x[i][2] += gamma_forward*dzold; v[i][2] += gamma_forward*dzold/dtv; f[i][2] += gamma_forward*dzold/dtv/dtfm; xbox = (image[i] & 1023) - 512; ybox = (image[i] >> 10 & 1023) - 512; zbox = (image[i] >> 20) - 512; xold[i][0] = x[i][0] + xbox*xprd; xold[i][1] = x[i][1] + ybox*yprd; xold[i][2] = x[i][2] + zbox*zprd; } } } /* ---------------------------------------------------------------------- */ void FixTMD::initial_integrate_respa(int vflag, int ilevel, int flag) { if (flag) return; // only used by NPT,NPH dtv = step_respa[ilevel]; dtf = step_respa[ilevel] * force->ftm2v; if (ilevel == 0) initial_integrate(vflag); } /* ---------------------------------------------------------------------- memory usage of local atom-based arrays ------------------------------------------------------------------------- */ double FixTMD::memory_usage() { double bytes = 2*atom->nmax*3 * sizeof(double); return bytes; } /* ---------------------------------------------------------------------- allocate atom-based arrays ------------------------------------------------------------------------- */ void FixTMD::grow_arrays(int nmax) { xf = memory->grow_2d_double_array(xf,nmax,3,"fix_tmd:xf"); xold = memory->grow_2d_double_array(xold,nmax,3,"fix_tmd:xold"); } /* ---------------------------------------------------------------------- copy values within local atom-based arrays ------------------------------------------------------------------------- */ void FixTMD::copy_arrays(int i, int j) { xf[j][0] = xf[i][0]; xf[j][1] = xf[i][1]; xf[j][2] = xf[i][2]; xold[j][0] = xold[i][0]; xold[j][1] = xold[i][1]; xold[j][2] = xold[i][2]; } /* ---------------------------------------------------------------------- pack values in local atom-based arrays for exchange with another proc ------------------------------------------------------------------------- */ int FixTMD::pack_exchange(int i, double *buf) { buf[0] = xf[i][0]; buf[1] = xf[i][1]; buf[2] = xf[i][2]; buf[3] = xold[i][0]; buf[4] = xold[i][1]; buf[5] = xold[i][2]; return 6; } /* ---------------------------------------------------------------------- unpack values in local atom-based arrays from exchange with another proc ------------------------------------------------------------------------- */ int FixTMD::unpack_exchange(int nlocal, double *buf) { xf[nlocal][0] = buf[0]; xf[nlocal][1] = buf[1]; xf[nlocal][2] = buf[2]; xold[nlocal][0] = buf[3]; xold[nlocal][1] = buf[4]; xold[nlocal][2] = buf[5]; return 6; } /* ---------------------------------------------------------------------- read target coordinates from file, store with appropriate atom ------------------------------------------------------------------------- */ void FixTMD::readfile(char *file) { if (me == 0) { if (screen) fprintf(screen,"Reading TMD target file %s ...\n",file); open(file); } int *mask = atom->mask; int nlocal = atom->nlocal; char *buffer = new char[CHUNK*MAXLINE]; char *ptr,*next,*bufptr; int i,m,nlines,tag,imageflag,ix,iy,iz; double x,y,z,xprd,yprd,zprd; int firstline = 1; int ncount = 0; int eof = 0; xprd = yprd = zprd = -1.0; while (!eof) { if (me == 0) { m = 0; for (nlines = 0; nlines < CHUNK; nlines++) { ptr = fgets(&buffer[m],MAXLINE,fp); if (ptr == NULL) break; m += strlen(&buffer[m]); } if (ptr == NULL) eof = 1; buffer[m++] = '\n'; } MPI_Bcast(&eof,1,MPI_INT,0,world); MPI_Bcast(&nlines,1,MPI_INT,0,world); MPI_Bcast(&m,1,MPI_INT,0,world); MPI_Bcast(buffer,m,MPI_CHAR,0,world); bufptr = buffer; for (i = 0; i < nlines; i++) { next = strchr(bufptr,'\n'); *next = '\0'; if (firstline) { if (strstr(bufptr,"xlo xhi")) { double lo,hi; sscanf(bufptr,"%lg %lg",&lo,&hi); xprd = hi - lo; bufptr = next + 1; continue; } else if (strstr(bufptr,"ylo yhi")) { double lo,hi; sscanf(bufptr,"%lg %lg",&lo,&hi); yprd = hi - lo; bufptr = next + 1; continue; } else if (strstr(bufptr,"zlo zhi")) { double lo,hi; sscanf(bufptr,"%lg %lg",&lo,&hi); zprd = hi - lo; bufptr = next + 1; continue; } else if (atom->count_words(bufptr) == 4) { if (xprd >= 0.0 || yprd >= 0.0 || zprd >= 0.0) error->all("Incorrect format in TMD target file"); imageflag = 0; firstline = 0; } else if (atom->count_words(bufptr) == 7) { if (xprd < 0.0 || yprd < 0.0 || zprd < 0.0) error->all("Incorrect format in TMD target file"); imageflag = 1; firstline = 0; } else error->all("Incorrect format in TMD target file"); } if (imageflag) sscanf(bufptr,"%d %lg %lg %lg %d %d %d",&tag,&x,&y,&z,&ix,&iy,&iz); else sscanf(bufptr,"%d %lg %lg %lg",&tag,&x,&y,&z); m = atom->map(tag); if (m >= 0 && m < nlocal && mask[m] & groupbit) { if (imageflag) { xf[m][0] = x + ix*xprd; xf[m][1] = y + iy*yprd; xf[m][2] = z + iz*zprd; } else { xf[m][0] = x; xf[m][1] = y; xf[m][2] = z; } ncount++; } bufptr = next + 1; } } // clean up delete [] buffer; if (me == 0) { if (compressed) pclose(fp); else fclose(fp); } // check that all atoms in group were listed in target file // set xf = 0.0 for atoms not in group int gcount = 0; for (i = 0; i < nlocal; i++) if (mask[i] & groupbit) gcount++; else xf[i][0] = xf[i][1] = xf[i][2] = 0.0; int flag = 0; if (gcount != ncount) flag = 1; int flagall; MPI_Allreduce(&flag,&flagall,1,MPI_INT,MPI_SUM,world); if (flagall) error->all("TMD target file did not list all group atoms"); } /* ---------------------------------------------------------------------- proc 0 opens TMD data file test if gzipped ------------------------------------------------------------------------- */ void FixTMD::open(char *file) { compressed = 0; char *suffix = file + strlen(file) - 3; if (suffix > file && strcmp(suffix,".gz") == 0) compressed = 1; if (!compressed) fp = fopen(file,"r"); else { #ifdef LAMMPS_GZIP char gunzip[128]; sprintf(gunzip,"gunzip -c %s",file); fp = popen(gunzip,"r"); #else error->one("Cannot open gzipped file"); #endif } if (fp == NULL) { char str[128]; sprintf(str,"Cannot open file %s",file); error->one(str); } } /* ---------------------------------------------------------------------- */ void FixTMD::reset_dt() { dtv = update->dt; dtf = update->dt * force->ftm2v; } diff --git a/src/fix_tmd.h b/src/fix_tmd.h index 785bae60c..ee4a723d8 100644 --- a/src/fix_tmd.h +++ b/src/fix_tmd.h @@ -1,61 +1,62 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ #ifdef FIX_CLASS FixStyle(tmd,FixTMD) #else #ifndef LMP_FIX_TMD_H #define LMP_FIX_TMD_H #include "stdio.h" #include "fix.h" namespace LAMMPS_NS { class FixTMD : public Fix { public: FixTMD(class LAMMPS *, int, char **); ~FixTMD(); int setmask(); void init(); void initial_integrate(int); void initial_integrate_respa(int, int, int); double memory_usage(); void grow_arrays(int); void copy_arrays(int, int); int pack_exchange(int, double *); int unpack_exchange(int, double *); void reset_dt(); private: int me; - int nfileevery,previous_stat,compressed; + int nfileevery,compressed; + bigint previous_stat; FILE *fp; double rho_start,rho_stop,rho_old,masstotal; double dtv,dtf; double *step_respa; double work_lambda,work_analytical; double **xf,**xold; void readfile(char *); void open(char *); }; } #endif #endif diff --git a/src/fix_ttm.cpp b/src/fix_ttm.cpp index 0cc1a191f..4edfba1bb 100644 --- a/src/fix_ttm.cpp +++ b/src/fix_ttm.cpp @@ -1,698 +1,699 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- Contributing authors: Paul Crozier (SNL) Carolyn Phillips (University of Michigan) ------------------------------------------------------------------------- */ #include "mpi.h" #include "math.h" #include "string.h" #include "stdlib.h" #include "fix_ttm.h" +#include "lmptype.h" #include "atom.h" #include "force.h" #include "update.h" #include "domain.h" #include "region.h" #include "respa.h" #include "comm.h" #include "random_mars.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; #define MIN(A,B) ((A) < (B)) ? (A) : (B) #define MAX(A,B) ((A) > (B)) ? (A) : (B) #define MAXLINE 1024 /* ---------------------------------------------------------------------- */ FixTTM::FixTTM(LAMMPS *lmp, int narg, char **arg) : Fix(lmp, narg, arg) { if (narg < 15) error->all("Illegal fix ttm command"); vector_flag = 1; size_vector = 2; global_freq = 1; extvector = 1; nevery = 1; restart_peratom = 1; restart_global = 1; seed = atoi(arg[3]); electronic_specific_heat = atof(arg[4]); electronic_density = atof(arg[5]); electronic_thermal_conductivity = atof(arg[6]); gamma_p = atof(arg[7]); gamma_s = atof(arg[8]); v_0 = atof(arg[9]); nxnodes = atoi(arg[10]); nynodes = atoi(arg[11]); nznodes = atoi(arg[12]); fpr = fopen(arg[13],"r"); if (fpr == NULL) { char str[128]; sprintf(str,"Cannot open file %s",arg[13]); error->one(str); } nfileevery = atoi(arg[14]); if (nfileevery) { if (narg != 16) error->all("Illegal fix ttm command"); MPI_Comm_rank(world,&me); if (me == 0) { fp = fopen(arg[15],"w"); if (fp == NULL) { char str[128]; sprintf(str,"Cannot open fix ttm file %s",arg[15]); error->one(str); } } } // error check if (seed <= 0) error->all("Invalid random number seed in fix ttm command"); if (electronic_specific_heat <= 0.0) error->all("Fix ttm electronic_specific_heat must be > 0.0"); if (electronic_density <= 0.0) error->all("Fix ttm electronic_density must be > 0.0"); if (electronic_thermal_conductivity < 0.0) error->all("Fix ttm electronic_thermal_conductivity must be >= 0.0"); if (gamma_p <= 0.0) error->all("Fix ttm gamma_p must be > 0.0"); if (gamma_s < 0.0) error->all("Fix ttm gamma_s must be >= 0.0"); if (v_0 < 0.0) error->all("Fix ttm v_0 must be >= 0.0"); if (nxnodes <= 0 || nynodes <= 0 || nznodes <= 0) error->all("Fix ttm number of nodes must be > 0"); v_0_sq = v_0*v_0; // initialize Marsaglia RNG with processor-unique seed random = new RanMars(lmp,seed + comm->me); // allocate per-type arrays for force prefactors gfactor1 = new double[atom->ntypes+1]; gfactor2 = new double[atom->ntypes+1]; // allocate 3d grid variables total_nnodes = nxnodes*nynodes*nznodes; nsum = memory->create_3d_int_array(nxnodes,nynodes,nznodes,"ttm:nsum"); nsum_all = memory->create_3d_int_array(nxnodes,nynodes,nznodes, "ttm:nsum_all"); T_initial_set = memory->create_3d_int_array(nxnodes,nynodes,nznodes, "ttm:T_initial_set"); sum_vsq = memory->create_3d_double_array(nxnodes,nynodes,nznodes, "ttm:sum_vsq"); sum_mass_vsq = memory->create_3d_double_array(nxnodes,nynodes,nznodes, "ttm:sum_mass_vsq"); sum_vsq_all = memory->create_3d_double_array(nxnodes,nynodes,nznodes, "ttm:sum_vsq_all"); sum_mass_vsq_all = memory->create_3d_double_array(nxnodes,nynodes,nznodes, "ttm:sum_mass_vsq_all"); T_electron_old = memory->create_3d_double_array(nxnodes,nynodes,nznodes, "ttm:T_electron_old"); T_electron = memory->create_3d_double_array(nxnodes,nynodes,nznodes,"ttm:T_electron"); net_energy_transfer = memory->create_3d_double_array(nxnodes,nynodes,nznodes, "TTM:net_energy_transfer"); net_energy_transfer_all = memory->create_3d_double_array(nxnodes,nynodes,nznodes, "TTM:net_energy_transfer_all"); flangevin = NULL; grow_arrays(atom->nmax); // zero out the flangevin array for (int i = 0; i < atom->nmax; i++) { flangevin[i][0] = 0; flangevin[i][1] = 0; flangevin[i][2] = 0; } atom->add_callback(0); atom->add_callback(1); // set initial electron temperatures from user input file if (me == 0) read_initial_electron_temperatures(); MPI_Bcast(&T_electron[0][0][0],total_nnodes,MPI_DOUBLE,0,world); } /* ---------------------------------------------------------------------- */ FixTTM::~FixTTM() { if (nfileevery && me == 0) fclose(fp); delete random; delete [] gfactor1; delete [] gfactor2; memory->destroy_3d_int_array(nsum); memory->destroy_3d_int_array(nsum_all); memory->destroy_3d_int_array(T_initial_set); memory->destroy_3d_double_array(sum_vsq); memory->destroy_3d_double_array(sum_mass_vsq); memory->destroy_3d_double_array(sum_vsq_all); memory->destroy_3d_double_array(sum_mass_vsq_all); memory->destroy_3d_double_array(T_electron_old); memory->destroy_3d_double_array(T_electron); memory->destroy_2d_double_array(flangevin); memory->destroy_3d_double_array(net_energy_transfer); memory->destroy_3d_double_array(net_energy_transfer_all); } /* ---------------------------------------------------------------------- */ int FixTTM::setmask() { int mask = 0; mask |= POST_FORCE; mask |= POST_FORCE_RESPA; mask |= END_OF_STEP; return mask; } /* ---------------------------------------------------------------------- */ void FixTTM::init() { if (domain->dimension == 2) error->all("Cannot use fix ttm with 2d simulation"); if (domain->nonperiodic != 0) error->all("Cannot use nonperiodic boundares with fix ttm"); if (domain->triclinic) error->all("Cannot use fix ttm with triclinic box"); // set force prefactors for (int i = 1; i <= atom->ntypes; i++) { gfactor1[i] = - gamma_p / force->ftm2v; gfactor2[i] = sqrt(24.0*force->boltz*gamma_p/update->dt/force->mvv2e) / force->ftm2v; } for (int ixnode = 0; ixnode < nxnodes; ixnode++) for (int iynode = 0; iynode < nynodes; iynode++) for (int iznode = 0; iznode < nznodes; iznode++) net_energy_transfer_all[ixnode][iynode][iznode] = 0; if (strcmp(update->integrate_style,"respa") == 0) nlevels_respa = ((Respa *) update->integrate)->nlevels; } /* ---------------------------------------------------------------------- */ void FixTTM::setup(int vflag) { if (strcmp(update->integrate_style,"verlet") == 0) post_force_setup(vflag); else { ((Respa *) update->integrate)->copy_flevel_f(nlevels_respa-1); post_force_respa_setup(vflag,nlevels_respa-1,0); ((Respa *) update->integrate)->copy_f_flevel(nlevels_respa-1); } } /* ---------------------------------------------------------------------- */ void FixTTM::post_force(int vflag) { double **x = atom->x; double **v = atom->v; double **f = atom->f; int *type = atom->type; int *mask = atom->mask; int nlocal = atom->nlocal; double gamma1,gamma2; // apply damping and thermostat to all atoms in fix group for (int i = 0; i < nlocal; i++) { if (mask[i] & groupbit) { double xscale = (x[i][0] - domain->boxlo[0])/domain->xprd; double yscale = (x[i][1] - domain->boxlo[1])/domain->yprd; double zscale = (x[i][2] - domain->boxlo[2])/domain->zprd; int ixnode = static_cast<int>(xscale*nxnodes); int iynode = static_cast<int>(yscale*nynodes); int iznode = static_cast<int>(zscale*nznodes); while (ixnode > nxnodes-1) ixnode -= nxnodes; while (iynode > nynodes-1) iynode -= nynodes; while (iznode > nznodes-1) iznode -= nznodes; while (ixnode < 0) ixnode += nxnodes; while (iynode < 0) iynode += nynodes; while (iznode < 0) iznode += nznodes; if (T_electron[ixnode][iynode][iznode] < 0) error->all("Electronic temperature dropped below zero"); double tsqrt = sqrt(T_electron[ixnode][iynode][iznode]); gamma1 = gfactor1[type[i]]; double vsq = v[i][0]*v[i][0] + v[i][1]*v[i][1] + v[i][2]*v[i][2]; if (vsq > v_0_sq) gamma1 *= (gamma_p + gamma_s)/gamma_p; gamma2 = gfactor2[type[i]] * tsqrt; flangevin[i][0] = gamma1*v[i][0] + gamma2*(random->uniform()-0.5); flangevin[i][1] = gamma1*v[i][1] + gamma2*(random->uniform()-0.5); flangevin[i][2] = gamma1*v[i][2] + gamma2*(random->uniform()-0.5); f[i][0] += flangevin[i][0]; f[i][1] += flangevin[i][1]; f[i][2] += flangevin[i][2]; } } } /* ---------------------------------------------------------------------- */ void FixTTM::post_force_setup(int vflag) { double **f = atom->f; int *mask = atom->mask; int nlocal = atom->nlocal; // apply langevin forces that have been stored from previous run for (int i = 0; i < nlocal; i++) { if (mask[i] & groupbit) { f[i][0] += flangevin[i][0]; f[i][1] += flangevin[i][1]; f[i][2] += flangevin[i][2]; } } } /* ---------------------------------------------------------------------- */ void FixTTM::post_force_respa(int vflag, int ilevel, int iloop) { if (ilevel == nlevels_respa-1) post_force(vflag); } /* ---------------------------------------------------------------------- */ void FixTTM::post_force_respa_setup(int vflag, int ilevel, int iloop) { if (ilevel == nlevels_respa-1) post_force_setup(vflag); } /* ---------------------------------------------------------------------- */ void FixTTM::reset_dt() { for (int i = 1; i <= atom->ntypes; i++) gfactor2[i] = sqrt(24.0*force->boltz*gamma_p/update->dt/force->mvv2e) / force->ftm2v; } /* ---------------------------------------------------------------------- read in initial electron temperatures from a user-specified file only called by proc 0 ------------------------------------------------------------------------- */ void FixTTM::read_initial_electron_temperatures() { char line[MAXLINE]; for (int ixnode = 0; ixnode < nxnodes; ixnode++) for (int iynode = 0; iynode < nynodes; iynode++) for (int iznode = 0; iznode < nznodes; iznode++) T_initial_set[ixnode][iynode][iznode] = 0; // read initial electron temperature values from file int ixnode,iynode,iznode; double T_tmp; while (1) { if (fgets(line,MAXLINE,fpr) == NULL) break; sscanf(line,"%d %d %d %lg",&ixnode,&iynode,&iznode,&T_tmp); if (T_tmp < 0.0) error->one("Fix ttm electron temperatures must be > 0.0"); T_electron[ixnode][iynode][iznode] = T_tmp; T_initial_set[ixnode][iynode][iznode] = 1; } for (int ixnode = 0; ixnode < nxnodes; ixnode++) for (int iynode = 0; iynode < nynodes; iynode++) for (int iznode = 0; iznode < nznodes; iznode++) if (T_initial_set[ixnode][iynode][iznode] == 0) error->one("Initial temperatures not all set in fix ttm"); // close file fclose(fpr); } /* ---------------------------------------------------------------------- */ void FixTTM::end_of_step() { double **x = atom->x; double **v = atom->v; double *mass = atom->mass; double *rmass = atom->rmass; int *type = atom->type; int *mask = atom->mask; int nlocal = atom->nlocal; for (int ixnode = 0; ixnode < nxnodes; ixnode++) for (int iynode = 0; iynode < nynodes; iynode++) for (int iznode = 0; iznode < nznodes; iznode++) net_energy_transfer[ixnode][iynode][iznode] = 0; for (int i = 0; i < nlocal; i++) if (mask[i] & groupbit) { double xscale = (x[i][0] - domain->boxlo[0])/domain->xprd; double yscale = (x[i][1] - domain->boxlo[1])/domain->yprd; double zscale = (x[i][2] - domain->boxlo[2])/domain->zprd; int ixnode = static_cast<int>(xscale*nxnodes); int iynode = static_cast<int>(yscale*nynodes); int iznode = static_cast<int>(zscale*nznodes); while (ixnode > nxnodes-1) ixnode -= nxnodes; while (iynode > nynodes-1) iynode -= nynodes; while (iznode > nznodes-1) iznode -= nznodes; while (ixnode < 0) ixnode += nxnodes; while (iynode < 0) iynode += nynodes; while (iznode < 0) iznode += nznodes; net_energy_transfer[ixnode][iynode][iznode] += (flangevin[i][0]*v[i][0] + flangevin[i][1]*v[i][1] + flangevin[i][2]*v[i][2]); } MPI_Allreduce(&net_energy_transfer[0][0][0], &net_energy_transfer_all[0][0][0], total_nnodes,MPI_DOUBLE,MPI_SUM,world); double dx = domain->xprd/nxnodes; double dy = domain->yprd/nynodes; double dz = domain->zprd/nznodes; double del_vol = dx*dy*dz; // num_inner_timesteps = # of inner steps (thermal solves) // required this MD step to maintain a stable explicit solve int num_inner_timesteps = 1; double inner_dt = update->dt; double stability_criterion = 1.0 - 2.0*inner_dt/(electronic_specific_heat*electronic_density) * (electronic_thermal_conductivity*(1.0/dx/dx + 1.0/dy/dy + 1.0/dz/dz)); if (stability_criterion < 0.0) { inner_dt = 0.5*(electronic_specific_heat*electronic_density) / (electronic_thermal_conductivity*(1.0/dx/dx + 1.0/dy/dy + 1.0/dz/dz)); num_inner_timesteps = static_cast<int>(update->dt/inner_dt) + 1; inner_dt = update->dt/double(num_inner_timesteps); if (num_inner_timesteps > 1000000) error->warning("Too many inner timesteps in fix ttm",0); } for (int ith_inner_timestep = 0; ith_inner_timestep < num_inner_timesteps; ith_inner_timestep++) { for (int ixnode = 0; ixnode < nxnodes; ixnode++) for (int iynode = 0; iynode < nynodes; iynode++) for (int iznode = 0; iznode < nznodes; iznode++) T_electron_old[ixnode][iynode][iznode] = T_electron[ixnode][iynode][iznode]; // compute new electron T profile for (int ixnode = 0; ixnode < nxnodes; ixnode++) for (int iynode = 0; iynode < nynodes; iynode++) for (int iznode = 0; iznode < nznodes; iznode++) { int right_xnode = ixnode + 1; int right_ynode = iynode + 1; int right_znode = iznode + 1; if (right_xnode == nxnodes) right_xnode = 0; if (right_ynode == nynodes) right_ynode = 0; if (right_znode == nznodes) right_znode = 0; int left_xnode = ixnode - 1; int left_ynode = iynode - 1; int left_znode = iznode - 1; if (left_xnode == -1) left_xnode = nxnodes - 1; if (left_ynode == -1) left_ynode = nynodes - 1; if (left_znode == -1) left_znode = nznodes - 1; T_electron[ixnode][iynode][iznode] = T_electron_old[ixnode][iynode][iznode] + inner_dt/(electronic_specific_heat*electronic_density) * (electronic_thermal_conductivity * ((T_electron_old[right_xnode][iynode][iznode] + T_electron_old[left_xnode][iynode][iznode] - 2*T_electron_old[ixnode][iynode][iznode])/dx/dx + (T_electron_old[ixnode][right_ynode][iznode] + T_electron_old[ixnode][left_ynode][iznode] - 2*T_electron_old[ixnode][iynode][iznode])/dy/dy + (T_electron_old[ixnode][iynode][right_znode] + T_electron_old[ixnode][iynode][left_znode] - 2*T_electron_old[ixnode][iynode][iznode])/dz/dz) - (net_energy_transfer_all[ixnode][iynode][iznode])/del_vol); } } // output nodal temperatures for current timestep if ((nfileevery) && !(update->ntimestep % nfileevery)) { // compute atomic Ta for each grid point for (int ixnode = 0; ixnode < nxnodes; ixnode++) for (int iynode = 0; iynode < nynodes; iynode++) for (int iznode = 0; iznode < nznodes; iznode++) { nsum[ixnode][iynode][iznode] = 0; nsum_all[ixnode][iynode][iznode] = 0; sum_vsq[ixnode][iynode][iznode] = 0.0; sum_mass_vsq[ixnode][iynode][iznode] = 0.0; sum_vsq_all[ixnode][iynode][iznode] = 0.0; sum_mass_vsq_all[ixnode][iynode][iznode] = 0.0; } double massone; for (int i = 0; i < nlocal; i++) if (mask[i] & groupbit) { if (rmass) massone = rmass[i]; else massone = mass[type[i]]; double xscale = (x[i][0] - domain->boxlo[0])/domain->xprd; double yscale = (x[i][1] - domain->boxlo[1])/domain->yprd; double zscale = (x[i][2] - domain->boxlo[2])/domain->zprd; int ixnode = static_cast<int>(xscale*nxnodes); int iynode = static_cast<int>(yscale*nynodes); int iznode = static_cast<int>(zscale*nznodes); while (ixnode > nxnodes-1) ixnode -= nxnodes; while (iynode > nynodes-1) iynode -= nynodes; while (iznode > nznodes-1) iznode -= nznodes; while (ixnode < 0) ixnode += nxnodes; while (iynode < 0) iynode += nynodes; while (iznode < 0) iznode += nznodes; double vsq = v[i][0]*v[i][0] + v[i][1]*v[i][1] + v[i][2]*v[i][2]; nsum[ixnode][iynode][iznode] += 1; sum_vsq[ixnode][iynode][iznode] += vsq; sum_mass_vsq[ixnode][iynode][iznode] += massone*vsq; } MPI_Allreduce(&nsum[0][0][0],&nsum_all[0][0][0],total_nnodes, MPI_INT,MPI_SUM,world); MPI_Allreduce(&sum_vsq[0][0][0],&sum_vsq_all[0][0][0],total_nnodes, MPI_DOUBLE,MPI_SUM,world); MPI_Allreduce(&sum_mass_vsq[0][0][0],&sum_mass_vsq_all[0][0][0], total_nnodes,MPI_DOUBLE,MPI_SUM,world); if (me == 0) { - fprintf(fp,"%d ",update->ntimestep); + fprintf(fp,BIGINT_FORMAT,update->ntimestep); double T_a; for (int ixnode = 0; ixnode < nxnodes; ixnode++) for (int iynode = 0; iynode < nynodes; iynode++) for (int iznode = 0; iznode < nznodes; iznode++) { T_a = 0; if (nsum_all[ixnode][iynode][iznode] > 0) T_a = sum_mass_vsq_all[ixnode][iynode][iznode]/ (3.0*force->boltz*nsum_all[ixnode][iynode][iznode]/force->mvv2e); - fprintf(fp,"%f ",T_a); + fprintf(fp," %f",T_a); } fprintf(fp,"\t"); for (int ixnode = 0; ixnode < nxnodes; ixnode++) for (int iynode = 0; iynode < nynodes; iynode++) for (int iznode = 0; iznode < nznodes; iznode++) fprintf(fp,"%f ",T_electron[ixnode][iynode][iznode]); fprintf(fp,"\n"); } } } /* ---------------------------------------------------------------------- memory usage of 3d grid ------------------------------------------------------------------------- */ double FixTTM::memory_usage() { double bytes = 0.0; bytes += 5*total_nnodes * sizeof(int); bytes += 14*total_nnodes * sizeof(double); return bytes; } /* ---------------------------------------------------------------------- */ void FixTTM::grow_arrays(int ngrow) { flangevin = memory->grow_2d_double_array(flangevin,ngrow,3,"TTM:flangevin"); } /* ---------------------------------------------------------------------- return the energy of the electronic subsystem or the net_energy transfer between the subsystems ------------------------------------------------------------------------- */ double FixTTM::compute_vector(int n) { double e_energy = 0.0; double transfer_energy = 0.0; double dx = domain->xprd/nxnodes; double dy = domain->yprd/nynodes; double dz = domain->zprd/nznodes; double del_vol = dx*dy*dz; for (int ixnode = 0; ixnode < nxnodes; ixnode++) for (int iynode = 0; iynode < nynodes; iynode++) for (int iznode = 0; iznode < nznodes; iznode++) { e_energy += T_electron[ixnode][iynode][iznode]*electronic_specific_heat* electronic_density*del_vol; transfer_energy += net_energy_transfer_all[ixnode][iynode][iznode]*update->dt; } if (n == 0) return e_energy; if (n == 1) return transfer_energy; return 0.0; } /* ---------------------------------------------------------------------- pack entire state of Fix into one write ------------------------------------------------------------------------- */ void FixTTM::write_restart(FILE *fp) { double *rlist = (double *) memory->smalloc((1+nxnodes*nynodes*nznodes)*sizeof(double),"TTM:rlist"); int n = 0; rlist[n++] = seed; for (int ixnode = 0; ixnode < nxnodes; ixnode++) for (int iynode = 0; iynode < nynodes; iynode++) for (int iznode = 0; iznode < nznodes; iznode++) rlist[n++] = T_electron[ixnode][iynode][iznode]; if (comm->me == 0) { int size = n * sizeof(double); fwrite(&size,sizeof(int),1,fp); fwrite(rlist,sizeof(double),n,fp); } memory->sfree(rlist); } /* ---------------------------------------------------------------------- use state info from restart file to restart the Fix ------------------------------------------------------------------------- */ void FixTTM::restart(char *buf) { int n = 0; double *rlist = (double *) buf; // the seed must be changed from the initial seed seed = static_cast<int> (0.5*rlist[n++]); for (int ixnode = 0; ixnode < nxnodes; ixnode++) for (int iynode = 0; iynode < nynodes; iynode++) for (int iznode = 0; iznode < nznodes; iznode++) T_electron[ixnode][iynode][iznode] = rlist[n++]; delete random; random = new RanMars(lmp,seed+comm->me); } /* ---------------------------------------------------------------------- pack values in local atom-based arrays for restart file ------------------------------------------------------------------------- */ int FixTTM::pack_restart(int i, double *buf) { buf[0] = 4; buf[1] = flangevin[i][0]; buf[2] = flangevin[i][1]; buf[3] = flangevin[i][2]; return 4; } /* ---------------------------------------------------------------------- unpack values from atom->extra array to restart the fix ------------------------------------------------------------------------- */ void FixTTM::unpack_restart(int nlocal, int nth) { double **extra = atom->extra; // skip to Nth set of extra values int m = 0; for (int i = 0; i < nth; i++) m += static_cast<int> (extra[nlocal][m]); m++; flangevin[nlocal][0] = extra[nlocal][m++]; flangevin[nlocal][1] = extra[nlocal][m++]; flangevin[nlocal][2] = extra[nlocal][m++]; } /* ---------------------------------------------------------------------- maxsize of any atom's restart data ------------------------------------------------------------------------- */ int FixTTM::maxsize_restart() { return 4; } /* ---------------------------------------------------------------------- size of atom nlocal's restart data ------------------------------------------------------------------------- */ int FixTTM::size_restart(int nlocal) { return 4; } diff --git a/src/group.cpp b/src/group.cpp index b2ee3c4af..79a526b5b 100644 --- a/src/group.cpp +++ b/src/group.cpp @@ -1,1469 +1,1469 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ #include "math.h" #include "mpi.h" #include "stdio.h" #include "string.h" #include "stdlib.h" #include "group.h" #include "lmptype.h" #include "domain.h" #include "atom.h" #include "force.h" #include "region.h" #include "modify.h" #include "fix.h" #include "compute.h" #include "output.h" #include "dump.h" #include "error.h" using namespace LAMMPS_NS; #define MAX_GROUP 32 enum{TYPE,MOLECULE,ID}; enum{LT,LE,GT,GE,EQ,NEQ,BETWEEN}; #define BIG 1.0e20 #define MIN(a,b) ((a) < (b) ? (a) : (b)) #define MAX(a,b) ((a) > (b) ? (a) : (b)) /* ---------------------------------------------------------------------- initialize group memory ------------------------------------------------------------------------- */ Group::Group(LAMMPS *lmp) : Pointers(lmp) { MPI_Comm_rank(world,&me); names = new char*[MAX_GROUP]; bitmask = new int[MAX_GROUP]; inversemask = new int[MAX_GROUP]; for (int i = 0; i < MAX_GROUP; i++) names[i] = NULL; for (int i = 0; i < MAX_GROUP; i++) bitmask[i] = 1 << i; for (int i = 0; i < MAX_GROUP; i++) inversemask[i] = bitmask[i] ^ ~0; // create "all" group char *str = (char *) "all"; int n = strlen(str) + 1; names[0] = new char[n]; strcpy(names[0],str); ngroup = 1; } /* ---------------------------------------------------------------------- free all memory ------------------------------------------------------------------------- */ Group::~Group() { for (int i = 0; i < MAX_GROUP; i++) delete [] names[i]; delete [] names; delete [] bitmask; delete [] inversemask; } /* ---------------------------------------------------------------------- assign atoms to a new or existing group ------------------------------------------------------------------------- */ void Group::assign(int narg, char **arg) { int i; if (domain->box_exist == 0) error->all("Group command before simulation box is defined"); if (narg < 2) error->all("Illegal group command"); // delete the group if not being used elsewhere // clear mask of each atom assigned to this group if (strcmp(arg[1],"delete") == 0) { int igroup = find(arg[0]); if (igroup == -1) error->all("Could not find group delete group ID"); if (igroup == 0) error->all("Cannot delete group all"); for (i = 0; i < modify->nfix; i++) if (modify->fix[i]->igroup == igroup) error->all("Cannot delete group currently used by a fix"); for (i = 0; i < modify->ncompute; i++) if (modify->compute[i]->igroup == igroup) error->all("Cannot delete group currently used by a compute"); for (i = 0; i < output->ndump; i++) if (output->dump[i]->igroup == igroup) error->all("Cannot delete group currently used by a dump"); if (atom->firstgroupname && strcmp(arg[0],atom->firstgroupname) == 0) error->all("Cannot delete group currently used by atom_modify first"); int *mask = atom->mask; int nlocal = atom->nlocal; int bits = inversemask[igroup]; for (i = 0; i < nlocal; i++) mask[i] &= bits; delete [] names[igroup]; names[igroup] = NULL; ngroup--; return; } // find group in existing list // add a new group if igroup = -1 int igroup = find(arg[0]); if (igroup == -1) { if (ngroup == MAX_GROUP) error->all("Too many groups"); igroup = find_unused(); int n = strlen(arg[0]) + 1; names[igroup] = new char[n]; strcpy(names[igroup],arg[0]); ngroup++; } double **x = atom->x; int *mask = atom->mask; int nlocal = atom->nlocal; int bit = bitmask[igroup]; // style = region // add to group if atom is in region if (strcmp(arg[1],"region") == 0) { if (narg != 3) error->all("Illegal group command"); int iregion = domain->find_region(arg[2]); if (iregion == -1) error->all("Group region ID does not exist"); for (i = 0; i < nlocal; i++) if (domain->regions[iregion]->match(x[i][0],x[i][1],x[i][2])) mask[i] |= bit; // style = logical condition } else if (narg >= 3 && (strcmp(arg[2],"<") == 0 || strcmp(arg[2],">") == 0 || strcmp(arg[2],"<=") == 0 || strcmp(arg[2],">=") == 0 || strcmp(arg[2],"<>") == 0)) { if (narg < 4 || narg > 5) error->all("Illegal group command"); int category,condition,bound1,bound2; if (strcmp(arg[1],"type") == 0) category = TYPE; else if (strcmp(arg[1],"molecule") == 0) category = MOLECULE; else if (strcmp(arg[1],"id") == 0) category = ID; else error->all("Illegal group command"); if (strcmp(arg[2],"<") == 0) condition = LT; else if (strcmp(arg[2],"<=") == 0) condition = LE; else if (strcmp(arg[2],">") == 0) condition = GT; else if (strcmp(arg[2],">=") == 0) condition = GE; else if (strcmp(arg[2],"==") == 0) condition = EQ; else if (strcmp(arg[2],"!=") == 0) condition = NEQ; else if (strcmp(arg[2],"<>") == 0) condition = BETWEEN; else error->all("Illegal group command"); bound1 = atoi(arg[3]); bound2 = -1; if (condition == BETWEEN) { if (narg != 5) error->all("Illegal group command"); bound2 = atoi(arg[4]); } int *attribute; if (category == TYPE) attribute = atom->type; else if (category == MOLECULE) attribute = atom->molecule; else if (category == ID) attribute = atom->tag; // add to group if meets condition if (condition == LT) { for (i = 0; i < nlocal; i++) if (attribute[i] < bound1) mask[i] |= bit; } else if (condition == LE) { for (i = 0; i < nlocal; i++) if (attribute[i] <= bound1) mask[i] |= bit; } else if (condition == GT) { for (i = 0; i < nlocal; i++) if (attribute[i] > bound1) mask[i] |= bit; } else if (condition == GE) { for (i = 0; i < nlocal; i++) if (attribute[i] >= bound1) mask[i] |= bit; } else if (condition == EQ) { for (i = 0; i < nlocal; i++) if (attribute[i] == bound1) mask[i] |= bit; } else if (condition == NEQ) { for (i = 0; i < nlocal; i++) if (attribute[i] != bound1) mask[i] |= bit; } else if (condition == BETWEEN) { for (i = 0; i < nlocal; i++) if (attribute[i] >= bound1 && attribute[i] <= bound2) mask[i] |= bit; } // style = list of values } else if (strcmp(arg[1],"type") == 0 || strcmp(arg[1],"molecule") == 0 || strcmp(arg[1],"id") == 0) { if (narg < 3) error->all("Illegal group command"); int length = narg-2; int *list = new int[length]; int category; if (strcmp(arg[1],"type") == 0) category = TYPE; else if (strcmp(arg[1],"molecule") == 0) category = MOLECULE; else if (strcmp(arg[1],"id") == 0) category = ID; else error->all("Illegal group command"); length = narg - 2; for (int iarg = 2; iarg < narg; iarg++) list[iarg-2] = atoi(arg[iarg]); int *attribute; if (category == TYPE) attribute = atom->type; else if (category == MOLECULE) attribute = atom->molecule; else if (category == ID) attribute = atom->tag; // add to group if attribute is any in list for (int ilist = 0; ilist < length; ilist++) for (i = 0; i < nlocal; i++) if (attribute[i] == list[ilist]) mask[i] |= bit; delete [] list; // style = subtract } else if (strcmp(arg[1],"subtract") == 0) { if (narg < 4) error->all("Illegal group command"); int length = narg-2; int *list = new int[length]; int jgroup; for (int iarg = 2; iarg < narg; iarg++) { jgroup = find(arg[iarg]); if (jgroup == -1) error->all("Group ID does not exist"); list[iarg-2] = jgroup; } // add to group if in 1st group in list int otherbit = bitmask[list[0]]; for (i = 0; i < nlocal; i++) if (mask[i] & otherbit) mask[i] |= bit; // remove atoms if they are in any of the other groups // AND with inverse mask removes the atom from group int inverse = inversemask[igroup]; for (int ilist = 1; ilist < length; ilist++) { otherbit = bitmask[list[ilist]]; for (i = 0; i < nlocal; i++) if (mask[i] & otherbit) mask[i] &= inverse; } delete [] list; // style = union } else if (strcmp(arg[1],"union") == 0) { if (narg < 3) error->all("Illegal group command"); int length = narg-2; int *list = new int[length]; int jgroup; for (int iarg = 2; iarg < narg; iarg++) { jgroup = find(arg[iarg]); if (jgroup == -1) error->all("Group ID does not exist"); list[iarg-2] = jgroup; } // add to group if in any other group in list int otherbit; for (int ilist = 0; ilist < length; ilist++) { otherbit = bitmask[list[ilist]]; for (i = 0; i < nlocal; i++) if (mask[i] & otherbit) mask[i] |= bit; } delete [] list; // style = intersect } else if (strcmp(arg[1],"intersect") == 0) { if (narg < 4) error->all("Illegal group command"); int length = narg-2; int *list = new int[length]; int jgroup; for (int iarg = 2; iarg < narg; iarg++) { jgroup = find(arg[iarg]); if (jgroup == -1) error->all("Group ID does not exist"); list[iarg-2] = jgroup; } // add to group if in all groups in list int otherbit,ok,ilist; for (i = 0; i < nlocal; i++) { ok = 1; for (ilist = 0; ilist < length; ilist++) { otherbit = bitmask[list[ilist]]; if ((mask[i] & otherbit) == 0) ok = 0; } if (ok) mask[i] |= bit; } delete [] list; // not a valid group style } else error->all("Illegal group command"); // print stats for changed group int n; n = 0; for (i = 0; i < nlocal; i++) if (mask[i] & bit) n++; double rlocal = n; double all; MPI_Allreduce(&rlocal,&all,1,MPI_DOUBLE,MPI_SUM,world); if (me == 0) { if (screen) fprintf(screen,"%.15g atoms in group %s\n",all,names[igroup]); if (logfile) fprintf(logfile,"%.15g atoms in group %s\n",all,names[igroup]); } } /* ---------------------------------------------------------------------- add flagged atoms to a new or existing group ------------------------------------------------------------------------- */ void Group::create(char *name, int *flag) { int i; // find group in existing list // add a new group if igroup = -1 int igroup = find(name); if (igroup == -1) { if (ngroup == MAX_GROUP) error->all("Too many groups"); igroup = find_unused(); int n = strlen(name) + 1; names[igroup] = new char[n]; strcpy(names[igroup],name); ngroup++; } // add atoms to group whose flags are set int *mask = atom->mask; int nlocal = atom->nlocal; int bit = bitmask[igroup]; for (i = 0; i < nlocal; i++) if (flag[i]) mask[i] |= bit; } /* ---------------------------------------------------------------------- return group index if name matches existing group, -1 if no such group ------------------------------------------------------------------------- */ int Group::find(const char *name) { for (int igroup = 0; igroup < MAX_GROUP; igroup++) if (names[igroup] && strcmp(name,names[igroup]) == 0) return igroup; return -1; } /* ---------------------------------------------------------------------- return index of first available group should never be called when group limit has been reached ------------------------------------------------------------------------- */ int Group::find_unused() { for (int igroup = 0; igroup < MAX_GROUP; igroup++) if (names[igroup] == NULL) return igroup; return -1; } /* ---------------------------------------------------------------------- write group info to a restart file only called by proc 0 ------------------------------------------------------------------------- */ void Group::write_restart(FILE *fp) { fwrite(&ngroup,sizeof(int),1,fp); // use count to not change restart format with deleted groups // remove this on next major release int n; int count = 0; for (int i = 0; i < MAX_GROUP; i++) { if (names[i]) n = strlen(names[i]) + 1; else n = 0; fwrite(&n,sizeof(int),1,fp); if (n) { fwrite(names[i],sizeof(char),n,fp); count++; } if (count == ngroup) break; } } /* ---------------------------------------------------------------------- read group info from a restart file proc 0 reads, bcast to all procs ------------------------------------------------------------------------- */ void Group::read_restart(FILE *fp) { int i,n; // delete existing group names // atom masks will be overwritten by reading of restart file for (i = 0; i < MAX_GROUP; i++) delete [] names[i]; if (me == 0) fread(&ngroup,sizeof(int),1,fp); MPI_Bcast(&ngroup,1,MPI_INT,0,world); // use count to not change restart format with deleted groups // remove this on next major release int count = 0; for (i = 0; i < MAX_GROUP; i++) { if (count == ngroup) { names[i] = NULL; continue; } if (me == 0) fread(&n,sizeof(int),1,fp); MPI_Bcast(&n,1,MPI_INT,0,world); if (n) { names[i] = new char[n]; if (me == 0) fread(names[i],sizeof(char),n,fp); MPI_Bcast(names[i],n,MPI_CHAR,0,world); count++; } else names[i] = NULL; } } // ---------------------------------------------------------------------- // computations on a group of atoms // ---------------------------------------------------------------------- /* ---------------------------------------------------------------------- count atoms in group ------------------------------------------------------------------------- */ bigint Group::count(int igroup) { int groupbit = bitmask[igroup]; int *mask = atom->mask; int nlocal = atom->nlocal; int n = 0; for (int i = 0; i < nlocal; i++) if (mask[i] & groupbit) n++; bigint nsingle = n; bigint nall; - MPI_Allreduce(&nsingle,&nall,1,MPI_UNSIGNED_LONG_LONG,MPI_SUM,world); + MPI_Allreduce(&nsingle,&nall,1,MPI_LMP_BIGINT,MPI_SUM,world); return nall; } /* ---------------------------------------------------------------------- count atoms in group and region ------------------------------------------------------------------------- */ bigint Group::count(int igroup, int iregion) { int groupbit = bitmask[igroup]; Region *region = domain->regions[iregion]; double **x = atom->x; int *mask = atom->mask; int nlocal = atom->nlocal; int n = 0; for (int i = 0; i < nlocal; i++) if (mask[i] & groupbit && region->match(x[i][0],x[i][1],x[i][2])) n++; bigint nsingle = n; bigint nall; - MPI_Allreduce(&nsingle,&nall,1,MPI_UNSIGNED_LONG_LONG,MPI_SUM,world); + MPI_Allreduce(&nsingle,&nall,1,MPI_LMP_BIGINT,MPI_SUM,world); return nall; } /* ---------------------------------------------------------------------- compute the total mass of group of atoms use either per-type mass or per-atom rmass ------------------------------------------------------------------------- */ double Group::mass(int igroup) { int groupbit = bitmask[igroup]; double *mass = atom->mass; double *rmass = atom->rmass; int *mask = atom->mask; int *type = atom->type; int nlocal = atom->nlocal; double one = 0.0; if (rmass) { for (int i = 0; i < nlocal; i++) if (mask[i] & groupbit) one += rmass[i]; } else { for (int i = 0; i < nlocal; i++) if (mask[i] & groupbit) one += mass[type[i]]; } double all; MPI_Allreduce(&one,&all,1,MPI_DOUBLE,MPI_SUM,world); return all; } /* ---------------------------------------------------------------------- compute the total mass of group of atoms in region use either per-type mass or per-atom rmass ------------------------------------------------------------------------- */ double Group::mass(int igroup, int iregion) { int groupbit = bitmask[igroup]; Region *region = domain->regions[iregion]; double **x = atom->x; double *mass = atom->mass; double *rmass = atom->rmass; int *mask = atom->mask; int *type = atom->type; int nlocal = atom->nlocal; double one = 0.0; if (rmass) { for (int i = 0; i < nlocal; i++) if (mask[i] & groupbit && region->match(x[i][0],x[i][1],x[i][2])) one += rmass[i]; } else { for (int i = 0; i < nlocal; i++) if (mask[i] & groupbit && region->match(x[i][0],x[i][1],x[i][2])) one += mass[type[i]]; } double all; MPI_Allreduce(&one,&all,1,MPI_DOUBLE,MPI_SUM,world); return all; } /* ---------------------------------------------------------------------- compute the total charge of group of atoms ------------------------------------------------------------------------- */ double Group::charge(int igroup) { int groupbit = bitmask[igroup]; double *q = atom->q; int *mask = atom->mask; int nlocal = atom->nlocal; double qone = 0.0; for (int i = 0; i < nlocal; i++) if (mask[i] & groupbit) qone += q[i]; double qall; MPI_Allreduce(&qone,&qall,1,MPI_DOUBLE,MPI_SUM,world); return qall; } /* ---------------------------------------------------------------------- compute the total charge of group of atoms in region ------------------------------------------------------------------------- */ double Group::charge(int igroup, int iregion) { int groupbit = bitmask[igroup]; Region *region = domain->regions[iregion]; double **x = atom->x; double *q = atom->q; int *mask = atom->mask; int nlocal = atom->nlocal; double qone = 0.0; for (int i = 0; i < nlocal; i++) if (mask[i] & groupbit && region->match(x[i][0],x[i][1],x[i][2])) qone += q[i]; double qall; MPI_Allreduce(&qone,&qall,1,MPI_DOUBLE,MPI_SUM,world); return qall; } /* ---------------------------------------------------------------------- compute the coordinate bounds of the group of atoms periodic images are not considered, so atoms are NOT unwrapped ------------------------------------------------------------------------- */ void Group::bounds(int igroup, double *minmax) { int groupbit = bitmask[igroup]; double extent[6]; extent[0] = extent[2] = extent[4] = BIG; extent[1] = extent[3] = extent[5] = -BIG; double **x = atom->x; int *mask = atom->mask; int nlocal = atom->nlocal; for (int i = 0; i < nlocal; i++) { if (mask[i] & groupbit) { extent[0] = MIN(extent[0],x[i][0]); extent[1] = MAX(extent[1],x[i][0]); extent[2] = MIN(extent[2],x[i][1]); extent[3] = MAX(extent[3],x[i][1]); extent[4] = MIN(extent[4],x[i][2]); extent[5] = MAX(extent[5],x[i][2]); } } // compute extent across all procs // flip sign of MIN to do it in one Allreduce MAX // set box by extent in shrink-wrapped dims extent[0] = -extent[0]; extent[2] = -extent[2]; extent[4] = -extent[4]; MPI_Allreduce(extent,minmax,6,MPI_DOUBLE,MPI_MAX,world); minmax[0] = -minmax[0]; minmax[2] = -minmax[2]; minmax[4] = -minmax[4]; } /* ---------------------------------------------------------------------- compute the coordinate bounds of the group of atoms in region periodic images are not considered, so atoms are NOT unwrapped ------------------------------------------------------------------------- */ void Group::bounds(int igroup, double *minmax, int iregion) { int groupbit = bitmask[igroup]; Region *region = domain->regions[iregion]; double extent[6]; extent[0] = extent[2] = extent[4] = BIG; extent[1] = extent[3] = extent[5] = -BIG; double **x = atom->x; int *mask = atom->mask; int nlocal = atom->nlocal; for (int i = 0; i < nlocal; i++) { if (mask[i] & groupbit && region->match(x[i][0],x[i][1],x[i][2])) { extent[0] = MIN(extent[0],x[i][0]); extent[1] = MAX(extent[1],x[i][0]); extent[2] = MIN(extent[2],x[i][1]); extent[3] = MAX(extent[3],x[i][1]); extent[4] = MIN(extent[4],x[i][2]); extent[5] = MAX(extent[5],x[i][2]); } } // compute extent across all procs // flip sign of MIN to do it in one Allreduce MAX // set box by extent in shrink-wrapped dims extent[0] = -extent[0]; extent[2] = -extent[2]; extent[4] = -extent[4]; MPI_Allreduce(extent,minmax,6,MPI_DOUBLE,MPI_MAX,world); minmax[0] = -minmax[0]; minmax[2] = -minmax[2]; minmax[4] = -minmax[4]; } /* ---------------------------------------------------------------------- compute the center-of-mass coords of group of atoms masstotal = total mass return center-of-mass coords in cm[] must unwrap atoms to compute center-of-mass correctly ------------------------------------------------------------------------- */ void Group::xcm(int igroup, double masstotal, double *cm) { int groupbit = bitmask[igroup]; double **x = atom->x; int *mask = atom->mask; int *type = atom->type; int *image = atom->image; double *mass = atom->mass; double *rmass = atom->rmass; int nlocal = atom->nlocal; double cmone[3]; cmone[0] = cmone[1] = cmone[2] = 0.0; double xprd = domain->xprd; double yprd = domain->yprd; double zprd = domain->zprd; int xbox,ybox,zbox; double massone; if (rmass) { for (int i = 0; i < nlocal; i++) if (mask[i] & groupbit) { xbox = (image[i] & 1023) - 512; ybox = (image[i] >> 10 & 1023) - 512; zbox = (image[i] >> 20) - 512; massone = rmass[i]; cmone[0] += (x[i][0] + xbox*xprd) * massone; cmone[1] += (x[i][1] + ybox*yprd) * massone; cmone[2] += (x[i][2] + zbox*zprd) * massone; } } else { for (int i = 0; i < nlocal; i++) if (mask[i] & groupbit) { xbox = (image[i] & 1023) - 512; ybox = (image[i] >> 10 & 1023) - 512; zbox = (image[i] >> 20) - 512; massone = mass[type[i]]; cmone[0] += (x[i][0] + xbox*xprd) * massone; cmone[1] += (x[i][1] + ybox*yprd) * massone; cmone[2] += (x[i][2] + zbox*zprd) * massone; } } MPI_Allreduce(cmone,cm,3,MPI_DOUBLE,MPI_SUM,world); if (masstotal > 0.0) { cm[0] /= masstotal; cm[1] /= masstotal; cm[2] /= masstotal; } } /* ---------------------------------------------------------------------- compute the center-of-mass coords of group of atoms in region mastotal = total mass return center-of-mass coords in cm[] must unwrap atoms to compute center-of-mass correctly ------------------------------------------------------------------------- */ void Group::xcm(int igroup, double masstotal, double *cm, int iregion) { int groupbit = bitmask[igroup]; Region *region = domain->regions[iregion]; double **x = atom->x; int *mask = atom->mask; int *type = atom->type; int *image = atom->image; double *mass = atom->mass; double *rmass = atom->rmass; int nlocal = atom->nlocal; double cmone[3]; cmone[0] = cmone[1] = cmone[2] = 0.0; double xprd = domain->xprd; double yprd = domain->yprd; double zprd = domain->zprd; int xbox,ybox,zbox; double massone; if (rmass) { for (int i = 0; i < nlocal; i++) if (mask[i] & groupbit && region->match(x[i][0],x[i][1],x[i][2])) { xbox = (image[i] & 1023) - 512; ybox = (image[i] >> 10 & 1023) - 512; zbox = (image[i] >> 20) - 512; massone = rmass[i]; cmone[0] += (x[i][0] + xbox*xprd) * massone; cmone[1] += (x[i][1] + ybox*yprd) * massone; cmone[2] += (x[i][2] + zbox*zprd) * massone; } } else { for (int i = 0; i < nlocal; i++) if (mask[i] & groupbit && region->match(x[i][0],x[i][1],x[i][2])) { xbox = (image[i] & 1023) - 512; ybox = (image[i] >> 10 & 1023) - 512; zbox = (image[i] >> 20) - 512; massone = mass[type[i]]; cmone[0] += (x[i][0] + xbox*xprd) * massone; cmone[1] += (x[i][1] + ybox*yprd) * massone; cmone[2] += (x[i][2] + zbox*zprd) * massone; } } MPI_Allreduce(cmone,cm,3,MPI_DOUBLE,MPI_SUM,world); if (masstotal > 0.0) { cm[0] /= masstotal; cm[1] /= masstotal; cm[2] /= masstotal; } } /* ---------------------------------------------------------------------- compute the center-of-mass velocity of group of atoms masstotal = total mass return center-of-mass velocity in cm[] ------------------------------------------------------------------------- */ void Group::vcm(int igroup, double masstotal, double *cm) { int groupbit = bitmask[igroup]; double **v = atom->v; int *mask = atom->mask; int *type = atom->type; double *mass = atom->mass; double *rmass = atom->rmass; int nlocal = atom->nlocal; double p[3],massone; p[0] = p[1] = p[2] = 0.0; if (rmass) { for (int i = 0; i < nlocal; i++) if (mask[i] & groupbit) { massone = rmass[i]; p[0] += v[i][0]*massone; p[1] += v[i][1]*massone; p[2] += v[i][2]*massone; } } else { for (int i = 0; i < nlocal; i++) if (mask[i] & groupbit) { massone = mass[type[i]]; p[0] += v[i][0]*massone; p[1] += v[i][1]*massone; p[2] += v[i][2]*massone; } } MPI_Allreduce(p,cm,3,MPI_DOUBLE,MPI_SUM,world); if (masstotal > 0.0) { cm[0] /= masstotal; cm[1] /= masstotal; cm[2] /= masstotal; } } /* ---------------------------------------------------------------------- compute the center-of-mass velocity of group of atoms in region masstotal = total mass return center-of-mass velocity in cm[] ------------------------------------------------------------------------- */ void Group::vcm(int igroup, double masstotal, double *cm, int iregion) { int groupbit = bitmask[igroup]; Region *region = domain->regions[iregion]; double **x = atom->x; double **v = atom->v; int *mask = atom->mask; int *type = atom->type; double *mass = atom->mass; double *rmass = atom->rmass; int nlocal = atom->nlocal; double p[3],massone; p[0] = p[1] = p[2] = 0.0; if (rmass) { for (int i = 0; i < nlocal; i++) if (mask[i] & groupbit && region->match(x[i][0],x[i][1],x[i][2])) { massone = rmass[i]; p[0] += v[i][0]*massone; p[1] += v[i][1]*massone; p[2] += v[i][2]*massone; } } else { for (int i = 0; i < nlocal; i++) if (mask[i] & groupbit && region->match(x[i][0],x[i][1],x[i][2])) { massone = mass[type[i]]; p[0] += v[i][0]*massone; p[1] += v[i][1]*massone; p[2] += v[i][2]*massone; } } MPI_Allreduce(p,cm,3,MPI_DOUBLE,MPI_SUM,world); if (masstotal > 0.0) { cm[0] /= masstotal; cm[1] /= masstotal; cm[2] /= masstotal; } } /* ---------------------------------------------------------------------- compute the total force on group of atoms ------------------------------------------------------------------------- */ void Group::fcm(int igroup, double *cm) { int groupbit = bitmask[igroup]; double **f = atom->f; int *mask = atom->mask; int nlocal = atom->nlocal; double flocal[3]; flocal[0] = flocal[1] = flocal[2] = 0.0; for (int i = 0; i < nlocal; i++) if (mask[i] & groupbit) { flocal[0] += f[i][0]; flocal[1] += f[i][1]; flocal[2] += f[i][2]; } MPI_Allreduce(flocal,cm,3,MPI_DOUBLE,MPI_SUM,world); } /* ---------------------------------------------------------------------- compute the total force on group of atoms in region ------------------------------------------------------------------------- */ void Group::fcm(int igroup, double *cm, int iregion) { int groupbit = bitmask[igroup]; Region *region = domain->regions[iregion]; double **x = atom->x; double **f = atom->f; int *mask = atom->mask; int nlocal = atom->nlocal; double flocal[3]; flocal[0] = flocal[1] = flocal[2] = 0.0; for (int i = 0; i < nlocal; i++) if (mask[i] & groupbit && region->match(x[i][0],x[i][1],x[i][2])) { flocal[0] += f[i][0]; flocal[1] += f[i][1]; flocal[2] += f[i][2]; } MPI_Allreduce(flocal,cm,3,MPI_DOUBLE,MPI_SUM,world); } /* ---------------------------------------------------------------------- compute the total kinetic energy of group of atoms and return it ------------------------------------------------------------------------- */ double Group::ke(int igroup) { int groupbit = bitmask[igroup]; double **v = atom->v; int *mask = atom->mask; int *type = atom->type; double *mass = atom->mass; double *rmass = atom->rmass; int nlocal = atom->nlocal; double one = 0.0; if (rmass) { for (int i = 0; i < nlocal; i++) if (mask[i] & groupbit) one += (v[i][0]*v[i][0] + v[i][1]*v[i][1] + v[i][2]*v[i][2]) * rmass[i]; } else { for (int i = 0; i < nlocal; i++) if (mask[i] & groupbit) one += (v[i][0]*v[i][0] + v[i][1]*v[i][1] + v[i][2]*v[i][2]) * mass[type[i]]; } double all; MPI_Allreduce(&one,&all,1,MPI_DOUBLE,MPI_SUM,world); all *= 0.5 * force->mvv2e; return all; } /* ---------------------------------------------------------------------- compute the total kinetic energy of group of atoms in region and return it ------------------------------------------------------------------------- */ double Group::ke(int igroup, int iregion) { int groupbit = bitmask[igroup]; Region *region = domain->regions[iregion]; double **x = atom->x; double **v = atom->v; int *mask = atom->mask; int *type = atom->type; double *mass = atom->mass; double *rmass = atom->rmass; int nlocal = atom->nlocal; double one = 0.0; if (rmass) { for (int i = 0; i < nlocal; i++) if (mask[i] & groupbit && region->match(x[i][0],x[i][1],x[i][2])) one += (v[i][0]*v[i][0] + v[i][1]*v[i][1] + v[i][2]*v[i][2]) * rmass[i]; } else { for (int i = 0; i < nlocal; i++) if (mask[i] & groupbit && region->match(x[i][0],x[i][1],x[i][2])) one += (v[i][0]*v[i][0] + v[i][1]*v[i][1] + v[i][2]*v[i][2]) * mass[type[i]]; } double all; MPI_Allreduce(&one,&all,1,MPI_DOUBLE,MPI_SUM,world); all *= 0.5 * force->mvv2e; return all; } /* ---------------------------------------------------------------------- compute the radius-of-gyration of group of atoms around center-of-mass cm must unwrap atoms to compute Rg correctly ------------------------------------------------------------------------- */ double Group::gyration(int igroup, double masstotal, double *cm) { int groupbit = bitmask[igroup]; double **x = atom->x; int *mask = atom->mask; int *type = atom->type; int *image = atom->image; double *mass = atom->mass; double *rmass = atom->rmass; int nlocal = atom->nlocal; int xbox,ybox,zbox; double dx,dy,dz,massone; double xprd = domain->xprd; double yprd = domain->yprd; double zprd = domain->zprd; double rg = 0.0; for (int i = 0; i < nlocal; i++) if (mask[i] & groupbit) { xbox = (image[i] & 1023) - 512; ybox = (image[i] >> 10 & 1023) - 512; zbox = (image[i] >> 20) - 512; dx = (x[i][0] + xbox*xprd) - cm[0]; dy = (x[i][1] + ybox*yprd) - cm[1]; dz = (x[i][2] + zbox*zprd) - cm[2]; if (rmass) massone = rmass[i]; else massone = mass[type[i]]; rg += (dx*dx + dy*dy + dz*dz) * massone; } double rg_all; MPI_Allreduce(&rg,&rg_all,1,MPI_DOUBLE,MPI_SUM,world); if (masstotal > 0.0) return sqrt(rg_all/masstotal); return 0.0; } /* ---------------------------------------------------------------------- compute the radius-of-gyration of group of atoms in region around center-of-mass cm must unwrap atoms to compute Rg correctly ------------------------------------------------------------------------- */ double Group::gyration(int igroup, double masstotal, double *cm, int iregion) { int groupbit = bitmask[igroup]; Region *region = domain->regions[iregion]; double **x = atom->x; int *mask = atom->mask; int *type = atom->type; int *image = atom->image; double *mass = atom->mass; double *rmass = atom->rmass; int nlocal = atom->nlocal; int xbox,ybox,zbox; double dx,dy,dz,massone; double xprd = domain->xprd; double yprd = domain->yprd; double zprd = domain->zprd; double rg = 0.0; for (int i = 0; i < nlocal; i++) if (mask[i] & groupbit && region->match(x[i][0],x[i][1],x[i][2])) { xbox = (image[i] & 1023) - 512; ybox = (image[i] >> 10 & 1023) - 512; zbox = (image[i] >> 20) - 512; dx = (x[i][0] + xbox*xprd) - cm[0]; dy = (x[i][1] + ybox*yprd) - cm[1]; dz = (x[i][2] + zbox*zprd) - cm[2]; if (rmass) massone = rmass[i]; else massone = mass[type[i]]; rg += (dx*dx + dy*dy + dz*dz) * massone; } double rg_all; MPI_Allreduce(&rg,&rg_all,1,MPI_DOUBLE,MPI_SUM,world); if (masstotal > 0.0) return sqrt(rg_all/masstotal); return 0.0; } /* ---------------------------------------------------------------------- compute the angular momentum L (lmom) of group around center-of-mass cm must unwrap atoms to compute L correctly ------------------------------------------------------------------------- */ void Group::angmom(int igroup, double *cm, double *lmom) { int groupbit = bitmask[igroup]; double **x = atom->x; double **v = atom->v; int *mask = atom->mask; int *type = atom->type; int *image = atom->image; double *mass = atom->mass; double *rmass = atom->rmass; int nlocal = atom->nlocal; int xbox,ybox,zbox; double dx,dy,dz,massone; double xprd = domain->xprd; double yprd = domain->yprd; double zprd = domain->zprd; double p[3]; p[0] = p[1] = p[2] = 0.0; for (int i = 0; i < nlocal; i++) if (mask[i] & groupbit) { xbox = (image[i] & 1023) - 512; ybox = (image[i] >> 10 & 1023) - 512; zbox = (image[i] >> 20) - 512; dx = (x[i][0] + xbox*xprd) - cm[0]; dy = (x[i][1] + ybox*yprd) - cm[1]; dz = (x[i][2] + zbox*zprd) - cm[2]; if (rmass) massone = rmass[i]; else massone = mass[type[i]]; p[0] += massone * (dy*v[i][2] - dz*v[i][1]); p[1] += massone * (dz*v[i][0] - dx*v[i][2]); p[2] += massone * (dx*v[i][1] - dy*v[i][0]); } MPI_Allreduce(p,lmom,3,MPI_DOUBLE,MPI_SUM,world); } /* ---------------------------------------------------------------------- compute the angular momentum L (lmom) of group of atoms in region around center-of-mass cm must unwrap atoms to compute L correctly ------------------------------------------------------------------------- */ void Group::angmom(int igroup, double *cm, double *lmom, int iregion) { int groupbit = bitmask[igroup]; Region *region = domain->regions[iregion]; double **x = atom->x; double **v = atom->v; int *mask = atom->mask; int *type = atom->type; int *image = atom->image; double *mass = atom->mass; double *rmass = atom->rmass; int nlocal = atom->nlocal; int xbox,ybox,zbox; double dx,dy,dz,massone; double xprd = domain->xprd; double yprd = domain->yprd; double zprd = domain->zprd; double p[3]; p[0] = p[1] = p[2] = 0.0; for (int i = 0; i < nlocal; i++) if (mask[i] & groupbit && region->match(x[i][0],x[i][1],x[i][2])) { xbox = (image[i] & 1023) - 512; ybox = (image[i] >> 10 & 1023) - 512; zbox = (image[i] >> 20) - 512; dx = (x[i][0] + xbox*xprd) - cm[0]; dy = (x[i][1] + ybox*yprd) - cm[1]; dz = (x[i][2] + zbox*zprd) - cm[2]; if (rmass) massone = rmass[i]; else massone = mass[type[i]]; p[0] += massone * (dy*v[i][2] - dz*v[i][1]); p[1] += massone * (dz*v[i][0] - dx*v[i][2]); p[2] += massone * (dx*v[i][1] - dy*v[i][0]); } MPI_Allreduce(p,lmom,3,MPI_DOUBLE,MPI_SUM,world); } /* ---------------------------------------------------------------------- compute the torque T (tq) on group around center-of-mass cm must unwrap atoms to compute T correctly ------------------------------------------------------------------------- */ void Group::torque(int igroup, double *cm, double *tq) { int groupbit = bitmask[igroup]; double **x = atom->x; double **f = atom->f; int *mask = atom->mask; int *image = atom->image; int nlocal = atom->nlocal; int xbox,ybox,zbox; double dx,dy,dz; double xprd = domain->xprd; double yprd = domain->yprd; double zprd = domain->zprd; double tlocal[3]; tlocal[0] = tlocal[1] = tlocal[2] = 0.0; for (int i = 0; i < nlocal; i++) if (mask[i] & groupbit) { xbox = (image[i] & 1023) - 512; ybox = (image[i] >> 10 & 1023) - 512; zbox = (image[i] >> 20) - 512; dx = (x[i][0] + xbox*xprd) - cm[0]; dy = (x[i][1] + ybox*yprd) - cm[1]; dz = (x[i][2] + zbox*zprd) - cm[2]; tlocal[0] += dy*f[i][2] - dz*f[i][1]; tlocal[1] += dz*f[i][0] - dx*f[i][2]; tlocal[2] += dx*f[i][1] - dy*f[i][0]; } MPI_Allreduce(tlocal,tq,3,MPI_DOUBLE,MPI_SUM,world); } /* ---------------------------------------------------------------------- compute the torque T (tq) on group of atoms in region around center-of-mass cm must unwrap atoms to compute T correctly ------------------------------------------------------------------------- */ void Group::torque(int igroup, double *cm, double *tq, int iregion) { int groupbit = bitmask[igroup]; Region *region = domain->regions[iregion]; double **x = atom->x; double **f = atom->f; int *mask = atom->mask; int *image = atom->image; int nlocal = atom->nlocal; int xbox,ybox,zbox; double dx,dy,dz; double xprd = domain->xprd; double yprd = domain->yprd; double zprd = domain->zprd; double tlocal[3]; tlocal[0] = tlocal[1] = tlocal[2] = 0.0; for (int i = 0; i < nlocal; i++) if (mask[i] & groupbit && region->match(x[i][0],x[i][1],x[i][2])) { xbox = (image[i] & 1023) - 512; ybox = (image[i] >> 10 & 1023) - 512; zbox = (image[i] >> 20) - 512; dx = (x[i][0] + xbox*xprd) - cm[0]; dy = (x[i][1] + ybox*yprd) - cm[1]; dz = (x[i][2] + zbox*zprd) - cm[2]; tlocal[0] += dy*f[i][2] - dz*f[i][1]; tlocal[1] += dz*f[i][0] - dx*f[i][2]; tlocal[2] += dx*f[i][1] - dy*f[i][0]; } MPI_Allreduce(tlocal,tq,3,MPI_DOUBLE,MPI_SUM,world); } /* ---------------------------------------------------------------------- compute moment of inertia tensor around center-of-mass cm of group must unwrap atoms to compute itensor correctly ------------------------------------------------------------------------- */ void Group::inertia(int igroup, double *cm, double itensor[3][3]) { int i,j; int groupbit = bitmask[igroup]; double **x = atom->x; int *mask = atom->mask; int *type = atom->type; int *image = atom->image; double *mass = atom->mass; double *rmass = atom->rmass; int nlocal = atom->nlocal; int xbox,ybox,zbox; double dx,dy,dz,massone; double xprd = domain->xprd; double yprd = domain->yprd; double zprd = domain->zprd; double ione[3][3]; for (i = 0; i < 3; i++) for (j = 0; j < 3; j++) ione[i][j] = 0.0; for (i = 0; i < nlocal; i++) if (mask[i] & groupbit) { xbox = (image[i] & 1023) - 512; ybox = (image[i] >> 10 & 1023) - 512; zbox = (image[i] >> 20) - 512; dx = (x[i][0] + xbox*xprd) - cm[0]; dy = (x[i][1] + ybox*yprd) - cm[1]; dz = (x[i][2] + zbox*zprd) - cm[2]; if (rmass) massone = rmass[i]; else massone = mass[type[i]]; ione[0][0] += massone * (dy*dy + dz*dz); ione[1][1] += massone * (dx*dx + dz*dz); ione[2][2] += massone * (dx*dx + dy*dy); ione[0][1] -= massone * dx*dy; ione[1][2] -= massone * dy*dz; ione[0][2] -= massone * dx*dz; } ione[1][0] = ione[0][1]; ione[2][1] = ione[1][2]; ione[2][0] = ione[0][2]; MPI_Allreduce(&ione[0][0],&itensor[0][0],9,MPI_DOUBLE,MPI_SUM,world); } /* ---------------------------------------------------------------------- compute moment of inertia tensor around cm of group of atoms in region must unwrap atoms to compute itensor correctly ------------------------------------------------------------------------- */ void Group::inertia(int igroup, double *cm, double itensor[3][3], int iregion) { int i,j; int groupbit = bitmask[igroup]; Region *region = domain->regions[iregion]; double **x = atom->x; int *mask = atom->mask; int *type = atom->type; int *image = atom->image; double *mass = atom->mass; double *rmass = atom->rmass; int nlocal = atom->nlocal; int xbox,ybox,zbox; double dx,dy,dz,massone; double xprd = domain->xprd; double yprd = domain->yprd; double zprd = domain->zprd; double ione[3][3]; for (i = 0; i < 3; i++) for (j = 0; j < 3; j++) ione[i][j] = 0.0; for (i = 0; i < nlocal; i++) if (mask[i] & groupbit && region->match(x[i][0],x[i][1],x[i][2])) { xbox = (image[i] & 1023) - 512; ybox = (image[i] >> 10 & 1023) - 512; zbox = (image[i] >> 20) - 512; dx = (x[i][0] + xbox*xprd) - cm[0]; dy = (x[i][1] + ybox*yprd) - cm[1]; dz = (x[i][2] + zbox*zprd) - cm[2]; if (rmass) massone = rmass[i]; else massone = mass[type[i]]; ione[0][0] += massone * (dy*dy + dz*dz); ione[1][1] += massone * (dx*dx + dz*dz); ione[2][2] += massone * (dx*dx + dy*dy); ione[0][1] -= massone * dx*dy; ione[1][2] -= massone * dy*dz; ione[0][2] -= massone * dx*dz; } ione[1][0] = ione[0][1]; ione[2][1] = ione[1][2]; ione[2][0] = ione[0][2]; MPI_Allreduce(&ione[0][0],&itensor[0][0],9,MPI_DOUBLE,MPI_SUM,world); } /* ---------------------------------------------------------------------- compute angular velocity omega from L = Iw, inverting I to solve for w really not a group operation, but L and I were computed for a group ------------------------------------------------------------------------- */ void Group::omega(double *angmom, double inertia[3][3], double *w) { double inverse[3][3]; inverse[0][0] = inertia[1][1]*inertia[2][2] - inertia[1][2]*inertia[2][1]; inverse[0][1] = -(inertia[0][1]*inertia[2][2] - inertia[0][2]*inertia[2][1]); inverse[0][2] = inertia[0][1]*inertia[1][2] - inertia[0][2]*inertia[1][1]; inverse[1][0] = -(inertia[1][0]*inertia[2][2] - inertia[1][2]*inertia[2][0]); inverse[1][1] = inertia[0][0]*inertia[2][2] - inertia[0][2]*inertia[2][0]; inverse[1][2] = -(inertia[0][0]*inertia[1][2] - inertia[0][2]*inertia[1][0]); inverse[2][0] = inertia[1][0]*inertia[2][1] - inertia[1][1]*inertia[2][0]; inverse[2][1] = -(inertia[0][0]*inertia[2][1] - inertia[0][1]*inertia[2][0]); inverse[2][2] = inertia[0][0]*inertia[1][1] - inertia[0][1]*inertia[1][0]; double determinant = inertia[0][0]*inertia[1][1]*inertia[2][2] + inertia[0][1]*inertia[1][2]*inertia[2][0] + inertia[0][2]*inertia[1][0]*inertia[2][1] - inertia[0][0]*inertia[1][2]*inertia[2][1] - inertia[0][1]*inertia[1][0]*inertia[2][2] - inertia[2][0]*inertia[1][1]*inertia[0][2]; if (determinant > 0.0) for (int i = 0; i < 3; i++) for (int j = 0; j < 3; j++) inverse[i][j] /= determinant; w[0] = inverse[0][0]*angmom[0] + inverse[0][1]*angmom[1] + inverse[0][2]*angmom[2]; w[1] = inverse[1][0]*angmom[0] + inverse[1][1]*angmom[1] + inverse[1][2]*angmom[2]; w[2] = inverse[2][0]*angmom[0] + inverse[2][1]*angmom[1] + inverse[2][2]*angmom[2]; } diff --git a/src/integrate.cpp b/src/integrate.cpp index ca5297b59..5b7d8df19 100644 --- a/src/integrate.cpp +++ b/src/integrate.cpp @@ -1,131 +1,132 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain 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 "integrate.h" +#include "lmptype.h" #include "update.h" #include "modify.h" #include "compute.h" using namespace LAMMPS_NS; /* ---------------------------------------------------------------------- */ Integrate::Integrate(LAMMPS *lmp, int narg, char **arg) : Pointers(lmp) { elist_global = elist_atom = NULL; vlist_global = vlist_atom = NULL; } /* ---------------------------------------------------------------------- */ Integrate::~Integrate() { delete [] elist_global; delete [] elist_atom; delete [] vlist_global; delete [] vlist_atom; } /* ---------------------------------------------------------------------- setup lists of computes for global and per-atom PE and pressure ------------------------------------------------------------------------- */ void Integrate::ev_setup() { delete [] elist_global; delete [] elist_atom; delete [] vlist_global; delete [] vlist_atom; elist_global = elist_atom = NULL; vlist_global = vlist_atom = NULL; nelist_global = nelist_atom = 0; nvlist_global = nvlist_atom = 0; for (int i = 0; i < modify->ncompute; i++) { if (modify->compute[i]->peflag) nelist_global++; if (modify->compute[i]->peatomflag) nelist_atom++; if (modify->compute[i]->pressflag) nvlist_global++; if (modify->compute[i]->pressatomflag) nvlist_atom++; } if (nelist_global) elist_global = new Compute*[nelist_global]; if (nelist_atom) elist_atom = new Compute*[nelist_atom]; if (nvlist_global) vlist_global = new Compute*[nvlist_global]; if (nvlist_atom) vlist_atom = new Compute*[nvlist_atom]; nelist_global = nelist_atom = 0; nvlist_global = nvlist_atom = 0; for (int i = 0; i < modify->ncompute; i++) { if (modify->compute[i]->peflag) elist_global[nelist_global++] = modify->compute[i]; if (modify->compute[i]->peatomflag) elist_atom[nelist_atom++] = modify->compute[i]; if (modify->compute[i]->pressflag) vlist_global[nvlist_global++] = modify->compute[i]; if (modify->compute[i]->pressatomflag) vlist_atom[nvlist_atom++] = modify->compute[i]; } } /* ---------------------------------------------------------------------- set eflag,vflag for current iteration invoke matchstep() on all timestep-dependent computes to clear their arrays eflag/vflag based on computes that need info on this ntimestep eflag = 0 = no energy computation eflag = 1 = global energy only eflag = 2 = per-atom energy only eflag = 3 = both global and per-atom energy vflag = 0 = no virial computation (pressure) vflag = 1 = global virial with pair portion via sum of pairwise interactions vflag = 2 = global virial with pair portion via F dot r including ghosts vflag = 4 = per-atom virial only vflag = 5 or 6 = both global and per-atom virial ------------------------------------------------------------------------- */ -void Integrate::ev_set(int ntimestep) +void Integrate::ev_set(bigint ntimestep) { int i,flag; flag = 0; int eflag_global = 0; for (i = 0; i < nelist_global; i++) if (elist_global[i]->matchstep(ntimestep)) flag = 1; if (flag) eflag_global = 1; flag = 0; int eflag_atom = 0; for (i = 0; i < nelist_atom; i++) if (elist_atom[i]->matchstep(ntimestep)) flag = 1; if (flag) eflag_atom = 2; if (eflag_global) update->eflag_global = ntimestep; if (eflag_atom) update->eflag_atom = ntimestep; eflag = eflag_global + eflag_atom; flag = 0; int vflag_global = 0; for (i = 0; i < nvlist_global; i++) if (vlist_global[i]->matchstep(ntimestep)) flag = 1; if (flag) vflag_global = virial_style; flag = 0; int vflag_atom = 0; for (i = 0; i < nvlist_atom; i++) if (vlist_atom[i]->matchstep(ntimestep)) flag = 1; if (flag) vflag_atom = 4; if (vflag_global) update->vflag_global = ntimestep; if (vflag_atom) update->vflag_atom = ntimestep; vflag = vflag_global + vflag_atom; } diff --git a/src/integrate.h b/src/integrate.h index 8c7d948b3..bcbc71192 100644 --- a/src/integrate.h +++ b/src/integrate.h @@ -1,50 +1,51 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain 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_INTEGRATE_H #define LMP_INTEGRATE_H #include "pointers.h" +#include "lmptype.h" namespace LAMMPS_NS { class Integrate : protected Pointers { public: Integrate(class LAMMPS *, int, char **); virtual ~Integrate(); virtual void init() = 0; virtual void setup() = 0; virtual void setup_minimal(int) = 0; virtual void run(int) = 0; virtual void cleanup() {} virtual void reset_dt() {} virtual double memory_usage() {return 0.0;} protected: int eflag,vflag; // flags for energy/virial computation int virial_style; // compute virial explicitly or implicitly int nelist_global,nelist_atom; // # of PE,virial computes to check int nvlist_global,nvlist_atom; class Compute **elist_global; // lists of PE,virial Computes class Compute **elist_atom; class Compute **vlist_global; class Compute **vlist_atom; void ev_setup(); - void ev_set(int); + void ev_set(bigint); }; } #endif diff --git a/src/lammps.cpp b/src/lammps.cpp index 6b87c0a33..97b07922a 100644 --- a/src/lammps.cpp +++ b/src/lammps.cpp @@ -1,351 +1,358 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ #include "mpi.h" #include "string.h" #include "lammps.h" #include "memory.h" #include "error.h" #include "universe.h" #include "input.h" #include "atom.h" #include "update.h" #include "neighbor.h" #include "comm.h" #include "domain.h" #include "force.h" #include "modify.h" #include "group.h" #include "output.h" #include "timer.h" using namespace LAMMPS_NS; /* ---------------------------------------------------------------------- start up LAMMPS allocate fundamental classes (memory, error, universe, input) parse input switches initialize communicators, screen & logfile output input is allocated at end after MPI info is setup ------------------------------------------------------------------------- */ LAMMPS::LAMMPS(int narg, char **arg, MPI_Comm communicator) { memory = new Memory(this); error = new Error(this); universe = new Universe(this,communicator); output = NULL; screen = NULL; logfile = NULL; // parse input switches int inflag = 0; int screenflag = 0; int logflag = 0; int iarg = 1; while (iarg < narg) { if (strcmp(arg[iarg],"-partition") == 0) { universe->existflag = 1; if (iarg+2 > narg) error->universe_all("Invalid command-line argument"); iarg++; while (iarg < narg && arg[iarg][0] != '-') { universe->add_world(arg[iarg]); iarg++; } } else if (strcmp(arg[iarg],"-in") == 0) { if (iarg+2 > narg) error->universe_all("Invalid command-line argument"); inflag = iarg + 1; iarg += 2; } else if (strcmp(arg[iarg],"-screen") == 0) { if (iarg+2 > narg) error->universe_all("Invalid command-line argument"); screenflag = iarg + 1; iarg += 2; } else if (strcmp(arg[iarg],"-log") == 0) { if (iarg+2 > narg) error->universe_all("Invalid command-line argument"); logflag = iarg + 1; iarg += 2; } else if (strcmp(arg[iarg],"-var") == 0) { if (iarg+3 > narg) error->universe_all("Invalid command-line argument"); iarg += 3; } else if (strcmp(arg[iarg],"-echo") == 0) { if (iarg+2 > narg) error->universe_all("Invalid command-line argument"); iarg += 2; } else error->universe_all("Invalid command-line argument"); } // if no partition command-line switch, universe is one world w/ all procs if (universe->existflag == 0) universe->add_world(NULL); // sum of procs in all worlds must equal total # of procs if (!universe->consistent()) error->universe_all("Processor partitions are inconsistent"); // universe cannot use stdin for input file if (universe->existflag && inflag == 0) error->universe_all("Must use -in switch with multiple partitions"); // set universe screen and logfile if (universe->me == 0) { if (screenflag == 0) universe->uscreen = stdout; else if (strcmp(arg[screenflag],"none") == 0) universe->uscreen = NULL; else { universe->uscreen = fopen(arg[screenflag],"w"); if (universe->uscreen == NULL) error->universe_one("Cannot open universe screen file"); } if (logflag == 0) { universe->ulogfile = fopen("log.lammps","w"); if (universe->ulogfile == NULL) error->universe_one("Cannot open log.lammps"); } else if (strcmp(arg[logflag],"none") == 0) universe->ulogfile = NULL; else { universe->ulogfile = fopen(arg[logflag],"w"); if (universe->ulogfile == NULL) error->universe_one("Cannot open universe log file"); } } if (universe->me > 0) { if (screenflag == 0) universe->uscreen = stdout; else universe->uscreen = NULL; universe->ulogfile = NULL; } // universe does not exist on its own, only a single world // inherit settings from universe // set world screen, logfile, communicator, infile // open input script if from file if (universe->existflag == 0) { screen = universe->uscreen; logfile = universe->ulogfile; world = universe->uworld; infile = NULL; if (universe->me == 0) { if (inflag == 0) infile = stdin; else infile = fopen(arg[inflag],"r"); if (infile == NULL) { char str[128]; sprintf(str,"Cannot open input script %s",arg[inflag]); error->one(str); } } if (universe->me == 0) { if (screen) fprintf(screen,"LAMMPS (%s)\n",universe->version); if (logfile) fprintf(logfile,"LAMMPS (%s)\n",universe->version); } // universe is one or more worlds // split into separate communicators // set world screen, logfile, communicator, infile // open input script } else { int me; MPI_Comm_split(universe->uworld,universe->iworld,0,&world); MPI_Comm_rank(world,&me); if (me == 0) { if (screenflag == 0) { char str[32]; sprintf(str,"screen.%d",universe->iworld); screen = fopen(str,"w"); if (screen == NULL) error->one("Cannot open screen file"); } else if (strcmp(arg[screenflag],"none") == 0) screen = NULL; else { char str[128]; sprintf(str,"%s.%d",arg[screenflag],universe->iworld); screen = fopen(str,"w"); if (screen == NULL) error->one("Cannot open screen file"); } } else screen = NULL; if (me == 0) { if (logflag == 0) { char str[32]; sprintf(str,"log.lammps.%d",universe->iworld); logfile = fopen(str,"w"); if (logfile == NULL) error->one("Cannot open logfile"); } else if (strcmp(arg[logflag],"none") == 0) logfile = NULL; else { char str[128]; sprintf(str,"%s.%d",arg[logflag],universe->iworld); logfile = fopen(str,"w"); if (logfile == NULL) error->one("Cannot open logfile"); } } else logfile = NULL; if (me == 0) { infile = fopen(arg[inflag],"r"); if (infile == NULL) { char str[128]; sprintf(str,"Cannot open input script %s",arg[inflag]); error->one(str); } } else infile = NULL; // screen and logfile messages for universe and world if (universe->me == 0) { if (universe->uscreen) { fprintf(universe->uscreen,"LAMMPS (%s)\n",universe->version); fprintf(universe->uscreen,"Running on %d partitions of processors\n", universe->nworlds); } if (universe->ulogfile) { fprintf(universe->ulogfile,"LAMMPS (%s)\n",universe->version); fprintf(universe->ulogfile,"Running on %d partitions of processors\n", universe->nworlds); } } if (me == 0) { if (screen) { fprintf(screen,"LAMMPS (%s)\n",universe->version); fprintf(screen,"Processor partition = %d\n",universe->iworld); } if (logfile) { fprintf(logfile,"LAMMPS (%s)\n",universe->version); fprintf(logfile,"Processor partition = %d\n",universe->iworld); } } } - // check datatype sizes + // check datatype settings in lmptype.h - if (sizeof(bigint) != 8) - error->all("No support for 8-byte unsigned integers"); + if (sizeof(smallint) != sizeof(int)) + error->all("Smallint setting in lmptype.h is invalid"); + if (sizeof(tagint) < sizeof(smallint)) + error->all("Tagint setting in lmptype.h is invalid"); + if (sizeof(bigint) < sizeof(tagint)) + error->all("Bigint setting in lmptype.h is invalid"); int mpisize; - MPI_Type_size(MPI_UNSIGNED_LONG_LONG,&mpisize); - if (mpisize != 8) - error->all("MPI_UNSIGNED_LONG_LONG is not 8-byte data type"); + MPI_Type_size(MPI_LMP_TAGINT,&mpisize); + if (mpisize != sizeof(tagint)) + error->all("MPI_LMP_TAGINT and tagint in lmptype.h are not compatible"); + MPI_Type_size(MPI_LMP_BIGINT,&mpisize); + if (mpisize != sizeof(bigint)) + error->all("MPI_LMP_BIGINT and bigint in lmptype.h are not compatible"); // allocate input class now that MPI is fully setup input = new Input(this,narg,arg); // allocate top-level classes create(); } /* ---------------------------------------------------------------------- shutdown LAMMPS delete top-level classes close screen and log files in world and universe output files were already closed in destroy() delete fundamental classes ------------------------------------------------------------------------- */ LAMMPS::~LAMMPS() { destroy(); if (universe->nworlds == 1) { if (logfile) fclose(logfile); } else { if (screen && screen != stdout) fclose(screen); if (logfile) fclose(logfile); if (universe->ulogfile) fclose(universe->ulogfile); } if (world != universe->uworld) MPI_Comm_free(&world); delete input; delete universe; delete error; delete memory; } /* ---------------------------------------------------------------------- allocate single instance of top-level classes fundamental classes are allocated in constructor ------------------------------------------------------------------------- */ void LAMMPS::create() { atom = new Atom(this); neighbor = new Neighbor(this); comm = new Comm(this); domain = new Domain(this); group = new Group(this); force = new Force(this); // must be after group, to create temperature modify = new Modify(this); output = new Output(this); // must be after group, so "all" exists // must be after modify so can create Computes update = new Update(this); // must be after output, force, neighbor timer = new Timer(this); } /* ---------------------------------------------------------------------- initialize top-level classes ------------------------------------------------------------------------- */ void LAMMPS::init() { update->init(); force->init(); // pair must come after update due to minimizer domain->init(); atom->init(); // atom must come after force: // atom deletes extra array // used by fix shear_history::unpack_restart() // when force->pair->gran_history creates fix ?? modify->init(); // modify must come after update, force, atom, domain neighbor->init(); // neighbor must come after force, modify comm->init(); // comm must come after force, modify, neighbor output->init(); // output must come after domain, force, modify timer->init(); } /* ---------------------------------------------------------------------- delete single instance of top-level classes fundamental classes are deleted in destructor ------------------------------------------------------------------------- */ void LAMMPS::destroy() { delete update; delete neighbor; delete comm; delete force; delete group; delete output; delete modify; // modify must come after output, force, update // since they delete fixes delete domain; // domain must come after modify // since fix destructors access domain delete atom; // atom must come after modify, neighbor // since fixes delete callbacks in atom delete timer; } diff --git a/src/library.cpp b/src/library.cpp index 546ad4f3f..2b2cc3977 100644 --- a/src/library.cpp +++ b/src/library.cpp @@ -1,411 +1,411 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ // C or Fortran style library interface to LAMMPS // customize by adding new LAMMPS-specific functions #include "mpi.h" #include "string.h" #include "stdlib.h" #include "library.h" #include "lmptype.h" #include "lammps.h" #include "input.h" #include "atom.h" #include "domain.h" #include "update.h" #include "group.h" #include "input.h" #include "variable.h" #include "modify.h" #include "compute.h" #include "fix.h" using namespace LAMMPS_NS; /* ---------------------------------------------------------------------- create an instance of LAMMPS and return pointer to it pass in command-line args and MPI communicator to run on ------------------------------------------------------------------------- */ void lammps_open(int argc, char **argv, MPI_Comm communicator, void **ptr) { LAMMPS *lmp = new LAMMPS(argc,argv,communicator); *ptr = (void *) lmp; } /* ---------------------------------------------------------------------- create an instance of LAMMPS and return pointer to it caller doesn't know MPI communicator, so use MPI_COMM_WORLD intialize MPI if needed ------------------------------------------------------------------------- */ void lammps_open_no_mpi(int argc, char **argv, void **ptr) { int flag; MPI_Initialized(&flag); if (!flag) { int argc = 0; char **argv = NULL; MPI_Init(&argc,&argv); } MPI_Comm communicator = MPI_COMM_WORLD; LAMMPS *lmp = new LAMMPS(argc,argv,communicator); *ptr = (void *) lmp; } /* ---------------------------------------------------------------------- destruct an instance of LAMMPS ------------------------------------------------------------------------- */ void lammps_close(void *ptr) { LAMMPS *lmp = (LAMMPS *) ptr; delete lmp; } /* ---------------------------------------------------------------------- process an input script in filename str ------------------------------------------------------------------------- */ void lammps_file(void *ptr, char *str) { LAMMPS *lmp = (LAMMPS *) ptr; lmp->input->file(str); } /* ---------------------------------------------------------------------- process a single input command in str ------------------------------------------------------------------------- */ char *lammps_command(void *ptr, char *str) { LAMMPS *lmp = (LAMMPS *) ptr; return lmp->input->one(str); } /* ---------------------------------------------------------------------- clean-up function to free memory allocated by lib and returned to caller ------------------------------------------------------------------------- */ void lammps_free(void *ptr) { free(ptr); } /* ---------------------------------------------------------------------- add LAMMPS-specific library functions all must receive LAMMPS pointer as argument customize by adding a function here and in library.h header file ------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- extract a pointer to an internal LAMMPS global entity name = desired quantity, e.g. dt or boxyhi or natoms returns a void pointer to the entity which the caller can cast to the proper data type returns a NULL if name not listed below customize by adding names ------------------------------------------------------------------------- */ void *lammps_extract_global(void *ptr, char *name) { LAMMPS *lmp = (LAMMPS *) ptr; if (strcmp(name,"dt") == 0) return (void *) &lmp->update->dt; if (strcmp(name,"boxxlo") == 0) return (void *) &lmp->domain->boxlo[0]; if (strcmp(name,"boxxhi") == 0) return (void *) &lmp->domain->boxhi[0]; if (strcmp(name,"boxylo") == 0) return (void *) &lmp->domain->boxlo[1]; if (strcmp(name,"boxyhi") == 0) return (void *) &lmp->domain->boxhi[1]; if (strcmp(name,"boxzlo") == 0) return (void *) &lmp->domain->boxlo[2]; if (strcmp(name,"boxzhi") == 0) return (void *) &lmp->domain->boxhi[2]; if (strcmp(name,"natoms") == 0) return (void *) &lmp->atom->natoms; if (strcmp(name,"nlocal") == 0) return (void *) &lmp->atom->nlocal; return NULL; } /* ---------------------------------------------------------------------- extract a pointer to an internal LAMMPS atom-based entity name = desired quantity, e.g. x or mass returns a void pointer to the entity which the caller can cast to the proper data type returns a NULL if Atom::extract() does not recognize the name customize by adding names to Atom::extract() ------------------------------------------------------------------------- */ void *lammps_extract_atom(void *ptr, char *name) { LAMMPS *lmp = (LAMMPS *) ptr; return lmp->atom->extract(name); } /* ---------------------------------------------------------------------- extract a pointer to an internal LAMMPS compute-based entity id = compute ID style = 0 for global data, 1 for per-atom data, 2 for local data type = 0 for scalar, 1 for vector, 2 for array returns a void pointer to the compute's internal data structure for the entity which the caller can cast to the proper data type returns a NULL if id is not recognized or style/type not supported IMPORTANT: if the compute is not current it will be invoked LAMMPS cannot easily check if it is valid to invoke the compute, so caller must insure that it is OK ------------------------------------------------------------------------- */ void *lammps_extract_compute(void *ptr, char *id, int style, int type) { LAMMPS *lmp = (LAMMPS *) ptr; int icompute = lmp->modify->find_compute(id); if (icompute < 0) return NULL; Compute *compute = lmp->modify->compute[icompute]; if (style == 0) { if (type == 0) { if (!compute->scalar_flag) return NULL; if (compute->invoked_scalar != lmp->update->ntimestep) compute->compute_scalar(); return (void *) &compute->scalar; } if (type == 1) { if (!compute->vector_flag) return NULL; if (compute->invoked_vector != lmp->update->ntimestep) compute->compute_vector(); return (void *) compute->vector; } if (type == 2) { if (!compute->array_flag) return NULL; if (compute->invoked_array != lmp->update->ntimestep) compute->compute_array(); return (void *) compute->array; } } if (style == 1) { if (!compute->peratom_flag) return NULL; if (type == 1) { if (compute->invoked_peratom != lmp->update->ntimestep) compute->compute_peratom(); return (void *) compute->vector_atom; } if (type == 2) { if (compute->invoked_peratom != lmp->update->ntimestep) compute->compute_peratom(); return (void *) compute->array_atom; } } if (style == 2) { if (!compute->local_flag) return NULL; if (type == 1) { if (compute->invoked_local != lmp->update->ntimestep) compute->compute_local(); return (void *) compute->vector_local; } if (type == 2) { if (compute->invoked_local != lmp->update->ntimestep) compute->compute_local(); return (void *) compute->array_local; } } return NULL; } /* ---------------------------------------------------------------------- extract a pointer to an internal LAMMPS fix-based entity id = fix ID style = 0 for global data, 1 for per-atom data, 2 for local data type = 0 for scalar, 1 for vector, 2 for array i,j = indices needed only to specify which global vector or array value for global data, returns a pointer to a memory location which is allocated by this function which the caller can cast to a (double *) which points to the value for per-atom or local data, returns a pointer to the fix's internal data structure for the entity which the caller can cast to the proper data type returns a NULL if id is not recognized or style/type not supported IMPORTANT: for global data, this function allocates a double to store the value in, so the caller must free this memory to avoid a leak, e.g. double *dptr = (double *) lammps_extract_fix(); double value = *dptr; free(dptr); IMPORTANT: LAMMPS cannot easily check when info extracted from the fix is valid, so caller must insure that it is OK ------------------------------------------------------------------------- */ void *lammps_extract_fix(void *ptr, char *id, int style, int type, int i, int j) { LAMMPS *lmp = (LAMMPS *) ptr; int ifix = lmp->modify->find_fix(id); if (ifix < 0) return NULL; Fix *fix = lmp->modify->fix[ifix]; if (style == 0) { double *dptr = (double *) malloc(sizeof(double)); if (type == 0) { if (!fix->scalar_flag) return NULL; *dptr = fix->compute_scalar(); return (void *) dptr; } if (type == 1) { if (!fix->vector_flag) return NULL; *dptr = fix->compute_vector(i); return (void *) dptr; } if (type == 2) { if (!fix->array_flag) return NULL; *dptr = fix->compute_array(i,j); return (void *) dptr; } } if (style == 1) { if (!fix->peratom_flag) return NULL; if (type == 1) return (void *) fix->vector_atom; if (type == 2) return (void *) fix->array_atom; } if (style == 2) { if (!fix->local_flag) return NULL; if (type == 1) return (void *) fix->vector_local; if (type == 2) return (void *) fix->array_local; } return NULL; } /* ---------------------------------------------------------------------- extract a pointer to an internal LAMMPS evaluated variable name = variable name, must be equal-style or atom-style variable group = group ID for evaluating an atom-style variable, else NULL for equal-style variable, returns a pointer to a memory location which is allocated by this function which the caller can cast to a (double *) which points to the value for atom-style variable, returns a pointer to the vector of per-atom values on each processor, which the caller can cast to the proper data type returns a NULL if name is not recognized or not equal-style or atom-style IMPORTANT: for both equal-style and atom-style variables, this function allocates memory to store the variable data in so the caller must free this memory to avoid a leak e.g. for equal-style variables double *dptr = (double *) lammps_extract_variable(); double value = *dptr; free(dptr); e.g. for atom-style variables double *vector = (double *) lammps_extract_variable(); use the vector values free(vector); IMPORTANT: LAMMPS cannot easily check when it is valid to evaluate the variable or any fixes or computes or thermodynamic info it references, so caller must insure that it is OK ------------------------------------------------------------------------- */ void *lammps_extract_variable(void *ptr, char *name, char *group) { LAMMPS *lmp = (LAMMPS *) ptr; int ivar = lmp->input->variable->find(name); if (ivar < 0) return NULL; if (lmp->input->variable->equalstyle(ivar)) { double *dptr = (double *) malloc(sizeof(double)); *dptr = lmp->input->variable->compute_equal(ivar); return (void *) dptr; } if (lmp->input->variable->atomstyle(ivar)) { int igroup = lmp->group->find(group); if (igroup < 0) return NULL; int nlocal = lmp->atom->nlocal; double *vector = (double *) malloc(nlocal*sizeof(double)); lmp->input->variable->compute_atom(ivar,igroup,vector,1,0); return (void *) vector; } return NULL; } /* ---------------------------------------------------------------------- */ int lammps_get_natoms(void *ptr) { LAMMPS *lmp = (LAMMPS *) ptr; - if (lmp->atom->natoms > MAXINT32) return 0; + if (lmp->atom->natoms > MAXSMALLINT) return 0; int natoms = static_cast<int> (lmp->atom->natoms); return natoms; } /* ---------------------------------------------------------------------- */ void lammps_get_coords(void *ptr, double *coords) { LAMMPS *lmp = (LAMMPS *) ptr; // error if tags are not defined or not consecutive if (lmp->atom->tag_enable == 0 || lmp->atom->tag_consecutive() == 0) return; - if (lmp->atom->natoms > MAXINT32) return; + if (lmp->atom->natoms > MAXSMALLINT) return; int natoms = static_cast<int> (lmp->atom->natoms); double *copy = new double[3*natoms]; for (int i = 0; i < 3*natoms; i++) copy[i] = 0.0; double **x = lmp->atom->x; int *tag = lmp->atom->tag; int nlocal = lmp->atom->nlocal; int id,offset; for (int i = 0; i < nlocal; i++) { id = tag[i]; offset = 3*(id-1); copy[offset+0] = x[i][0]; copy[offset+1] = x[i][1]; copy[offset+2] = x[i][2]; } MPI_Allreduce(copy,coords,3*natoms,MPI_DOUBLE,MPI_SUM,lmp->world); delete [] copy; } /* ---------------------------------------------------------------------- */ void lammps_put_coords(void *ptr, double *coords) { LAMMPS *lmp = (LAMMPS *) ptr; // error if no map defined by LAMMPS if (lmp->atom->map_style == 0) return; - if (lmp->atom->natoms > MAXINT32) return; + if (lmp->atom->natoms > MAXSMALLINT) return; int natoms = static_cast<int> (lmp->atom->natoms); double **x = lmp->atom->x; int m,offset; for (int i = 0; i < natoms; i++) { if ((m = lmp->atom->map(i+1)) >= 0) { offset = 3*i; x[m][0] = coords[offset+0]; x[m][1] = coords[offset+1]; x[m][2] = coords[offset+2]; } } } diff --git a/src/lmptype.h b/src/lmptype.h index 1ab30c82c..84c135e24 100644 --- a/src/lmptype.h +++ b/src/lmptype.h @@ -1,26 +1,118 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ +// define integer data types used by LAMMPS and associated size limits + +// smallint = variables for system on 1 processor (nlocal, etc) +// tagint = variables for atom IDs (tag) +// bigint = variables for total system (natoms, ntimestep, etc) + +// smallint must be an int, as defined by C compiler +// tagint can be 32-bit or 64-bit int, must be >= smallint +// NOTE: 64-bit tagint is not yet supported +// bigint can be 32-bit or 64-bit int, must be >= tagint + +// MAXSMALLINT = max value of a smallint +// MAXTAGINT = max value of a tagint +// MAXBIGINT = max value of a bigint + +// MPI_LMP_TAGINT = MPI data type corresponding to tagint +// MPI_LMP_BIGINT = MPI data type corresponding to bigint + +// NOTE: if your machine/MPI does not support "long long" ints, +// but only "long" ints, then you will likely need to set +// MPI_LMP_BIGINT to MPI_LONG, LLONG_MAX to LONG_MAX, +// "lld" to "ld", and ATOBIGINT to atol + #ifndef LMP_LMPTYPE_H #define LMP_LMPTYPE_H +#include "limits.h" #include "stdint.h" namespace LAMMPS_NS { -typedef uint64_t bigint; -#define MAXINT32 0x7FFFFFFF +// default settings +// 32-bit smallint and tagint, 64-bit bigint + +typedef int smallint; +typedef int tagint; +typedef int64_t bigint; + +#define MAXSMALLINT INT_MAX +#define MAXTAGINT INT_MAX +#define MAXBIGINT LLONG_MAX + +#define MPI_LMP_TAGINT MPI_INT +#define MPI_LMP_BIGINT MPI_LONG_LONG + +#define TAGINT_FORMAT "%d" +#define BIGINT_FORMAT "%lld" +#define TAGINT_FORMAT_NL "%d\n" +#define BIGINT_FORMAT_NL "%lld\n" + +#define ATOTAGINT atoi +#define ATOBIGINT atoll + +// for molecular problems that exceed 2 billion (2^31) atoms +// 32-bit smallint, 64-bit tagint and bigint +// NOTE: 64-bit tagint is not yet supported + +/* +typedef int smallint; +typedef int64_t tagint; +typedef int64_t bigint; + +#define MAXSMALLINT INT_MAX +#define MAXTAGINT LLONG_MAX +#define MAXBIGINT LLONG_MAX + +#define MPI_LMP_TAGINT MPI_LONG_LONG +#define MPI_LMP_BIGINT MPI_LONG_LONG + +#define TAGINT_FORMAT "%lld" +#define BIGINT_FORMAT "%lld" +#define TAGINT_FORMAT_NL "%lld\n" +#define BIGINT_FORMAT_NL "%lld\n" + +#define ATOTAGINT atoll +#define ATOBIGINT atoll +*/ + +// for machines that do not support 64-bit ints +// 32-bit smallint and tagint and bigint + +/* +typedef int smallint; +typedef int tagint; +typedef int bigint; + +#define MAXSMALLINT INT_MAX +#define MAXTAGINT INT_MAX +#define MAXBIGINT INT_MAX + +#define MPI_LMP_TAGINT MPI_INT +#define MPI_LMP_BIGINT MPI_INT + +#define TAGINT_FORMAT "%d" +#define BIGINT_FORMAT "%d" +#define TAGINT_FORMAT_NL "%d\n" +#define BIGINT_FORMAT_NL "%d\n" + +#define ATOTAGINT atoi +#define ATOBIGINT atoi +*/ } #endif diff --git a/src/min.cpp b/src/min.cpp index 8f58ceae5..255bdfb60 100644 --- a/src/min.cpp +++ b/src/min.cpp @@ -1,764 +1,765 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- Contributing author: Aidan Thompson (SNL) improved CG and backtrack ls, added quadratic ls Sources: Numerical Recipes frprmn routine "Conjugate Gradient Method Without the Agonizing Pain" by JR Shewchuk, http://www-2.cs.cmu.edu/~jrs/jrspapers.html#cg ------------------------------------------------------------------------- */ #include "math.h" #include "stdlib.h" #include "string.h" #include "min.h" +#include "lmptype.h" #include "atom.h" #include "domain.h" #include "comm.h" #include "update.h" #include "modify.h" #include "fix_minimize.h" #include "compute.h" #include "neighbor.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 "thermo.h" #include "timer.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; #define MIN(A,B) ((A) < (B)) ? (A) : (B) #define MAX(A,B) ((A) > (B)) ? (A) : (B) /* ---------------------------------------------------------------------- */ Min::Min(LAMMPS *lmp) : Pointers(lmp) { dmax = 0.1; searchflag = 0; linestyle = 0; elist_global = elist_atom = NULL; vlist_global = vlist_atom = NULL; nextra_global = 0; fextra = NULL; nextra_atom = 0; xextra_atom = fextra_atom = NULL; extra_peratom = extra_nlen = NULL; extra_max = NULL; requestor = NULL; } /* ---------------------------------------------------------------------- */ Min::~Min() { delete [] elist_global; delete [] elist_atom; delete [] vlist_global; delete [] vlist_atom; delete [] fextra; memory->sfree(xextra_atom); memory->sfree(fextra_atom); memory->sfree(extra_peratom); memory->sfree(extra_nlen); memory->sfree(extra_max); memory->sfree(requestor); } /* ---------------------------------------------------------------------- */ void Min::init() { // create fix needed for storing atom-based quantities // will delete it at end of run char **fixarg = new char*[3]; fixarg[0] = (char *) "MINIMIZE"; fixarg[1] = (char *) "all"; fixarg[2] = (char *) "MINIMIZE"; modify->add_fix(3,fixarg); delete [] fixarg; fix_minimize = (FixMinimize *) modify->fix[modify->nfix-1]; // clear out extra global and per-atom dof // will receive requests for new per-atom dof during pair init() // can then add vectors to fix_minimize in setup() nextra_global = 0; delete [] fextra; fextra = NULL; nextra_atom = 0; memory->sfree(xextra_atom); memory->sfree(fextra_atom); memory->sfree(extra_peratom); memory->sfree(extra_nlen); memory->sfree(extra_max); memory->sfree(requestor); xextra_atom = fextra_atom = NULL; extra_peratom = extra_nlen = NULL; extra_max = NULL; requestor = NULL; // virial_style: // 1 if computed explicitly by pair->compute via sum over pair interactions // 2 if computed implicitly by pair->virial_compute via sum over ghost atoms 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(); // set flags for what arrays to clear in force_clear() // need to clear torques,erforce if arrays exists torqueflag = 0; if (atom->torque_flag) torqueflag = 1; erforceflag = 0; if (atom->erforce_flag) erforceflag = 1; // orthogonal vs triclinic simulation box triclinic = domain->triclinic; // reset reneighboring criteria if necessary neigh_every = neighbor->every; neigh_delay = neighbor->delay; neigh_dist_check = neighbor->dist_check; if (neigh_every != 1 || neigh_delay != 0 || neigh_dist_check != 1) { if (comm->me == 0) error->warning("Resetting reneighboring criteria during minimization"); } neighbor->every = 1; neighbor->delay = 0; neighbor->dist_check = 1; niter = neval = 0; // style-specific initialization init_style(); } /* ---------------------------------------------------------------------- setup before run ------------------------------------------------------------------------- */ void Min::setup() { if (comm->me == 0 && screen) fprintf(screen,"Setting up minimization ...\n"); // setup extra global dof due to fixes // cannot be done in init() b/c update init() is before modify init() nextra_global = modify->min_dof(); if (nextra_global) fextra = new double[nextra_global]; // compute for potential energy int id = modify->find_compute("thermo_pe"); if (id < 0) error->all("Minimization could not find thermo_pe compute"); pe_compute = modify->compute[id]; // style-specific setup does two tasks // setup extra global dof vectors // setup extra per-atom dof vectors due to requests from Pair classes // cannot be done in init() b/c update init() is before modify/pair init() setup_style(); // ndoftotal = total dof for entire minimization problem // dof for atoms, extra per-atom, extra global bigint ndofme = 3*atom->nlocal; for (int m = 0; m < nextra_atom; m++) ndofme += extra_peratom[m]*atom->nlocal; - MPI_Allreduce(&ndofme,&ndoftotal,1,MPI_UNSIGNED_LONG_LONG,MPI_SUM,world); + MPI_Allreduce(&ndofme,&ndoftotal,1,MPI_LMP_BIGINT,MPI_SUM,world); ndoftotal += nextra_global; // setup domain, communication and neighboring // acquire ghosts // build neighbor lists atom->setup(); 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); neighbor->build(); neighbor->ncalls = 0; // remove these restriction eventually if (nextra_global && searchflag == 0) error->all("Cannot use a damped dynamics min style with fix box/relax"); if (nextra_atom && searchflag == 0) error->all("Cannot use a damped dynamics min style with per-atom DOF"); // atoms may have migrated in comm->exchange() reset_vectors(); // compute all forces ev_set(update->ntimestep); force_clear(); modify->setup_pre_force(vflag); if (force->pair) force->pair->compute(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(); force->kspace->compute(eflag,vflag); } if (force->newton) comm->reverse_comm(); // update per-atom minimization variables stored by pair styles if (nextra_atom) for (int m = 0; m < nextra_atom; m++) requestor[m]->min_xf_get(m); modify->setup(vflag); output->setup(1); // stats for Finish to print ecurrent = pe_compute->compute_scalar(); if (nextra_global) ecurrent += modify->min_energy(fextra); if (output->thermo->normflag) ecurrent /= atom->natoms; einitial = ecurrent; fnorm2_init = sqrt(fnorm_sqr()); fnorminf_init = fnorm_inf(); } /* ---------------------------------------------------------------------- setup without output or one-time post-init setup flag = 0 = just force calculation flag = 1 = reneighbor and force calculation ------------------------------------------------------------------------- */ void Min::setup_minimal(int flag) { // setup domain, communication and neighboring // acquire ghosts // build neighbor lists if (flag) { 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); neighbor->build(); neighbor->ncalls = 0; } // atoms may have migrated in comm->exchange() reset_vectors(); // compute all forces ev_set(update->ntimestep); force_clear(); modify->setup_pre_force(vflag); if (force->pair) force->pair->compute(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(); force->kspace->compute(eflag,vflag); } if (force->newton) comm->reverse_comm(); // update per-atom minimization variables stored by pair styles if (nextra_atom) for (int m = 0; m < nextra_atom; m++) requestor[m]->min_xf_get(m); modify->setup(vflag); // stats for Finish to print ecurrent = pe_compute->compute_scalar(); if (nextra_global) ecurrent += modify->min_energy(fextra); if (output->thermo->normflag) ecurrent /= atom->natoms; einitial = ecurrent; fnorm2_init = sqrt(fnorm_sqr()); fnorminf_init = fnorm_inf(); } /* ---------------------------------------------------------------------- perform minimization, calling iterate() for N steps ------------------------------------------------------------------------- */ void Min::run(int n) { // minimizer iterations int iter_start = niter; stop_condition = iterate(n); stopstr = stopstrings(stop_condition); // if early exit from iterate loop: // set update->nsteps to niter for Finish stats to print // set output->next values to this timestep // call energy_force() to insure vflag is set when forces computed // output->write does final output for thermo, dump, restart files // add ntimestep to all computes that store invocation times // since are hardwiring call to thermo/dumps and computes may not be ready if (stop_condition) { update->nsteps = niter; if (update->restrict_output == 0) { for (int idump = 0; idump < output->ndump; idump++) output->next_dump[idump] = update->ntimestep; output->next_dump_any = update->ntimestep; if (output->restart_every) output->next_restart = update->ntimestep; } output->next_thermo = update->ntimestep; modify->addstep_compute_all(update->ntimestep); ecurrent = energy_force(0); output->write(update->ntimestep); } } /* ---------------------------------------------------------------------- */ void Min::cleanup() { // stats for Finish to print efinal = ecurrent; fnorm2_final = sqrt(fnorm_sqr()); fnorminf_final = fnorm_inf(); // reset reneighboring criteria neighbor->every = neigh_every; neighbor->delay = neigh_delay; neighbor->dist_check = neigh_dist_check; // delete fix at end of run, so its atom arrays won't persist modify->delete_fix("MINIMIZE"); } /* ---------------------------------------------------------------------- evaluate potential energy and forces may migrate atoms due to reneighboring return new energy, which should include nextra_global dof return negative gradient stored in atom->f return negative gradient for nextra_global dof in fextra ------------------------------------------------------------------------- */ double Min::energy_force(int resetflag) { // check for reneighboring // always communicate since minimizer moved atoms int nflag = neighbor->decide(); if (nflag == 0) { timer->stamp(); comm->forward_comm(); timer->stamp(TIME_COMM); } else { if (modify->n_min_pre_exchange) modify->min_pre_exchange(); if (triclinic) domain->x2lamda(atom->nlocal); domain->pbc(); if (domain->box_change) { domain->reset_box(); comm->setup(); if (neighbor->style) neighbor->setup_bins(); } timer->stamp(); comm->exchange(); if (atom->sortfreq > 0 && update->ntimestep >= atom->nextsort) atom->sort(); comm->borders(); if (triclinic) domain->lamda2x(atom->nlocal+atom->nghost); timer->stamp(TIME_COMM); neighbor->build(); timer->stamp(TIME_NEIGHBOR); } ev_set(update->ntimestep); force_clear(); if (modify->n_min_pre_force) modify->min_pre_force(vflag); timer->stamp(); if (force->pair) { force->pair->compute(eflag,vflag); timer->stamp(TIME_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(TIME_BOND); } if (force->kspace) { force->kspace->compute(eflag,vflag); timer->stamp(TIME_KSPACE); } if (force->newton) { comm->reverse_comm(); timer->stamp(TIME_COMM); } // update per-atom minimization variables stored by pair styles if (nextra_atom) for (int m = 0; m < nextra_atom; m++) requestor[m]->min_xf_get(m); // fixes that affect minimization if (modify->n_min_post_force) modify->min_post_force(vflag); // compute potential energy of system // normalize if thermo PE does double energy = pe_compute->compute_scalar(); if (nextra_global) energy += modify->min_energy(fextra); if (output->thermo->normflag) energy /= atom->natoms; // if reneighbored, atoms migrated // if resetflag = 1, update x0 of atoms crossing PBC // reset vectors used by lo-level minimizer if (nflag) { if (resetflag) fix_minimize->reset_coords(); reset_vectors(); } return energy; } /* ---------------------------------------------------------------------- clear force on own & ghost atoms setup and clear other arrays as needed ------------------------------------------------------------------------- */ void Min::force_clear() { int i; // clear global force array // nall includes ghosts only if either newton flag is set int nall; if (force->newton) nall = atom->nlocal + atom->nghost; else nall = atom->nlocal; 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; } } /* ---------------------------------------------------------------------- pair style makes request to add a per-atom variables to minimization requestor stores callback to pair class to invoke during min to get current variable and forces on it and to update the variable return flag that pair can use if it registers multiple variables ------------------------------------------------------------------------- */ int Min::request(Pair *pair, int peratom, double maxvalue) { int n = nextra_atom + 1; xextra_atom = (double **) memory->srealloc(xextra_atom,n*sizeof(double *), "min:xextra_atom"); fextra_atom = (double **) memory->srealloc(fextra_atom,n*sizeof(double *), "min:fextra_atom"); extra_peratom = (int *) memory->srealloc(extra_peratom,n*sizeof(int), "min:extra_peratom"); extra_nlen = (int *) memory->srealloc(extra_nlen,n*sizeof(int), "min:extra_nlen"); extra_max = (double *) memory->srealloc(extra_max,n*sizeof(double), "min:extra_max"); requestor = (Pair **) memory->srealloc(requestor,n*sizeof(Pair *), "min:requestor"); requestor[nextra_atom] = pair; extra_peratom[nextra_atom] = peratom; extra_max[nextra_atom] = maxvalue; nextra_atom++; return nextra_atom-1; } /* ---------------------------------------------------------------------- */ void Min::modify_params(int narg, char **arg) { if (narg == 0) error->all("Illegal min_modify command"); int iarg = 0; while (iarg < narg) { if (strcmp(arg[iarg],"dmax") == 0) { if (iarg+2 > narg) error->all("Illegal min_modify command"); dmax = atof(arg[iarg+1]); iarg += 2; } else if (strcmp(arg[iarg],"line") == 0) { if (iarg+2 > narg) error->all("Illegal min_modify command"); if (strcmp(arg[iarg+1],"backtrack") == 0) linestyle = 0; else if (strcmp(arg[iarg+1],"quadratic") == 0) linestyle = 1; else error->all("Illegal min_modify command"); iarg += 2; } else error->all("Illegal min_modify command"); } } /* ---------------------------------------------------------------------- setup lists of computes for global and per-atom PE and pressure ------------------------------------------------------------------------- */ void Min::ev_setup() { delete [] elist_global; delete [] elist_atom; delete [] vlist_global; delete [] vlist_atom; elist_global = elist_atom = NULL; vlist_global = vlist_atom = NULL; nelist_global = nelist_atom = 0; nvlist_global = nvlist_atom = 0; for (int i = 0; i < modify->ncompute; i++) { if (modify->compute[i]->peflag) nelist_global++; if (modify->compute[i]->peatomflag) nelist_atom++; if (modify->compute[i]->pressflag) nvlist_global++; if (modify->compute[i]->pressatomflag) nvlist_atom++; } if (nelist_global) elist_global = new Compute*[nelist_global]; if (nelist_atom) elist_atom = new Compute*[nelist_atom]; if (nvlist_global) vlist_global = new Compute*[nvlist_global]; if (nvlist_atom) vlist_atom = new Compute*[nvlist_atom]; nelist_global = nelist_atom = 0; nvlist_global = nvlist_atom = 0; for (int i = 0; i < modify->ncompute; i++) { if (modify->compute[i]->peflag) elist_global[nelist_global++] = modify->compute[i]; if (modify->compute[i]->peatomflag) elist_atom[nelist_atom++] = modify->compute[i]; if (modify->compute[i]->pressflag) vlist_global[nvlist_global++] = modify->compute[i]; if (modify->compute[i]->pressatomflag) vlist_atom[nvlist_atom++] = modify->compute[i]; } } /* ---------------------------------------------------------------------- set eflag,vflag for current iteration invoke matchstep() on all timestep-dependent computes to clear their arrays eflag/vflag based on computes that need info on this ntimestep always set eflag_global = 1, since need energy every iteration eflag = 0 = no energy computation eflag = 1 = global energy only eflag = 2 = per-atom energy only eflag = 3 = both global and per-atom energy vflag = 0 = no virial computation (pressure) vflag = 1 = global virial with pair portion via sum of pairwise interactions vflag = 2 = global virial with pair portion via F dot r including ghosts vflag = 4 = per-atom virial only vflag = 5 or 6 = both global and per-atom virial ------------------------------------------------------------------------- */ -void Min::ev_set(int ntimestep) +void Min::ev_set(bigint ntimestep) { int i,flag; int eflag_global = 1; for (i = 0; i < nelist_global; i++) elist_global[i]->matchstep(ntimestep); flag = 0; int eflag_atom = 0; for (i = 0; i < nelist_atom; i++) if (elist_atom[i]->matchstep(ntimestep)) flag = 1; if (flag) eflag_atom = 2; if (eflag_global) update->eflag_global = update->ntimestep; if (eflag_atom) update->eflag_atom = update->ntimestep; eflag = eflag_global + eflag_atom; flag = 0; int vflag_global = 0; for (i = 0; i < nvlist_global; i++) if (vlist_global[i]->matchstep(ntimestep)) flag = 1; if (flag) vflag_global = virial_style; flag = 0; int vflag_atom = 0; for (i = 0; i < nvlist_atom; i++) if (vlist_atom[i]->matchstep(ntimestep)) flag = 1; if (flag) vflag_atom = 4; if (vflag_global) update->vflag_global = update->ntimestep; if (vflag_atom) update->vflag_atom = update->ntimestep; vflag = vflag_global + vflag_atom; } /* ---------------------------------------------------------------------- compute and return ||force||_2^2 ------------------------------------------------------------------------- */ double Min::fnorm_sqr() { int i,n; double *fatom; double local_norm2_sqr = 0.0; for (i = 0; i < nvec; i++) local_norm2_sqr += fvec[i]*fvec[i]; if (nextra_atom) { for (int m = 0; m < nextra_atom; m++) { fatom = fextra_atom[m]; n = extra_nlen[m]; for (i = 0; i < n; i++) local_norm2_sqr += fatom[i]*fatom[i]; } } double norm2_sqr = 0.0; MPI_Allreduce(&local_norm2_sqr,&norm2_sqr,1,MPI_DOUBLE,MPI_SUM,world); if (nextra_global) for (i = 0; i < nextra_global; i++) norm2_sqr += fextra[i]*fextra[i]; return norm2_sqr; } /* ---------------------------------------------------------------------- compute and return ||force||_inf ------------------------------------------------------------------------- */ double Min::fnorm_inf() { int i,n; double *fatom; double local_norm_inf = 0.0; for (i = 0; i < nvec; i++) local_norm_inf = MAX(fabs(fvec[i]),local_norm_inf); if (nextra_atom) { for (int m = 0; m < nextra_atom; m++) { fatom = fextra_atom[m]; n = extra_nlen[m]; for (i = 0; i < n; i++) local_norm_inf = MAX(fabs(fatom[i]),local_norm_inf); } } double norm_inf = 0.0; MPI_Allreduce(&local_norm_inf,&norm_inf,1,MPI_DOUBLE,MPI_MAX,world); if (nextra_global) for (i = 0; i < nextra_global; i++) norm_inf = MAX(fabs(fextra[i]),norm_inf); return norm_inf; } /* ---------------------------------------------------------------------- possible stop conditions ------------------------------------------------------------------------- */ char *Min::stopstrings(int n) { char *strings[] = {"max iterations", "max force evaluations", "energy tolerance", "force tolerance", "search direction is not downhill", "linesearch alpha is zero", "forces are zero", "quadratic factors are zero", "trust region too small", "HFTN minimizer error"}; return strings[n]; } diff --git a/src/min.h b/src/min.h index f4626514e..7b0990333 100644 --- a/src/min.h +++ b/src/min.h @@ -1,108 +1,108 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain 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_MIN_H #define LMP_MIN_H #include "pointers.h" #include "lmptype.h" namespace LAMMPS_NS { class Min : protected Pointers { public: double einitial,efinal,eprevious; double fnorm2_init,fnorminf_init,fnorm2_final,fnorminf_final; double alpha_final; int niter,neval; int stop_condition; char *stopstr; int searchflag; // 0 if damped dynamics, 1 if sub-cycles on local search Min(class LAMMPS *); virtual ~Min(); void init(); void setup(); void setup_minimal(int); void run(int); void cleanup(); int request(class Pair *, int, double); double memory_usage() {return 0.0;} void modify_params(int, char **); double fnorm_sqr(); double fnorm_inf(); virtual void init_style() {} virtual void setup_style() = 0; virtual void reset_vectors() = 0; virtual int iterate(int) = 0; protected: int eflag,vflag; // flags for energy/virial computation int virial_style; // compute virial explicitly or implicitly double dmax; // max dist to move any atom in one step int linestyle; // 0 = backtrack, 1 = quadratic int nelist_global,nelist_atom; // # of PE,virial computes to check int nvlist_global,nvlist_atom; class Compute **elist_global; // lists of PE,virial Computes class Compute **elist_atom; class Compute **vlist_global; class Compute **vlist_atom; int pairflag; int torqueflag,erforceflag; int triclinic; // 0 if domain is orthog, 1 if triclinic int narray; // # of arrays stored by fix_minimize class FixMinimize *fix_minimize; // fix that stores auxiliary data class Compute *pe_compute; // compute for potential energy double ecurrent; // current potential energy bigint ndoftotal; // total dof for entire problem int nvec; // local atomic dof = length of xvec double *xvec; // variables for atomic dof, as 1d vector double *fvec; // force vector for atomic dof, as 1d vector int nextra_global; // # of extra global dof due to fixes double *fextra; // force vector for extra global dof // xextra is stored by fix int nextra_atom; // # of extra per-atom variables double **xextra_atom; // ptr to the variable double **fextra_atom; // ptr to the force on the variable int *extra_peratom; // # of values in variable, e.g. 3 in x int *extra_nlen; // total local length of variable, e.g 3*nlocal double *extra_max; // max allowed change per iter for atom's var class Pair **requestor; // Pair that stores/manipulates the variable int neigh_every,neigh_delay,neigh_dist_check; // neighboring params double energy_force(int); void force_clear(); double compute_force_norm_sqr(); double compute_force_norm_inf(); void ev_setup(); - void ev_set(int); + void ev_set(bigint); char *stopstrings(int); }; } #endif diff --git a/src/min_cg.cpp b/src/min_cg.cpp index 63ed35fdd..9ad87904f 100644 --- a/src/min_cg.cpp +++ b/src/min_cg.cpp @@ -1,187 +1,187 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ #include "mpi.h" #include "math.h" #include "string.h" #include "min_cg.h" #include "lmptype.h" #include "atom.h" #include "update.h" #include "output.h" #include "timer.h" using namespace LAMMPS_NS; // EPS_ENERGY = minimum normalization for energy tolerance #define EPS_ENERGY 1.0e-8 // same as in other min classes enum{MAXITER,MAXEVAL,ETOL,FTOL,DOWNHILL,ZEROALPHA,ZEROFORCE,ZEROQUAD}; #define MIN(A,B) ((A) < (B)) ? (A) : (B) #define MAX(A,B) ((A) > (B)) ? (A) : (B) /* ---------------------------------------------------------------------- */ MinCG::MinCG(LAMMPS *lmp) : MinLineSearch(lmp) {} /* ---------------------------------------------------------------------- minimization via conjugate gradient iterations ------------------------------------------------------------------------- */ int MinCG::iterate(int maxiter) { int i,m,n,fail,ntimestep; double beta,gg,dot[2],dotall[2]; double *fatom,*gatom,*hatom; // nlimit = max # of CG iterations before restarting // set to ndoftotal unless too big - int nlimit = static_cast<int> (MIN(MAXINT32,ndoftotal)); + int nlimit = static_cast<int> (MIN(MAXSMALLINT,ndoftotal)); // initialize working vectors for (i = 0; i < nvec; i++) h[i] = g[i] = fvec[i]; if (nextra_atom) for (m = 0; m < nextra_atom; m++) { fatom = fextra_atom[m]; gatom = gextra_atom[m]; hatom = hextra_atom[m]; n = extra_nlen[m]; for (i = 0; i < n; i++) hatom[i] = gatom[i] = fatom[i]; } if (nextra_global) for (i = 0; i < nextra_global; i++) hextra[i] = gextra[i] = fextra[i]; gg = fnorm_sqr(); for (int iter = 0; iter < maxiter; iter++) { ntimestep = ++update->ntimestep; niter++; // line minimization along direction h from current atom->x eprevious = ecurrent; fail = (this->*linemin)(ecurrent,alpha_final); if (fail) return fail; // function evaluation criterion if (neval >= update->max_eval) return MAXEVAL; // energy tolerance criterion if (fabs(ecurrent-eprevious) < update->etol * 0.5*(fabs(ecurrent) + fabs(eprevious) + EPS_ENERGY)) return ETOL; // force tolerance criterion dot[0] = dot[1] = 0.0; for (i = 0; i < nvec; i++) { dot[0] += fvec[i]*fvec[i]; dot[1] += fvec[i]*g[i]; } if (nextra_atom) for (m = 0; m < nextra_atom; m++) { fatom = fextra_atom[m]; gatom = gextra_atom[m]; n = extra_nlen[m]; for (i = 0; i < n; i++) { dot[0] += fatom[i]*fatom[i]; dot[1] += fatom[i]*gatom[i]; } } MPI_Allreduce(dot,dotall,2,MPI_DOUBLE,MPI_SUM,world); if (nextra_global) for (i = 0; i < nextra_global; i++) { dotall[0] += fextra[i]*fextra[i]; dotall[1] += fextra[i]*gextra[i]; } if (dotall[0] < update->ftol*update->ftol) return FTOL; // update new search direction h from new f = -Grad(x) and old g // this is Polak-Ribieri formulation // beta = dotall[0]/gg would be Fletcher-Reeves // reinitialize CG every ndof iterations by setting beta = 0.0 beta = MAX(0.0,(dotall[0] - dotall[1])/gg); if ((niter+1) % nlimit == 0) beta = 0.0; gg = dotall[0]; for (i = 0; i < nvec; i++) { g[i] = fvec[i]; h[i] = g[i] + beta*h[i]; } if (nextra_atom) for (m = 0; m < nextra_atom; m++) { fatom = fextra_atom[m]; gatom = gextra_atom[m]; hatom = hextra_atom[m]; n = extra_nlen[m]; for (i = 0; i < n; i++) { gatom[i] = fatom[i]; hatom[i] = gatom[i] + beta*hatom[i]; } } if (nextra_global) for (i = 0; i < nextra_global; i++) { gextra[i] = fextra[i]; hextra[i] = gextra[i] + beta*hextra[i]; } // reinitialize CG if new search direction h is not downhill dot[0] = 0.0; for (i = 0; i < nvec; i++) dot[0] += g[i]*h[i]; if (nextra_atom) for (m = 0; m < nextra_atom; m++) { gatom = gextra_atom[m]; hatom = hextra_atom[m]; n = extra_nlen[m]; for (i = 0; i < n; i++) dot[0] += gatom[i]*hatom[i]; } MPI_Allreduce(dot,dotall,1,MPI_DOUBLE,MPI_SUM,world); if (nextra_global) for (i = 0; i < nextra_global; i++) dotall[0] += gextra[i]*hextra[i]; if (dotall[0] <= 0.0) { for (i = 0; i < nvec; i++) h[i] = g[i]; if (nextra_atom) for (m = 0; m < nextra_atom; m++) { gatom = gextra_atom[m]; hatom = hextra_atom[m]; n = extra_nlen[m]; for (i = 0; i < n; i++) hatom[i] = gatom[i]; } if (nextra_global) for (i = 0; i < nextra_global; i++) hextra[i] = gextra[i]; } // output for thermo, dump, restart files if (output->next == ntimestep) { timer->stamp(); output->write(ntimestep); timer->stamp(TIME_OUTPUT); } } return MAXITER; } diff --git a/src/min_fire.cpp b/src/min_fire.cpp index 135e51742..0c4e73dc2 100644 --- a/src/min_fire.cpp +++ b/src/min_fire.cpp @@ -1,272 +1,273 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain 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 "min_fire.h" #include "universe.h" #include "atom.h" #include "force.h" #include "update.h" #include "output.h" #include "timer.h" #include "error.h" using namespace LAMMPS_NS; // EPS_ENERGY = minimum normalization for energy tolerance #define EPS_ENERGY 1.0e-8 // same as in other min classes enum{MAXITER,MAXEVAL,ETOL,FTOL,DOWNHILL,ZEROALPHA,ZEROFORCE,ZEROQUAD}; #define MIN(A,B) ((A) < (B)) ? (A) : (B) #define MAX(A,B) ((A) > (B)) ? (A) : (B) #define DELAYSTEP 5 #define DT_GROW 1.1 #define DT_SHRINK 0.5 #define ALPHA0 0.1 #define ALPHA_SHRINK 0.99 #define TMAX 10.0 /* ---------------------------------------------------------------------- */ MinFire::MinFire(LAMMPS *lmp) : Min(lmp) {} /* ---------------------------------------------------------------------- */ void MinFire::init_style() { dt = update->dt; } /* ---------------------------------------------------------------------- */ void MinFire::setup_style() { double **v = atom->v; int nlocal = atom->nlocal; for (int i = 0; i < nlocal; i++) v[i][0] = v[i][1] = v[i][2] = 0.0; } /* ---------------------------------------------------------------------- set current vector lengths and pointers called after atoms have migrated ------------------------------------------------------------------------- */ void MinFire::reset_vectors() { // atomic dof nvec = 3 * atom->nlocal; if (nvec) xvec = atom->x[0]; if (nvec) fvec = atom->f[0]; } /* ---------------------------------------------------------------------- */ int MinFire::iterate(int maxiter) { - int ntimestep,flag,flagall; + bigint ntimestep; double vmax,vdotf,vdotfall,vdotv,vdotvall,fdotf,fdotfall; double scale1,scale2; double dtvone,dtv,dtfm; + int flag,flagall; alpha_final = 0.0; double alpha = ALPHA0; double dtmax = TMAX * dt; - int last_negative = update->ntimestep; + bigint last_negative = update->ntimestep; for (int iter = 0; iter < maxiter; iter++) { ntimestep = ++update->ntimestep; niter++; // vdotfall = v dot f double **v = atom->v; double **f = atom->f; int nlocal = atom->nlocal; vdotf = 0.0; for (int i = 0; i < nlocal; i++) vdotf += v[i][0]*f[i][0] + v[i][1]*f[i][1] + v[i][2]*f[i][2]; MPI_Allreduce(&vdotf,&vdotfall,1,MPI_DOUBLE,MPI_SUM,world); // sum vdotf over replicas, if necessary // this communicator would be invalid for multiprocess replicas if (update->multireplica == 1) { vdotf = vdotfall; MPI_Allreduce(&vdotf,&vdotfall,1,MPI_DOUBLE,MPI_SUM,universe->uworld); } // if (v dot f) > 0: // v = (1-alpha) v + alpha |v| Fhat // |v| = length of v, Fhat = unit f // if more than DELAYSTEP since v dot f was negative: // increase timestep and decrease alpha if (vdotfall > 0.0) { vdotv = 0.0; for (int i = 0; i < nlocal; i++) vdotv += v[i][0]*v[i][0] + v[i][1]*v[i][1] + v[i][2]*v[i][2]; MPI_Allreduce(&vdotv,&vdotvall,1,MPI_DOUBLE,MPI_SUM,world); // sum vdotv over replicas, if necessary // this communicator would be invalid for multiprocess replicas if (update->multireplica == 1) { vdotv = vdotvall; MPI_Allreduce(&vdotv,&vdotvall,1,MPI_DOUBLE,MPI_SUM,universe->uworld); } fdotf = 0.0; for (int i = 0; i < nlocal; i++) fdotf += f[i][0]*f[i][0] + f[i][1]*f[i][1] + f[i][2]*f[i][2]; MPI_Allreduce(&fdotf,&fdotfall,1,MPI_DOUBLE,MPI_SUM,world); // sum fdotf over replicas, if necessary // this communicator would be invalid for multiprocess replicas if (update->multireplica == 1) { fdotf = fdotfall; MPI_Allreduce(&fdotf,&fdotfall,1,MPI_DOUBLE,MPI_SUM,universe->uworld); } scale1 = 1.0 - alpha; if (fdotfall == 0.0) scale2 = 0.0; else scale2 = alpha * sqrt(vdotvall/fdotfall); for (int i = 0; i < nlocal; i++) { v[i][0] = scale1*v[i][0] + scale2*f[i][0]; v[i][1] = scale1*v[i][1] + scale2*f[i][1]; v[i][2] = scale1*v[i][2] + scale2*f[i][2]; } if (ntimestep - last_negative > DELAYSTEP) { dt = MIN(dt*DT_GROW,dtmax); alpha *= ALPHA_SHRINK; } // else (v dot f) <= 0: // decrease timestep, reset alpha, set v = 0 } else { last_negative = ntimestep; dt *= DT_SHRINK; alpha = ALPHA0; for (int i = 0; i < nlocal; i++) v[i][0] = v[i][1] = v[i][2] = 0.0; } // limit timestep so no particle moves further than dmax double *rmass = atom->rmass; double *mass = atom->mass; int *type = atom->type; dtvone = dt; for (int i = 0; i < nlocal; i++) { vmax = MAX(fabs(v[i][0]),fabs(v[i][1])); vmax = MAX(vmax,fabs(v[i][2])); if (dtvone*vmax > dmax) dtvone = dmax/vmax; } MPI_Allreduce(&dtvone,&dtv,1,MPI_DOUBLE,MPI_MIN,world); // min dtv over replicas, if necessary // this communicator would be invalid for multiprocess replicas if (update->multireplica == 1) { dtvone = dtv; MPI_Allreduce(&dtvone,&dtv,1,MPI_DOUBLE,MPI_MIN,universe->uworld); } // Euler integration step double **x = atom->x; if (rmass) { for (int i = 0; i < nlocal; i++) { dtfm = dtv / rmass[i]; x[i][0] += dtv * v[i][0]; x[i][1] += dtv * v[i][1]; x[i][2] += dtv * v[i][2]; v[i][0] += dtfm * f[i][0]; v[i][1] += dtfm * f[i][1]; v[i][2] += dtfm * f[i][2]; } } else { for (int i = 0; i < nlocal; i++) { dtfm = dtv / mass[type[i]]; x[i][0] += dtv * v[i][0]; x[i][1] += dtv * v[i][1]; x[i][2] += dtv * v[i][2]; v[i][0] += dtfm * f[i][0]; v[i][1] += dtfm * f[i][1]; v[i][2] += dtfm * f[i][2]; } } eprevious = ecurrent; ecurrent = energy_force(0); neval++; // energy tolerance criterion // only check after DELAYSTEP elapsed since velocties reset to 0 // sync across replicas if running multi-replica minimization if (update->etol > 0.0 && ntimestep-last_negative > DELAYSTEP) { if (update->multireplica == 0) { if (fabs(ecurrent-eprevious) < update->etol * 0.5*(fabs(ecurrent) + fabs(eprevious) + EPS_ENERGY)) return ETOL; } else { if (fabs(ecurrent-eprevious) < update->etol * 0.5*(fabs(ecurrent) + fabs(eprevious) + EPS_ENERGY)) flag = 0; else flag = 1; MPI_Allreduce(&flag,&flagall,1,MPI_INT,MPI_SUM,universe->uworld); if (flagall == 0) return ETOL; } } // force tolerance criterion // sync across replicas if running multi-replica minimization if (update->ftol > 0.0) { fdotf = fnorm_sqr(); if (update->multireplica == 0) { if (fdotf < update->ftol*update->ftol) return FTOL; } else { if (fdotf < update->ftol*update->ftol) flag = 0; else flag = 1; MPI_Allreduce(&flag,&flagall,1,MPI_INT,MPI_SUM,universe->uworld); if (flagall == 0) return FTOL; } } // output for thermo, dump, restart files if (output->next == ntimestep) { timer->stamp(); output->write(ntimestep); timer->stamp(TIME_OUTPUT); } } return MAXITER; } diff --git a/src/min_quickmin.cpp b/src/min_quickmin.cpp index 89a3403d4..6fb15b175 100644 --- a/src/min_quickmin.cpp +++ b/src/min_quickmin.cpp @@ -1,238 +1,240 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ #include "mpi.h" #include "math.h" #include "min_quickmin.h" +#include "lmptype.h" #include "universe.h" #include "atom.h" #include "force.h" #include "update.h" #include "output.h" #include "timer.h" #include "error.h" using namespace LAMMPS_NS; // EPS_ENERGY = minimum normalization for energy tolerance #define EPS_ENERGY 1.0e-8 // same as in other min classes enum{MAXITER,MAXEVAL,ETOL,FTOL,DOWNHILL,ZEROALPHA,ZEROFORCE,ZEROQUAD}; #define MIN(A,B) ((A) < (B)) ? (A) : (B) #define MAX(A,B) ((A) > (B)) ? (A) : (B) #define DELAYSTEP 5 /* ---------------------------------------------------------------------- */ MinQuickMin::MinQuickMin(LAMMPS *lmp) : Min(lmp) {} /* ---------------------------------------------------------------------- */ void MinQuickMin::init_style() { dt = update->dt; } /* ---------------------------------------------------------------------- */ void MinQuickMin::setup_style() { double **v = atom->v; int nlocal = atom->nlocal; for (int i = 0; i < nlocal; i++) v[i][0] = v[i][1] = v[i][2] = 0.0; } /* ---------------------------------------------------------------------- set current vector lengths and pointers called after atoms have migrated ------------------------------------------------------------------------- */ void MinQuickMin::reset_vectors() { // atomic dof nvec = 3 * atom->nlocal; if (nvec) xvec = atom->x[0]; if (nvec) fvec = atom->f[0]; } /* ---------------------------------------------------------------------- minimization via QuickMin damped dynamics /* ---------------------------------------------------------------------- */ int MinQuickMin::iterate(int maxiter) { - int ntimestep,flag,flagall; + bigint ntimestep; double vmax,vdotf,vdotfall,fdotf,fdotfall,scale; double dtvone,dtv,dtfm; + int flag,flagall; alpha_final = 0.0; - int last_negative = update->ntimestep; + bigint last_negative = update->ntimestep; for (int iter = 0; iter < maxiter; iter++) { ntimestep = ++update->ntimestep; niter++; // zero velocity if anti-parallel to force // else project velocity in direction of force double **v = atom->v; double **f = atom->f; int nlocal = atom->nlocal; vdotf = 0.0; for (int i = 0; i < nlocal; i++) vdotf += v[i][0]*f[i][0] + v[i][1]*f[i][1] + v[i][2]*f[i][2]; MPI_Allreduce(&vdotf,&vdotfall,1,MPI_DOUBLE,MPI_SUM,world); // sum vdotf over replicas, if necessary // this communicator would be invalid for multiprocess replicas if (update->multireplica == 1) { vdotf = vdotfall; MPI_Allreduce(&vdotf,&vdotfall,1,MPI_DOUBLE,MPI_SUM,universe->uworld); } if (vdotfall < 0.0) { last_negative = ntimestep; for (int i = 0; i < nlocal; i++) v[i][0] = v[i][1] = v[i][2] = 0.0; } else { fdotf = 0.0; for (int i = 0; i < nlocal; i++) fdotf += f[i][0]*f[i][0] + f[i][1]*f[i][1] + f[i][2]*f[i][2]; MPI_Allreduce(&fdotf,&fdotfall,1,MPI_DOUBLE,MPI_SUM,world); // sum fdotf over replicas, if necessary // this communicator would be invalid for multiprocess replicas if (update->multireplica == 1) { fdotf = fdotfall; MPI_Allreduce(&fdotf,&fdotfall,1,MPI_DOUBLE,MPI_SUM,universe->uworld); } if (fdotfall == 0.0) scale = 0.0; else scale = vdotfall/fdotfall; for (int i = 0; i < nlocal; i++) { v[i][0] = scale * f[i][0]; v[i][1] = scale * f[i][1]; v[i][2] = scale * f[i][2]; } } // limit timestep so no particle moves further than dmax double *rmass = atom->rmass; double *mass = atom->mass; int *type = atom->type; dtvone = dt; for (int i = 0; i < nlocal; i++) { vmax = MAX(fabs(v[i][0]),fabs(v[i][1])); vmax = MAX(vmax,fabs(v[i][2])); if (dtvone*vmax > dmax) dtvone = dmax/vmax; } MPI_Allreduce(&dtvone,&dtv,1,MPI_DOUBLE,MPI_MIN,world); // min dtv over replicas, if necessary // this communicator would be invalid for multiprocess replicas if (update->multireplica == 1) { dtvone = dtv; MPI_Allreduce(&dtvone,&dtv,1,MPI_DOUBLE,MPI_MIN,universe->uworld); } // Euler integration step double **x = atom->x; if (rmass) { for (int i = 0; i < nlocal; i++) { dtfm = dtv / rmass[i]; x[i][0] += dtv * v[i][0]; x[i][1] += dtv * v[i][1]; x[i][2] += dtv * v[i][2]; v[i][0] += dtfm * f[i][0]; v[i][1] += dtfm * f[i][1]; v[i][2] += dtfm * f[i][2]; } } else { for (int i = 0; i < nlocal; i++) { dtfm = dtv / mass[type[i]]; x[i][0] += dtv * v[i][0]; x[i][1] += dtv * v[i][1]; x[i][2] += dtv * v[i][2]; v[i][0] += dtfm * f[i][0]; v[i][1] += dtfm * f[i][1]; v[i][2] += dtfm * f[i][2]; } } eprevious = ecurrent; ecurrent = energy_force(0); neval++; // energy tolerance criterion // only check after DELAYSTEP elapsed since velocties reset to 0 // sync across replicas if running multi-replica minimization if (update->etol > 0.0 && ntimestep-last_negative > DELAYSTEP) { if (update->multireplica == 0) { if (fabs(ecurrent-eprevious) < update->etol * 0.5*(fabs(ecurrent) + fabs(eprevious) + EPS_ENERGY)) return ETOL; } else { if (fabs(ecurrent-eprevious) < update->etol * 0.5*(fabs(ecurrent) + fabs(eprevious) + EPS_ENERGY)) flag = 0; else flag = 1; MPI_Allreduce(&flag,&flagall,1,MPI_INT,MPI_SUM,universe->uworld); if (flagall == 0) return ETOL; } } // force tolerance criterion // sync across replicas if running multi-replica minimization if (update->ftol > 0.0) { fdotf = fnorm_sqr(); if (update->multireplica == 0) { if (fdotf < update->ftol*update->ftol) return FTOL; } else { if (fdotf < update->ftol*update->ftol) flag = 0; else flag = 1; MPI_Allreduce(&flag,&flagall,1,MPI_INT,MPI_SUM,universe->uworld); if (flagall == 0) return FTOL; } } // output for thermo, dump, restart files if (output->next == ntimestep) { timer->stamp(); output->write(ntimestep); timer->stamp(TIME_OUTPUT); } } return MAXITER; } diff --git a/src/modify.cpp b/src/modify.cpp index f70ee43a3..99cb49cf1 100644 --- a/src/modify.cpp +++ b/src/modify.cpp @@ -1,1111 +1,1111 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain 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 "stdio.h" #include "string.h" #include "modify.h" #include "style_compute.h" #include "style_fix.h" #include "atom.h" #include "comm.h" #include "fix.h" #include "compute.h" #include "group.h" #include "update.h" #include "domain.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; #define DELTA 4 // mask settings - same as in fix.cpp #define INITIAL_INTEGRATE 1 #define POST_INTEGRATE 2 #define PRE_EXCHANGE 4 #define PRE_NEIGHBOR 8 #define PRE_FORCE 16 #define POST_FORCE 32 #define FINAL_INTEGRATE 64 #define END_OF_STEP 128 #define THERMO_ENERGY 256 #define INITIAL_INTEGRATE_RESPA 512 #define POST_INTEGRATE_RESPA 1024 #define PRE_FORCE_RESPA 2048 #define POST_FORCE_RESPA 4096 #define FINAL_INTEGRATE_RESPA 8192 #define MIN_PRE_EXCHANGE 16384 #define MIN_PRE_FORCE 32768 #define MIN_POST_FORCE 65536 #define MIN_ENERGY 131072 #define POST_RUN 262144 #define MIN(A,B) ((A) < (B)) ? (A) : (B) #define MAX(A,B) ((A) > (B)) ? (A) : (B) #define BIG 1.0e20 /* ---------------------------------------------------------------------- */ Modify::Modify(LAMMPS *lmp) : Pointers(lmp) { nfix = maxfix = 0; n_initial_integrate = n_post_integrate = 0; n_pre_exchange = n_pre_neighbor = 0; n_pre_force = n_post_force = 0; n_final_integrate = n_end_of_step = n_thermo_energy = 0; n_initial_integrate_respa = n_post_integrate_respa = 0; n_pre_force_respa = n_post_force_respa = n_final_integrate_respa = 0; n_min_pre_exchange = n_min_pre_force = n_min_post_force = n_min_energy = 0; fix = NULL; fmask = NULL; list_initial_integrate = list_post_integrate = NULL; list_pre_exchange = list_pre_neighbor = NULL; list_pre_force = list_post_force = NULL; list_final_integrate = list_end_of_step = NULL; list_thermo_energy = NULL; list_initial_integrate_respa = list_post_integrate_respa = NULL; list_pre_force_respa = list_post_force_respa = NULL; list_final_integrate_respa = NULL; list_min_pre_exchange = list_min_pre_force = list_min_post_force = list_min_energy = NULL; end_of_step_every = NULL; list_timeflag = NULL; nfix_restart_global = 0; id_restart_global = style_restart_global = state_restart_global = NULL; nfix_restart_peratom = 0; id_restart_peratom = style_restart_peratom = NULL; index_restart_peratom = NULL; ncompute = maxcompute = 0; compute = NULL; } /* ---------------------------------------------------------------------- */ Modify::~Modify() { // delete all fixes // do it via delete_fix() so callbacks in Atom are also updated correctly while (nfix) delete_fix(fix[0]->id); memory->sfree(fix); memory->sfree(fmask); // delete all computes for (int i = 0; i < ncompute; i++) delete compute[i]; memory->sfree(compute); delete [] list_initial_integrate; delete [] list_post_integrate; delete [] list_pre_exchange; delete [] list_pre_neighbor; delete [] list_pre_force; delete [] list_post_force; delete [] list_final_integrate; delete [] list_end_of_step; delete [] list_thermo_energy; delete [] list_initial_integrate_respa; delete [] list_post_integrate_respa; delete [] list_pre_force_respa; delete [] list_post_force_respa; delete [] list_final_integrate_respa; delete [] list_min_pre_exchange; delete [] list_min_pre_force; delete [] list_min_post_force; delete [] list_min_energy; delete [] end_of_step_every; delete [] list_timeflag; restart_deallocate(); } /* ---------------------------------------------------------------------- initialize all fixes and computes ------------------------------------------------------------------------- */ void Modify::init() { int i,j; // delete storage of restart info since it is not valid after 1st run restart_deallocate(); // create lists of fixes to call at each stage of run list_init(INITIAL_INTEGRATE,n_initial_integrate,list_initial_integrate); list_init(POST_INTEGRATE,n_post_integrate,list_post_integrate); list_init(PRE_EXCHANGE,n_pre_exchange,list_pre_exchange); list_init(PRE_NEIGHBOR,n_pre_neighbor,list_pre_neighbor); list_init(PRE_FORCE,n_pre_force,list_pre_force); list_init(POST_FORCE,n_post_force,list_post_force); list_init(FINAL_INTEGRATE,n_final_integrate,list_final_integrate); list_init_end_of_step(END_OF_STEP,n_end_of_step,list_end_of_step); list_init_thermo_energy(THERMO_ENERGY,n_thermo_energy,list_thermo_energy); list_init(INITIAL_INTEGRATE_RESPA, n_initial_integrate_respa,list_initial_integrate_respa); list_init(POST_INTEGRATE_RESPA, n_post_integrate_respa,list_post_integrate_respa); list_init(POST_FORCE_RESPA, n_post_force_respa,list_post_force_respa); list_init(PRE_FORCE_RESPA, n_pre_force_respa,list_pre_force_respa); list_init(FINAL_INTEGRATE_RESPA, n_final_integrate_respa,list_final_integrate_respa); list_init(MIN_PRE_EXCHANGE,n_min_pre_exchange,list_min_pre_exchange); list_init(MIN_PRE_FORCE,n_min_pre_force,list_min_pre_force); list_init(MIN_POST_FORCE,n_min_post_force,list_min_post_force); list_init(MIN_ENERGY,n_min_energy,list_min_energy); // init each fix // needs to come before compute init // this is b/c some computes call fix->dof() // FixRigid::dof() depends on its own init having been called comm->maxforward_fix = comm->maxreverse_fix = 0; for (i = 0; i < nfix; i++) fix[i]->init(); // set global flag if any fix has its restart_pbc flag set restart_pbc_any = 0; for (i = 0; i < nfix; i++) if (fix[i]->restart_pbc) restart_pbc_any = 1; // create list of computes that store invocation times list_init_compute(); // init each compute // set invoked_scalar,vector,etc to -1 to force new run to re-compute them // add initial timestep to all computes that store invocation times // since any of them may be invoked by initial thermo // do not clear out invocation times stored within a compute, // b/c some may be holdovers from previous run, like for ave fixes for (i = 0; i < ncompute; i++) { compute[i]->init(); compute[i]->invoked_scalar = -1; compute[i]->invoked_vector = -1; compute[i]->invoked_array = -1; compute[i]->invoked_peratom = -1; compute[i]->invoked_local = -1; } addstep_compute_all(update->ntimestep); // warn if any particle is time integrated more than once int nlocal = atom->nlocal; int *mask = atom->mask; int *flag = new int[nlocal]; for (i = 0; i < nlocal; i++) flag[i] = 0; int groupbit; for (i = 0; i < nfix; i++) { if (fix[i]->time_integrate == 0) continue; groupbit = fix[i]->groupbit; for (j = 0; j < nlocal; j++) if (mask[j] & groupbit) flag[j]++; } int check = 0; for (i = 0; i < nlocal; i++) if (flag[i] > 1) check = 1; delete [] flag; int checkall; MPI_Allreduce(&check,&checkall,1,MPI_INT,MPI_SUM,world); if (comm->me == 0 && checkall) error->warning("One or more atoms are time integrated more than once"); } /* ---------------------------------------------------------------------- setup for run, calls setup() of all fixes ------------------------------------------------------------------------- */ void Modify::setup(int vflag) { if (update->whichflag == 1) for (int i = 0; i < nfix; i++) fix[i]->setup(vflag); else if (update->whichflag == 2) for (int i = 0; i < nfix; i++) fix[i]->min_setup(vflag); } /* ---------------------------------------------------------------------- setup pre_force call, only for relevant fixes ------------------------------------------------------------------------- */ void Modify::setup_pre_force(int vflag) { if (update->whichflag == 1) for (int i = 0; i < n_pre_force; i++) fix[list_pre_force[i]]->setup_pre_force(vflag); else if (update->whichflag == 2) for (int i = 0; i < n_pre_force; i++) fix[list_min_pre_force[i]]->min_setup_pre_force(vflag); } /* ---------------------------------------------------------------------- 1st half of integrate call, only for relevant fixes ------------------------------------------------------------------------- */ void Modify::initial_integrate(int vflag) { for (int i = 0; i < n_initial_integrate; i++) fix[list_initial_integrate[i]]->initial_integrate(vflag); } /* ---------------------------------------------------------------------- post_integrate call, only for relevant fixes ------------------------------------------------------------------------- */ void Modify::post_integrate() { for (int i = 0; i < n_post_integrate; i++) fix[list_post_integrate[i]]->post_integrate(); } /* ---------------------------------------------------------------------- pre_exchange call, only for relevant fixes ------------------------------------------------------------------------- */ void Modify::pre_exchange() { for (int i = 0; i < n_pre_exchange; i++) fix[list_pre_exchange[i]]->pre_exchange(); } /* ---------------------------------------------------------------------- pre_neighbor call, only for relevant fixes ------------------------------------------------------------------------- */ void Modify::pre_neighbor() { for (int i = 0; i < n_pre_neighbor; i++) fix[list_pre_neighbor[i]]->pre_neighbor(); } /* ---------------------------------------------------------------------- pre_force call, only for relevant fixes ------------------------------------------------------------------------- */ void Modify::pre_force(int vflag) { for (int i = 0; i < n_pre_force; i++) fix[list_pre_force[i]]->pre_force(vflag); } /* ---------------------------------------------------------------------- post_force call, only for relevant fixes ------------------------------------------------------------------------- */ void Modify::post_force(int vflag) { for (int i = 0; i < n_post_force; i++) fix[list_post_force[i]]->post_force(vflag); } /* ---------------------------------------------------------------------- 2nd half of integrate call, only for relevant fixes ------------------------------------------------------------------------- */ void Modify::final_integrate() { for (int i = 0; i < n_final_integrate; i++) fix[list_final_integrate[i]]->final_integrate(); } /* ---------------------------------------------------------------------- end-of-timestep call, only for relevant fixes only call fix->end_of_step() on timesteps that are multiples of nevery ------------------------------------------------------------------------- */ void Modify::end_of_step() { for (int i = 0; i < n_end_of_step; i++) if (update->ntimestep % end_of_step_every[i] == 0) fix[list_end_of_step[i]]->end_of_step(); } /* ---------------------------------------------------------------------- thermo energy call, only for relevant fixes called by Thermo class compute_scalar() is fix call to return energy ------------------------------------------------------------------------- */ double Modify::thermo_energy() { double energy = 0.0; for (int i = 0; i < n_thermo_energy; i++) energy += fix[list_thermo_energy[i]]->compute_scalar(); return energy; } /* ---------------------------------------------------------------------- post_run call ------------------------------------------------------------------------- */ void Modify::post_run() { for (int i = 0; i < nfix; i++) fix[i]->post_run(); } /* ---------------------------------------------------------------------- setup rRESPA pre_force call, only for relevant fixes ------------------------------------------------------------------------- */ void Modify::setup_pre_force_respa(int vflag, int ilevel) { for (int i = 0; i < n_pre_force; i++) fix[list_pre_force[i]]->setup_pre_force_respa(vflag,ilevel); } /* ---------------------------------------------------------------------- 1st half of rRESPA integrate call, only for relevant fixes ------------------------------------------------------------------------- */ void Modify::initial_integrate_respa(int vflag, int ilevel, int iloop) { for (int i = 0; i < n_initial_integrate_respa; i++) fix[list_initial_integrate_respa[i]]-> initial_integrate_respa(vflag,ilevel,iloop); } /* ---------------------------------------------------------------------- rRESPA post_integrate call, only for relevant fixes ------------------------------------------------------------------------- */ void Modify::post_integrate_respa(int ilevel, int iloop) { for (int i = 0; i < n_post_integrate_respa; i++) fix[list_post_integrate_respa[i]]->post_integrate_respa(ilevel,iloop); } /* ---------------------------------------------------------------------- rRESPA pre_force call, only for relevant fixes ------------------------------------------------------------------------- */ void Modify::pre_force_respa(int vflag, int ilevel, int iloop) { for (int i = 0; i < n_pre_force_respa; i++) fix[list_pre_force_respa[i]]->pre_force_respa(vflag,ilevel,iloop); } /* ---------------------------------------------------------------------- rRESPA post_force call, only for relevant fixes ------------------------------------------------------------------------- */ void Modify::post_force_respa(int vflag, int ilevel, int iloop) { for (int i = 0; i < n_post_force_respa; i++) fix[list_post_force_respa[i]]->post_force_respa(vflag,ilevel,iloop); } /* ---------------------------------------------------------------------- 2nd half of rRESPA integrate call, only for relevant fixes ------------------------------------------------------------------------- */ void Modify::final_integrate_respa(int ilevel, int iloop) { for (int i = 0; i < n_final_integrate_respa; i++) fix[list_final_integrate_respa[i]]->final_integrate_respa(ilevel,iloop); } /* ---------------------------------------------------------------------- minimizer pre-exchange call, only for relevant fixes ------------------------------------------------------------------------- */ void Modify::min_pre_exchange() { for (int i = 0; i < n_min_pre_exchange; i++) fix[list_min_pre_exchange[i]]->min_pre_exchange(); } /* ---------------------------------------------------------------------- minimizer pre-force call, only for relevant fixes ------------------------------------------------------------------------- */ void Modify::min_pre_force(int vflag) { for (int i = 0; i < n_min_pre_force; i++) fix[list_min_pre_force[i]]->min_pre_force(vflag); } /* ---------------------------------------------------------------------- minimizer force adjustment call, only for relevant fixes ------------------------------------------------------------------------- */ void Modify::min_post_force(int vflag) { for (int i = 0; i < n_min_post_force; i++) fix[list_min_post_force[i]]->min_post_force(vflag); } /* ---------------------------------------------------------------------- minimizer energy/force evaluation, only for relevant fixes return energy and forces on extra degrees of freedom ------------------------------------------------------------------------- */ double Modify::min_energy(double *fextra) { int ifix,index; index = 0; double eng = 0.0; for (int i = 0; i < n_min_energy; i++) { ifix = list_min_energy[i]; eng += fix[ifix]->min_energy(&fextra[index]); index += fix[ifix]->min_dof(); } return eng; } /* ---------------------------------------------------------------------- store current state of extra dof, only for relevant fixes ------------------------------------------------------------------------- */ void Modify::min_store() { for (int i = 0; i < n_min_energy; i++) fix[list_min_energy[i]]->min_store(); } /* ---------------------------------------------------------------------- mange state of extra dof on a stack, only for relevant fixes ------------------------------------------------------------------------- */ void Modify::min_clearstore() { for (int i = 0; i < n_min_energy; i++) fix[list_min_energy[i]]->min_clearstore(); } void Modify::min_pushstore() { for (int i = 0; i < n_min_energy; i++) fix[list_min_energy[i]]->min_pushstore(); } void Modify::min_popstore() { for (int i = 0; i < n_min_energy; i++) fix[list_min_energy[i]]->min_popstore(); } /* ---------------------------------------------------------------------- displace extra dof along vector hextra, only for relevant fixes ------------------------------------------------------------------------- */ void Modify::min_step(double alpha, double *hextra) { int ifix,index; index = 0; for (int i = 0; i < n_min_energy; i++) { ifix = list_min_energy[i]; fix[ifix]->min_step(alpha,&hextra[index]); index += fix[ifix]->min_dof(); } } /* ---------------------------------------------------------------------- compute max allowed step size along vector hextra, only for relevant fixes ------------------------------------------------------------------------- */ double Modify::max_alpha(double *hextra) { int ifix,index; double alpha = BIG; index = 0; for (int i = 0; i < n_min_energy; i++) { ifix = list_min_energy[i]; double alpha_one = fix[ifix]->max_alpha(&hextra[index]); alpha = MIN(alpha,alpha_one); index += fix[ifix]->min_dof(); } return alpha; } /* ---------------------------------------------------------------------- extract extra dof for minimization, only for relevant fixes ------------------------------------------------------------------------- */ int Modify::min_dof() { int ndof = 0; for (int i = 0; i < n_min_energy; i++) ndof += fix[list_min_energy[i]]->min_dof(); return ndof; } /* ---------------------------------------------------------------------- reset reference state of fix, only for relevant fixes ------------------------------------------------------------------------- */ int Modify::min_reset_ref() { int itmp,itmpall; itmpall = 0; for (int i = 0; i < n_min_energy; i++) { itmp = fix[list_min_energy[i]]->min_reset_ref(); if (itmp) itmpall = 1; } return itmpall; } /* ---------------------------------------------------------------------- add a new fix or replace one with same ID ------------------------------------------------------------------------- */ void Modify::add_fix(int narg, char **arg) { if (domain->box_exist == 0) error->all("Fix command before simulation box is defined"); if (narg < 3) error->all("Illegal fix command"); // check group ID int igroup = group->find(arg[1]); if (igroup == -1) error->all("Could not find fix group ID"); // if fix ID exists: // set newflag = 0 so create new fix in same location in fix list // error if new style does not match old style // since can't replace it (all when-to-invoke ptrs would be invalid) // warn if new group != old group // delete old fix, but do not call update_callback(), // since will replace this fix and thus other fix locs will not change // set ptr to NULL in case new fix scans list of fixes, // e.g. scan will occur in add_callback() if called by new fix // if fix ID does not exist: // set newflag = 1 so create new fix // extend fix and fmask lists as necessary int ifix,newflag; for (ifix = 0; ifix < nfix; ifix++) if (strcmp(arg[0],fix[ifix]->id) == 0) break; if (ifix < nfix) { newflag = 0; if (strcmp(arg[2],fix[ifix]->style) != 0) error->all("Replacing a fix, but new style != old style"); if (fix[ifix]->igroup != igroup && comm->me == 0) error->warning("Replacing a fix, but new group != old group"); delete fix[ifix]; fix[ifix] = NULL; } else { newflag = 1; if (nfix == maxfix) { maxfix += DELTA; fix = (Fix **) memory->srealloc(fix,maxfix*sizeof(Fix *),"modify:fix"); fmask = (int *) memory->srealloc(fmask,maxfix*sizeof(int),"modify:fmask"); } } // create the Fix if (0) return; // dummy line to enable else-if macro expansion #define FIX_CLASS #define FixStyle(key,Class) \ else if (strcmp(arg[2],#key) == 0) fix[ifix] = new Class(lmp,narg,arg); #include "style_fix.h" #undef FIX_CLASS else error->all("Invalid fix style"); // set fix mask values and increment nfix (if new) fmask[ifix] = fix[ifix]->setmask(); if (newflag) nfix++; // check if Fix is in restart_global list // if yes, pass state info to the Fix so it can reset itself for (int i = 0; i < nfix_restart_global; i++) if (strcmp(id_restart_global[i],fix[ifix]->id) == 0 && strcmp(style_restart_global[i],fix[ifix]->style) == 0) { fix[ifix]->restart(state_restart_global[i]); if (comm->me == 0) { char *str = (char *) ("Resetting global state of Fix %s Style %s " "from restart file info\n"); if (screen) fprintf(screen,str,fix[ifix]->id,fix[ifix]->style); if (logfile) fprintf(logfile,str,fix[ifix]->id,fix[ifix]->style); } } // check if Fix is in restart_peratom list // if yes, loop over atoms so they can extract info from atom->extra array for (int i = 0; i < nfix_restart_peratom; i++) if (strcmp(id_restart_peratom[i],fix[ifix]->id) == 0 && strcmp(style_restart_peratom[i],fix[ifix]->style) == 0) { for (int j = 0; j < atom->nlocal; j++) fix[ifix]->unpack_restart(j,index_restart_peratom[i]); if (comm->me == 0) { char *str = (char *) ("Resetting per-atom state of Fix %s Style %s " "from restart file info\n"); if (screen) fprintf(screen,str,fix[ifix]->id,fix[ifix]->style); if (logfile) fprintf(logfile,str,fix[ifix]->id,fix[ifix]->style); } } } /* ---------------------------------------------------------------------- modify a Fix's parameters ------------------------------------------------------------------------- */ void Modify::modify_fix(int narg, char **arg) { if (narg < 2) error->all("Illegal fix_modify command"); // lookup Fix ID int ifix; for (ifix = 0; ifix < nfix; ifix++) if (strcmp(arg[0],fix[ifix]->id) == 0) break; if (ifix == nfix) error->all("Could not find fix_modify ID"); fix[ifix]->modify_params(narg-1,&arg[1]); } /* ---------------------------------------------------------------------- delete a Fix from list of Fixes Atom class must update indices in its list of callbacks to fixes ------------------------------------------------------------------------- */ void Modify::delete_fix(const char *id) { int ifix = find_fix(id); if (ifix < 0) error->all("Could not find fix ID to delete"); delete fix[ifix]; atom->update_callback(ifix); // move other Fixes and fmask down in list one slot for (int i = ifix+1; i < nfix; i++) fix[i-1] = fix[i]; for (int i = ifix+1; i < nfix; i++) fmask[i-1] = fmask[i]; nfix--; } /* ---------------------------------------------------------------------- find a fix by ID return index of fix or -1 if not found ------------------------------------------------------------------------- */ int Modify::find_fix(const char *id) { int ifix; for (ifix = 0; ifix < nfix; ifix++) if (strcmp(id,fix[ifix]->id) == 0) break; if (ifix == nfix) return -1; return ifix; } /* ---------------------------------------------------------------------- add a new compute ------------------------------------------------------------------------- */ void Modify::add_compute(int narg, char **arg) { if (narg < 3) error->all("Illegal compute command"); // error check for (int icompute = 0; icompute < ncompute; icompute++) if (strcmp(arg[0],compute[icompute]->id) == 0) error->all("Reuse of compute ID"); // extend Compute list if necessary if (ncompute == maxcompute) { maxcompute += DELTA; compute = (Compute **) memory->srealloc(compute,maxcompute*sizeof(Compute *),"modify:compute"); } // create the Compute if (0) return; // dummy line to enable else-if macro expansion #define COMPUTE_CLASS #define ComputeStyle(key,Class) \ else if (strcmp(arg[2],#key) == 0) \ compute[ncompute] = new Class(lmp,narg,arg); #include "style_compute.h" #undef COMPUTE_CLASS else error->all("Invalid compute style"); ncompute++; } /* ---------------------------------------------------------------------- modify a Compute's parameters ------------------------------------------------------------------------- */ void Modify::modify_compute(int narg, char **arg) { if (narg < 2) error->all("Illegal compute_modify command"); // lookup Compute ID int icompute; for (icompute = 0; icompute < ncompute; icompute++) if (strcmp(arg[0],compute[icompute]->id) == 0) break; if (icompute == ncompute) error->all("Could not find compute_modify ID"); compute[icompute]->modify_params(narg-1,&arg[1]); } /* ---------------------------------------------------------------------- delete a Compute from list of Computes ------------------------------------------------------------------------- */ void Modify::delete_compute(char *id) { int icompute = find_compute(id); if (icompute < 0) error->all("Could not find compute ID to delete"); delete compute[icompute]; // move other Computes down in list one slot for (int i = icompute+1; i < ncompute; i++) compute[i-1] = compute[i]; ncompute--; } /* ---------------------------------------------------------------------- find a compute by ID return index of compute or -1 if not found ------------------------------------------------------------------------- */ int Modify::find_compute(char *id) { int icompute; for (icompute = 0; icompute < ncompute; icompute++) if (strcmp(id,compute[icompute]->id) == 0) break; if (icompute == ncompute) return -1; return icompute; } /* ---------------------------------------------------------------------- clear invoked flag of all computes called everywhere that computes are used, before computes are invoked invoked flag used to avoid re-invoking same compute multiple times and to flag computes that store invocation times as having been invoked ------------------------------------------------------------------------- */ void Modify::clearstep_compute() { for (int icompute = 0; icompute < ncompute; icompute++) compute[icompute]->invoked_flag = 0; } /* ---------------------------------------------------------------------- loop over computes that store invocation times if its invoked flag set on this timestep, schedule next invocation called everywhere that computes are used, after computes are invoked ------------------------------------------------------------------------- */ -void Modify::addstep_compute(int newstep) +void Modify::addstep_compute(bigint newstep) { for (int icompute = 0; icompute < n_timeflag; icompute++) if (compute[list_timeflag[icompute]]->invoked_flag) compute[list_timeflag[icompute]]->addstep(newstep); } /* ---------------------------------------------------------------------- loop over all computes schedule next invocation for those that store invocation times called when not sure what computes will be needed on newstep do not loop only over n_timeflag, since may not be set yet ------------------------------------------------------------------------- */ -void Modify::addstep_compute_all(int newstep) +void Modify::addstep_compute_all(bigint newstep) { for (int icompute = 0; icompute < ncompute; icompute++) if (compute[icompute]->timeflag) compute[icompute]->addstep(newstep); } /* ---------------------------------------------------------------------- write to restart file for all Fixes with restart info (1) fixes that have global state (2) fixes that store per-atom quantities ------------------------------------------------------------------------- */ void Modify::write_restart(FILE *fp) { int me = comm->me; int count = 0; for (int i = 0; i < nfix; i++) if (fix[i]->restart_global) count++; if (me == 0) fwrite(&count,sizeof(int),1,fp); int n; for (int i = 0; i < nfix; i++) if (fix[i]->restart_global) { if (me == 0) { n = strlen(fix[i]->id) + 1; fwrite(&n,sizeof(int),1,fp); fwrite(fix[i]->id,sizeof(char),n,fp); n = strlen(fix[i]->style) + 1; fwrite(&n,sizeof(int),1,fp); fwrite(fix[i]->style,sizeof(char),n,fp); } fix[i]->write_restart(fp); } count = 0; for (int i = 0; i < nfix; i++) if (fix[i]->restart_peratom) count++; if (me == 0) fwrite(&count,sizeof(int),1,fp); for (int i = 0; i < nfix; i++) if (fix[i]->restart_peratom) { if (me == 0) { n = strlen(fix[i]->id) + 1; fwrite(&n,sizeof(int),1,fp); fwrite(fix[i]->id,sizeof(char),n,fp); n = strlen(fix[i]->style) + 1; fwrite(&n,sizeof(int),1,fp); fwrite(fix[i]->style,sizeof(char),n,fp); n = fix[i]->maxsize_restart(); fwrite(&n,sizeof(int),1,fp); } } } /* ---------------------------------------------------------------------- read in restart file data on all previously defined Fixes with restart info (1) fixes that have global state (2) fixes that store per-atom quantities return maxsize of extra info that will be stored with any atom ------------------------------------------------------------------------- */ int Modify::read_restart(FILE *fp) { // nfix_restart_global = # of restart entries with global state info int me = comm->me; if (me == 0) fread(&nfix_restart_global,sizeof(int),1,fp); MPI_Bcast(&nfix_restart_global,1,MPI_INT,0,world); // allocate space for each entry if (nfix_restart_global) { id_restart_global = new char*[nfix_restart_global]; style_restart_global = new char*[nfix_restart_global]; state_restart_global = new char*[nfix_restart_global]; } // read each entry and Bcast to all procs // each entry has id string, style string, chunk of state data int n; for (int i = 0; i < nfix_restart_global; i++) { if (me == 0) fread(&n,sizeof(int),1,fp); MPI_Bcast(&n,1,MPI_INT,0,world); id_restart_global[i] = new char[n]; if (me == 0) fread(id_restart_global[i],sizeof(char),n,fp); MPI_Bcast(id_restart_global[i],n,MPI_CHAR,0,world); if (me == 0) fread(&n,sizeof(int),1,fp); MPI_Bcast(&n,1,MPI_INT,0,world); style_restart_global[i] = new char[n]; if (me == 0) fread(style_restart_global[i],sizeof(char),n,fp); MPI_Bcast(style_restart_global[i],n,MPI_CHAR,0,world); if (me == 0) fread(&n,sizeof(int),1,fp); MPI_Bcast(&n,1,MPI_INT,0,world); state_restart_global[i] = new char[n]; if (me == 0) fread(state_restart_global[i],sizeof(char),n,fp); MPI_Bcast(state_restart_global[i],n,MPI_CHAR,0,world); } // nfix_restart_peratom = # of restart entries with peratom info int maxsize = 0; if (me == 0) fread(&nfix_restart_peratom,sizeof(int),1,fp); MPI_Bcast(&nfix_restart_peratom,1,MPI_INT,0,world); // allocate space for each entry if (nfix_restart_peratom) { id_restart_peratom = new char*[nfix_restart_peratom]; style_restart_peratom = new char*[nfix_restart_peratom]; index_restart_peratom = new int[nfix_restart_peratom]; } // read each entry and Bcast to all procs // each entry has id string, style string, maxsize of one atom's data // set index = which set of extra data this fix represents for (int i = 0; i < nfix_restart_peratom; i++) { if (me == 0) fread(&n,sizeof(int),1,fp); MPI_Bcast(&n,1,MPI_INT,0,world); id_restart_peratom[i] = new char[n]; if (me == 0) fread(id_restart_peratom[i],sizeof(char),n,fp); MPI_Bcast(id_restart_peratom[i],n,MPI_CHAR,0,world); if (me == 0) fread(&n,sizeof(int),1,fp); MPI_Bcast(&n,1,MPI_INT,0,world); style_restart_peratom[i] = new char[n]; if (me == 0) fread(style_restart_peratom[i],sizeof(char),n,fp); MPI_Bcast(style_restart_peratom[i],n,MPI_CHAR,0,world); if (me == 0) fread(&n,sizeof(int),1,fp); MPI_Bcast(&n,1,MPI_INT,0,world); maxsize += n; index_restart_peratom[i] = i; } return maxsize; } /* ---------------------------------------------------------------------- delete all lists of restart file Fix info ------------------------------------------------------------------------- */ void Modify::restart_deallocate() { if (nfix_restart_global) { for (int i = 0; i < nfix_restart_global; i++) { delete [] id_restart_global[i]; delete [] style_restart_global[i]; delete [] state_restart_global[i]; } delete [] id_restart_global; delete [] style_restart_global; delete [] state_restart_global; } if (nfix_restart_peratom) { for (int i = 0; i < nfix_restart_peratom; i++) { delete [] id_restart_peratom[i]; delete [] style_restart_peratom[i]; } delete [] id_restart_peratom; delete [] style_restart_peratom; delete [] index_restart_peratom; } nfix_restart_global = nfix_restart_peratom = 0; } /* ---------------------------------------------------------------------- create list of fix indices for fixes which match mask ------------------------------------------------------------------------- */ void Modify::list_init(int mask, int &n, int *&list) { delete [] list; n = 0; for (int i = 0; i < nfix; i++) if (fmask[i] & mask) n++; list = new int[n]; n = 0; for (int i = 0; i < nfix; i++) if (fmask[i] & mask) list[n++] = i; } /* ---------------------------------------------------------------------- create list of fix indices for end_of_step fixes also create end_of_step_every[] ------------------------------------------------------------------------- */ void Modify::list_init_end_of_step(int mask, int &n, int *&list) { delete [] list; delete [] end_of_step_every; n = 0; for (int i = 0; i < nfix; i++) if (fmask[i] & mask) n++; list = new int[n]; end_of_step_every = new int[n]; n = 0; for (int i = 0; i < nfix; i++) if (fmask[i] & mask) { list[n] = i; end_of_step_every[n++] = fix[i]->nevery; } } /* ---------------------------------------------------------------------- create list of fix indices for thermo energy fixes only added to list if fix has THERMO_ENERGY mask and its thermo_energy flag was set via fix_modify ------------------------------------------------------------------------- */ void Modify::list_init_thermo_energy(int mask, int &n, int *&list) { delete [] list; n = 0; for (int i = 0; i < nfix; i++) if (fmask[i] & mask && fix[i]->thermo_energy) n++; list = new int[n]; n = 0; for (int i = 0; i < nfix; i++) if (fmask[i] & mask && fix[i]->thermo_energy) list[n++] = i; } /* ---------------------------------------------------------------------- create list of compute indices for computes which store invocation times ------------------------------------------------------------------------- */ void Modify::list_init_compute() { delete [] list_timeflag; n_timeflag = 0; for (int i = 0; i < ncompute; i++) if (compute[i]->timeflag) n_timeflag++; list_timeflag = new int[n_timeflag]; n_timeflag = 0; for (int i = 0; i < ncompute; i++) if (compute[i]->timeflag) list_timeflag[n_timeflag++] = i; } /* ---------------------------------------------------------------------- return # of bytes of allocated memory from all fixes ------------------------------------------------------------------------- */ double Modify::memory_usage() { double bytes = 0.0; for (int i = 0; i < nfix; i++) bytes += fix[i]->memory_usage(); for (int i = 0; i < ncompute; i++) bytes += compute[i]->memory_usage(); return bytes; } diff --git a/src/modify.h b/src/modify.h index 0601e1b85..f211167a1 100644 --- a/src/modify.h +++ b/src/modify.h @@ -1,137 +1,138 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain 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_MODIFY_H #define LMP_MODIFY_H #include "stdio.h" #include "pointers.h" +#include "lmptype.h" namespace LAMMPS_NS { class Modify : protected Pointers { public: int nfix,maxfix; int n_initial_integrate,n_post_integrate,n_pre_exchange,n_pre_neighbor; int n_pre_force,n_post_force; int n_final_integrate,n_end_of_step,n_thermo_energy; int n_initial_integrate_respa,n_post_integrate_respa; int n_pre_force_respa,n_post_force_respa,n_final_integrate_respa; int n_min_pre_exchange,n_min_pre_force,n_min_post_force,n_min_energy; int restart_pbc_any; // 1 if any fix sets restart_pbc int nfix_restart_global; // stored fix global info from restart file int nfix_restart_peratom; // stored fix peratom info from restart file class Fix **fix; // list of fixes int *fmask; // bit mask for when each fix is applied int ncompute,maxcompute; // list of computes class Compute **compute; Modify(class LAMMPS *); ~Modify(); void init(); void setup(int); void setup_pre_force(int); void initial_integrate(int); void post_integrate(); void pre_decide(); void pre_exchange(); void pre_neighbor(); void pre_force(int); void post_force(int); void final_integrate(); void end_of_step(); double thermo_energy(); void post_run(); void setup_pre_force_respa(int, int); void initial_integrate_respa(int, int, int); void post_integrate_respa(int, int); void pre_force_respa(int, int, int); void post_force_respa(int, int, int); void final_integrate_respa(int, int); void setup_min_pre_force(int); void min_pre_exchange(); void min_pre_force(int); void min_post_force(int); double min_energy(double *); void min_store(); void min_step(double, double *); void min_clearstore(); void min_pushstore(); void min_popstore(); int min_reset_ref(); double max_alpha(double *); int min_dof(); void add_fix(int, char **); void modify_fix(int, char **); void delete_fix(const char *); int find_fix(const char *); void add_compute(int, char **); void modify_compute(int, char **); void delete_compute(char *); int find_compute(char *); void clearstep_compute(); - void addstep_compute(int); - void addstep_compute_all(int); + void addstep_compute(bigint); + void addstep_compute_all(bigint); void write_restart(FILE *); int read_restart(FILE *); void restart_deallocate(); double memory_usage(); private: // lists of fixes to apply at different stages of timestep int *list_initial_integrate,*list_post_integrate; int *list_pre_exchange,*list_pre_neighbor; int *list_pre_force,*list_post_force; int *list_final_integrate,*list_end_of_step,*list_thermo_energy; int *list_initial_integrate_respa,*list_post_integrate_respa; int *list_pre_force_respa,*list_post_force_respa; int *list_final_integrate_respa; int *list_min_pre_exchange,*list_min_pre_force; int *list_min_post_force,*list_min_energy; int *end_of_step_every; int n_timeflag; // list of computes that store time invocation int *list_timeflag; char **id_restart_global; // stored fix global info char **style_restart_global; // from read-in restart file char **state_restart_global; char **id_restart_peratom; // stored fix peratom info char **style_restart_peratom; // from read-in restart file int *index_restart_peratom; int index_permanent; // fix/compute index returned to library call void list_init(int, int &, int *&); void list_init_end_of_step(int, int &, int *&); void list_init_thermo_energy(int, int &, int *&); void list_init_compute(); }; } #endif diff --git a/src/neigh_bond.cpp b/src/neigh_bond.cpp index 57245abd3..6383dae8f 100644 --- a/src/neigh_bond.cpp +++ b/src/neigh_bond.cpp @@ -1,385 +1,400 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ #include "neighbor.h" +#include "lmptype.h" #include "atom.h" #include "force.h" #include "update.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; #define BONDDELTA 10000 /* ---------------------------------------------------------------------- */ void Neighbor::bond_all() { int i,m,atom1; int nlocal = atom->nlocal; int *num_bond = atom->num_bond; int **bond_atom = atom->bond_atom; int **bond_type = atom->bond_type; int *tag = atom->tag; int newton_bond = force->newton_bond; nbondlist = 0; for (i = 0; i < nlocal; i++) for (m = 0; m < num_bond[i]; m++) { atom1 = atom->map(bond_atom[i][m]); if (atom1 == -1) { - char str[128]; - sprintf(str,"Bond atoms %d %d missing on proc %d at step %d", - tag[i],bond_atom[i][m],me,update->ntimestep); + char str[128],fstr[64]; + sprintf(fstr,"Bond atoms %%d %%d missing on proc %%d at step %s", + BIGINT_FORMAT); + sprintf(str,fstr,tag[i],bond_atom[i][m],me,update->ntimestep); error->one(str); } if (newton_bond || i < atom1) { if (nbondlist == maxbond) { maxbond += BONDDELTA; bondlist = memory->grow_2d_int_array(bondlist,maxbond,3, "neighbor:bondlist"); } bondlist[nbondlist][0] = i; bondlist[nbondlist][1] = atom1; bondlist[nbondlist][2] = bond_type[i][m]; nbondlist++; } } } /* ---------------------------------------------------------------------- */ void Neighbor::bond_partial() { int i,m,atom1; int nlocal = atom->nlocal; int *num_bond = atom->num_bond; int **bond_atom = atom->bond_atom; int **bond_type = atom->bond_type; int *tag = atom->tag; int newton_bond = force->newton_bond; nbondlist = 0; for (i = 0; i < nlocal; i++) for (m = 0; m < num_bond[i]; m++) { if (bond_type[i][m] <= 0) continue; atom1 = atom->map(bond_atom[i][m]); if (atom1 == -1) { - char str[128]; - sprintf(str,"Bond atoms %d %d missing on proc %d at step %d", - tag[i],bond_atom[i][m],me,update->ntimestep); + char str[128],fstr[64]; + sprintf(fstr,"Bond atoms %%d %%d missing on proc %%d at step %s", + BIGINT_FORMAT); + sprintf(str,fstr,tag[i],bond_atom[i][m],me,update->ntimestep); error->one(str); } if (newton_bond || i < atom1) { if (nbondlist == maxbond) { maxbond += BONDDELTA; bondlist = memory->grow_2d_int_array(bondlist,maxbond,3, "neighbor:bondlist"); } bondlist[nbondlist][0] = i; bondlist[nbondlist][1] = atom1; bondlist[nbondlist][2] = bond_type[i][m]; nbondlist++; } } } /* ---------------------------------------------------------------------- */ void Neighbor::angle_all() { int i,m,atom1,atom2,atom3; int nlocal = atom->nlocal; int *num_angle = atom->num_angle; int **angle_atom1 = atom->angle_atom1; int **angle_atom2 = atom->angle_atom2; int **angle_atom3 = atom->angle_atom3; int **angle_type = atom->angle_type; int newton_bond = force->newton_bond; nanglelist = 0; for (i = 0; i < nlocal; i++) for (m = 0; m < num_angle[i]; m++) { atom1 = atom->map(angle_atom1[i][m]); atom2 = atom->map(angle_atom2[i][m]); atom3 = atom->map(angle_atom3[i][m]); if (atom1 == -1 || atom2 == -1 || atom3 == -1) { - char str[128]; - sprintf(str,"Angle atoms %d %d %d missing on proc %d at step %d", + char str[128],fstr[64]; + sprintf(fstr,"Angle atoms %%d %%d %%d missing on proc %%d at step %s", + BIGINT_FORMAT); + sprintf(str,fstr, angle_atom1[i][m],angle_atom2[i][m],angle_atom3[i][m], me,update->ntimestep); error->one(str); } if (newton_bond || (i <= atom1 && i <= atom2 && i <= atom3)) { if (nanglelist == maxangle) { maxangle += BONDDELTA; anglelist = memory->grow_2d_int_array(anglelist,maxangle,4, "neighbor:anglelist"); } anglelist[nanglelist][0] = atom1; anglelist[nanglelist][1] = atom2; anglelist[nanglelist][2] = atom3; anglelist[nanglelist][3] = angle_type[i][m]; nanglelist++; } } } /* ---------------------------------------------------------------------- */ void Neighbor::angle_partial() { int i,m,atom1,atom2,atom3; int nlocal = atom->nlocal; int *num_angle = atom->num_angle; int **angle_atom1 = atom->angle_atom1; int **angle_atom2 = atom->angle_atom2; int **angle_atom3 = atom->angle_atom3; int **angle_type = atom->angle_type; int newton_bond = force->newton_bond; nanglelist = 0; for (i = 0; i < nlocal; i++) for (m = 0; m < num_angle[i]; m++) { if (angle_type[i][m] <= 0) continue; atom1 = atom->map(angle_atom1[i][m]); atom2 = atom->map(angle_atom2[i][m]); atom3 = atom->map(angle_atom3[i][m]); if (atom1 == -1 || atom2 == -1 || atom3 == -1) { - char str[128]; - sprintf(str,"Angle atoms %d %d %d missing on proc %d at step %d", + char str[128],fstr[64]; + sprintf(fstr,"Angle atoms %%d %%d %%d missing on proc %%d at step %s", + BIGINT_FORMAT); + sprintf(str,fstr, angle_atom1[i][m],angle_atom2[i][m],angle_atom3[i][m], me,update->ntimestep); error->one(str); } if (newton_bond || (i <= atom1 && i <= atom2 && i <= atom3)) { if (nanglelist == maxangle) { maxangle += BONDDELTA; anglelist = memory->grow_2d_int_array(anglelist,maxangle,4, "neighbor:anglelist"); } anglelist[nanglelist][0] = atom1; anglelist[nanglelist][1] = atom2; anglelist[nanglelist][2] = atom3; anglelist[nanglelist][3] = angle_type[i][m]; nanglelist++; } } } /* ---------------------------------------------------------------------- */ void Neighbor::dihedral_all() { int i,m,atom1,atom2,atom3,atom4; int nlocal = atom->nlocal; int *num_dihedral = atom->num_dihedral; int **dihedral_atom1 = atom->dihedral_atom1; int **dihedral_atom2 = atom->dihedral_atom2; int **dihedral_atom3 = atom->dihedral_atom3; int **dihedral_atom4 = atom->dihedral_atom4; int **dihedral_type = atom->dihedral_type; int newton_bond = force->newton_bond; ndihedrallist = 0; for (i = 0; i < nlocal; i++) for (m = 0; m < num_dihedral[i]; m++) { atom1 = atom->map(dihedral_atom1[i][m]); atom2 = atom->map(dihedral_atom2[i][m]); atom3 = atom->map(dihedral_atom3[i][m]); atom4 = atom->map(dihedral_atom4[i][m]); if (atom1 == -1 || atom2 == -1 || atom3 == -1 || atom4 == -1) { - char str[128]; - sprintf(str,"Dihedral atoms %d %d %d %d missing on proc %d at step %d", + char str[128],fstr[128]; + sprintf(fstr,"Dihedral atoms %%d %%d %%d %%d " + "missing on proc %%d at step %s",BIGINT_FORMAT); + sprintf(str,fstr, dihedral_atom1[i][m],dihedral_atom2[i][m], dihedral_atom3[i][m],dihedral_atom4[i][m], me,update->ntimestep); error->one(str); } if (newton_bond || (i <= atom1 && i <= atom2 && i <= atom3 && i <= atom4)) { if (ndihedrallist == maxdihedral) { maxdihedral += BONDDELTA; dihedrallist = memory->grow_2d_int_array(dihedrallist,maxdihedral,5, "neighbor:dihedrallist"); } dihedrallist[ndihedrallist][0] = atom1; dihedrallist[ndihedrallist][1] = atom2; dihedrallist[ndihedrallist][2] = atom3; dihedrallist[ndihedrallist][3] = atom4; dihedrallist[ndihedrallist][4] = dihedral_type[i][m]; ndihedrallist++; } } } /* ---------------------------------------------------------------------- */ void Neighbor::dihedral_partial() { int i,m,atom1,atom2,atom3,atom4; int nlocal = atom->nlocal; int *num_dihedral = atom->num_dihedral; int **dihedral_atom1 = atom->dihedral_atom1; int **dihedral_atom2 = atom->dihedral_atom2; int **dihedral_atom3 = atom->dihedral_atom3; int **dihedral_atom4 = atom->dihedral_atom4; int **dihedral_type = atom->dihedral_type; int newton_bond = force->newton_bond; ndihedrallist = 0; for (i = 0; i < nlocal; i++) for (m = 0; m < num_dihedral[i]; m++) { if (dihedral_type[i][m] <= 0) continue; atom1 = atom->map(dihedral_atom1[i][m]); atom2 = atom->map(dihedral_atom2[i][m]); atom3 = atom->map(dihedral_atom3[i][m]); atom4 = atom->map(dihedral_atom4[i][m]); if (atom1 == -1 || atom2 == -1 || atom3 == -1 || atom4 == -1) { - char str[128]; - sprintf(str,"Dihedral atoms %d %d %d %d missing on proc %d at step %d", + char str[128],fstr[128]; + sprintf(fstr,"Dihedral atoms %%d %%d %%d %%d " + "missing on proc %%d at step %s",BIGINT_FORMAT); + sprintf(str,fstr, dihedral_atom1[i][m],dihedral_atom2[i][m], dihedral_atom3[i][m],dihedral_atom4[i][m], me,update->ntimestep); error->one(str); } if (newton_bond || (i <= atom1 && i <= atom2 && i <= atom3 && i <= atom4)) { if (ndihedrallist == maxdihedral) { maxdihedral += BONDDELTA; dihedrallist = memory->grow_2d_int_array(dihedrallist,maxdihedral,5, "neighbor:dihedrallist"); } dihedrallist[ndihedrallist][0] = atom1; dihedrallist[ndihedrallist][1] = atom2; dihedrallist[ndihedrallist][2] = atom3; dihedrallist[ndihedrallist][3] = atom4; dihedrallist[ndihedrallist][4] = dihedral_type[i][m]; ndihedrallist++; } } } /* ---------------------------------------------------------------------- */ void Neighbor::improper_all() { int i,m,atom1,atom2,atom3,atom4; int nlocal = atom->nlocal; int *num_improper = atom->num_improper; int **improper_atom1 = atom->improper_atom1; int **improper_atom2 = atom->improper_atom2; int **improper_atom3 = atom->improper_atom3; int **improper_atom4 = atom->improper_atom4; int **improper_type = atom->improper_type; int newton_bond = force->newton_bond; nimproperlist = 0; for (i = 0; i < nlocal; i++) for (m = 0; m < num_improper[i]; m++) { atom1 = atom->map(improper_atom1[i][m]); atom2 = atom->map(improper_atom2[i][m]); atom3 = atom->map(improper_atom3[i][m]); atom4 = atom->map(improper_atom4[i][m]); if (atom1 == -1 || atom2 == -1 || atom3 == -1 || atom4 == -1) { - char str[128]; - sprintf(str,"Improper atoms %d %d %d %d missing on proc %d at step %d", + char str[128],fstr[128]; + sprintf(fstr,"Improper atoms %%d %%d %%d %%d " + "missing on proc %%d at step %s",BIGINT_FORMAT); + sprintf(str,fstr, improper_atom1[i][m],improper_atom2[i][m], improper_atom3[i][m],improper_atom4[i][m], me,update->ntimestep); error->one(str); } if (newton_bond || (i <= atom1 && i <= atom2 && i <= atom3 && i <= atom4)) { if (nimproperlist == maximproper) { maximproper += BONDDELTA; improperlist = memory->grow_2d_int_array(improperlist,maximproper,5, "neighbor:improperlist"); } improperlist[nimproperlist][0] = atom1; improperlist[nimproperlist][1] = atom2; improperlist[nimproperlist][2] = atom3; improperlist[nimproperlist][3] = atom4; improperlist[nimproperlist][4] = improper_type[i][m]; nimproperlist++; } } } /* ---------------------------------------------------------------------- */ void Neighbor::improper_partial() { int i,m,atom1,atom2,atom3,atom4; int nlocal = atom->nlocal; int *num_improper = atom->num_improper; int **improper_atom1 = atom->improper_atom1; int **improper_atom2 = atom->improper_atom2; int **improper_atom3 = atom->improper_atom3; int **improper_atom4 = atom->improper_atom4; int **improper_type = atom->improper_type; int newton_bond = force->newton_bond; nimproperlist = 0; for (i = 0; i < nlocal; i++) for (m = 0; m < num_improper[i]; m++) { if (improper_type[i][m] <= 0) continue; atom1 = atom->map(improper_atom1[i][m]); atom2 = atom->map(improper_atom2[i][m]); atom3 = atom->map(improper_atom3[i][m]); atom4 = atom->map(improper_atom4[i][m]); if (atom1 == -1 || atom2 == -1 || atom3 == -1 || atom4 == -1) { - char str[128]; - sprintf(str,"Improper atoms %d %d %d %d missing on proc %d at step %d", + char str[128],fstr[128]; + sprintf(fstr,"Improper atoms %%d %%d %%d %%d " + "missing on proc %%d at step %s",BIGINT_FORMAT); + sprintf(str,fstr, improper_atom1[i][m],improper_atom2[i][m], improper_atom3[i][m],improper_atom4[i][m], me,update->ntimestep); error->one(str); } if (newton_bond || (i <= atom1 && i <= atom2 && i <= atom3 && i <= atom4)) { if (nimproperlist == maximproper) { maximproper += BONDDELTA; improperlist = memory->grow_2d_int_array(improperlist,maximproper,5, "neighbor:improperlist"); } improperlist[nimproperlist][0] = atom1; improperlist[nimproperlist][1] = atom2; improperlist[nimproperlist][2] = atom3; improperlist[nimproperlist][3] = atom4; improperlist[nimproperlist][4] = improper_type[i][m]; nimproperlist++; } } } diff --git a/src/output.cpp b/src/output.cpp index 720c02060..a9b701848 100644 --- a/src/output.cpp +++ b/src/output.cpp @@ -1,542 +1,546 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain 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 "stdio.h" #include "stdlib.h" #include "string.h" #include "output.h" #include "style_dump.h" #include "atom.h" #include "neighbor.h" #include "input.h" #include "variable.h" #include "comm.h" #include "update.h" #include "group.h" #include "domain.h" #include "thermo.h" #include "modify.h" #include "compute.h" #include "force.h" #include "dump.h" #include "write_restart.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; #define DELTA 1 #define MYMIN(a,b) ((a) < (b) ? (a) : (b)) #define MYMAX(a,b) ((a) > (b) ? (a) : (b)) /* ---------------------------------------------------------------------- initialize all output ------------------------------------------------------------------------- */ Output::Output(LAMMPS *lmp) : Pointers(lmp) { // create default computes for temp,pressure,pe char **newarg = new char*[4]; newarg[0] = (char *) "thermo_temp"; newarg[1] = (char *) "all"; newarg[2] = (char *) "temp"; modify->add_compute(3,newarg); newarg[0] = (char *) "thermo_press"; newarg[1] = (char *) "all"; newarg[2] = (char *) "pressure"; newarg[3] = (char *) "thermo_temp"; modify->add_compute(4,newarg); newarg[0] = (char *) "thermo_pe"; newarg[1] = (char *) "all"; newarg[2] = (char *) "pe"; modify->add_compute(3,newarg); delete [] newarg; // create default Thermo class newarg = new char*[1]; newarg[0] = (char *) "one"; thermo = new Thermo(lmp,1,newarg); delete [] newarg; thermo_every = 0; var_thermo = NULL; ndump = 0; max_dump = 0; every_dump = NULL; next_dump = NULL; last_dump = NULL; var_dump = NULL; ivar_dump = NULL; dump = NULL; restart = NULL; restart1 = restart2 = NULL; restart_every = 0; last_restart = -1; } /* ---------------------------------------------------------------------- free all memory ------------------------------------------------------------------------- */ Output::~Output() { if (thermo) delete thermo; delete [] var_thermo; memory->sfree(every_dump); memory->sfree(next_dump); memory->sfree(last_dump); for (int i = 0; i < ndump; i++) delete [] var_dump[i]; memory->sfree(var_dump); memory->sfree(ivar_dump); for (int i = 0; i < ndump; i++) delete dump[i]; memory->sfree(dump); delete restart; delete [] restart1; delete [] restart2; } /* ---------------------------------------------------------------------- */ void Output::init() { thermo->init(); if (thermo_every) delete [] var_thermo; else if (var_thermo) { ivar_thermo = input->variable->find(var_thermo); if (ivar_thermo < 0) error->all("Variable name for thermo every does not exist"); if (!input->variable->equalstyle(ivar_thermo)) error->all("Variable for thermo every is invalid style"); } for (int i = 0; i < ndump; i++) dump[i]->init(); for (int i = 0; i < ndump; i++) if (every_dump[i] == 0) { ivar_dump[i] = input->variable->find(var_dump[i]); if (ivar_dump[i] < 0) error->all("Variable name for dump every does not exist"); if (!input->variable->equalstyle(ivar_dump[i])) error->all("Variable for dump every is invalid style"); } } /* ---------------------------------------------------------------------- perform output for setup of run/min do dump first, so memory_usage will include dump allocation do thermo last, so will print after memory_usage ------------------------------------------------------------------------- */ void Output::setup(int flag) { - int ntimestep = update->ntimestep; + bigint ntimestep = update->ntimestep; // perform dump at start of run if current timestep is multiple of every // and last dump was not on this timestep // set next_dump to multiple of every // will not write on last step of run unless multiple of every // set next_dump_any to smallest next_dump // if no dumps, set next_dump_any to last+1 so will not influence next // wrap dumps that invoke computes with clear/add // if dump not written now, add_all on future step since clear/add is noop int writeflag; if (ndump && update->restrict_output == 0) { for (int idump = 0; idump < ndump; idump++) { if (dump[idump]->clearstep) modify->clearstep_compute(); writeflag = 0; if (every_dump[idump] && ntimestep % every_dump[idump] == 0 && last_dump[idump] != ntimestep) writeflag = 1; if (last_dump[idump] < 0 && dump[idump]->first_flag == 1) writeflag = 1; if (writeflag) { dump[idump]->write(); last_dump[idump] = ntimestep; } if (every_dump[idump]) next_dump[idump] = (ntimestep/every_dump[idump])*every_dump[idump] + every_dump[idump]; else { int nextdump = static_cast<int> (input->variable->compute_equal(ivar_dump[idump])); if (nextdump <= ntimestep) error->all("Dump every variable returned a bad timestep"); next_dump[idump] = nextdump; } if (dump[idump]->clearstep) { if (writeflag) modify->addstep_compute(next_dump[idump]); else modify->addstep_compute_all(next_dump[idump]); } if (idump) next_dump_any = MYMIN(next_dump_any,next_dump[idump]); else next_dump_any = next_dump[0]; } } else next_dump_any = update->laststep + 1; // do not write a restart file at start of run // set next_restart to multiple of every // will not write on last step of run unless multiple of every // if every = 0, set next_restart to last+1 so will not influence next if (restart_every && update->restrict_output == 0) next_restart = (ntimestep/restart_every)*restart_every + restart_every; else next_restart = update->laststep + 1; // print memory usage unless being called between multiple runs if (flag) memory_usage(); // always do thermo with header at start of run // set next_thermo to multiple of every or last step of run (if smaller) // if every = 0, set next_thermo to last step of run // thermo may invoke computes so wrap with clear/add modify->clearstep_compute(); thermo->header(); thermo->compute(0); last_thermo = ntimestep; if (thermo_every) { next_thermo = (ntimestep/thermo_every)*thermo_every + thermo_every; next_thermo = MYMIN(next_thermo,update->laststep); } else if (var_thermo) { next_thermo = static_cast<int> (input->variable->compute_equal(ivar_thermo)); if (next_thermo <= ntimestep) error->all("Thermo every variable returned a bad timestep"); } else next_thermo = update->laststep; modify->addstep_compute(next_thermo); // next = next timestep any output will be done next = MYMIN(next_dump_any,next_restart); next = MYMIN(next,next_thermo); } /* ---------------------------------------------------------------------- perform all output for this timestep only perform output if next matches current step and last doesn't do dump/restart before thermo so thermo CPU time will include them ------------------------------------------------------------------------- */ -void Output::write(int ntimestep) +void Output::write(bigint ntimestep) { // next_dump does not force output on last step of run // wrap dumps that invoke computes with clear/add if (next_dump_any == ntimestep) { for (int idump = 0; idump < ndump; idump++) { if (next_dump[idump] == ntimestep && last_dump[idump] != ntimestep) { if (dump[idump]->clearstep) modify->clearstep_compute(); dump[idump]->write(); last_dump[idump] = ntimestep; if (every_dump[idump]) next_dump[idump] += every_dump[idump]; else { int nextdump = static_cast<int> (input->variable->compute_equal(ivar_dump[idump])); if (nextdump <= ntimestep) error->all("Dump every variable returned a bad timestep"); next_dump[idump] = nextdump; } if (dump[idump]->clearstep) modify->addstep_compute(next_dump[idump]); } if (idump) next_dump_any = MYMIN(next_dump_any,next_dump[idump]); else next_dump_any = next_dump[0]; } } // next_restart does not force output on last step of run // for toggle = 0, replace "*" with current timestep in restart filename if (next_restart == ntimestep && last_restart != ntimestep) { if (restart_toggle == 0) { char *file = new char[strlen(restart1) + 16]; char *ptr = strchr(restart1,'*'); *ptr = '\0'; - sprintf(file,"%s%d%s",restart1,ntimestep,ptr+1); + char fstr[16]; + sprintf(fstr,"%%s%s%%s",BIGINT_FORMAT); + sprintf(file,fstr,restart1,ntimestep,ptr+1); *ptr = '*'; restart->write(file); delete [] file; } else if (restart_toggle == 1) { restart->write(restart1); restart_toggle = 2; } else if (restart_toggle == 2) { restart->write(restart2); restart_toggle = 1; } last_restart = ntimestep; next_restart += restart_every; } // insure next_thermo forces output on last step of run // thermo may invoke computes so wrap with clear/add if (next_thermo == ntimestep && last_thermo != ntimestep) { modify->clearstep_compute(); thermo->compute(1); last_thermo = ntimestep; if (thermo_every) next_thermo += thermo_every; else if (var_thermo) { next_thermo = static_cast<int> (input->variable->compute_equal(ivar_thermo)); if (next_thermo <= ntimestep) error->all("Thermo every variable returned a bad timestep"); } else next_thermo = update->laststep; next_thermo = MYMIN(next_thermo,update->laststep); modify->addstep_compute(next_thermo); } // next = next timestep any output will be done next = MYMIN(next_dump_any,next_restart); next = MYMIN(next,next_thermo); } /* ---------------------------------------------------------------------- force a snapshot to be written for all dumps ------------------------------------------------------------------------- */ -void Output::write_dump(int ntimestep) +void Output::write_dump(bigint ntimestep) { for (int idump = 0; idump < ndump; idump++) { dump[idump]->write(); last_dump[idump] = ntimestep; } } /* ---------------------------------------------------------------------- force a restart file to be written ------------------------------------------------------------------------- */ -void Output::write_restart(int ntimestep) +void Output::write_restart(bigint ntimestep) { if (restart_toggle == 0) { char *file = new char[strlen(restart1) + 16]; char *ptr = strchr(restart1,'*'); *ptr = '\0'; - sprintf(file,"%s%d%s",restart1,ntimestep,ptr+1); + char fstr[16]; + sprintf(fstr,"%%s%s%%s",BIGINT_FORMAT); + sprintf(file,fstr,restart1,ntimestep,ptr+1); *ptr = '*'; restart->write(file); delete [] file; } else if (restart_toggle == 1) { restart->write(restart1); restart_toggle = 2; } else if (restart_toggle == 2) { restart->write(restart2); restart_toggle = 1; } last_restart = ntimestep; } /* ---------------------------------------------------------------------- add a Dump to list of Dumps ------------------------------------------------------------------------- */ void Output::add_dump(int narg, char **arg) { if (narg < 5) error->all("Illegal dump command"); // error checks for (int idump = 0; idump < ndump; idump++) if (strcmp(arg[0],dump[idump]->id) == 0) error->all("Reuse of dump ID"); int igroup = group->find(arg[1]); if (igroup == -1) error->all("Could not find dump group ID"); if (atoi(arg[3]) <= 0) error->all("Invalid dump frequency"); // extend Dump list if necessary if (ndump == max_dump) { max_dump += DELTA; dump = (Dump **) memory->srealloc(dump,max_dump*sizeof(Dump *),"output:dump"); every_dump = (int *) memory->srealloc(every_dump,max_dump*sizeof(int),"output:every_dump"); - next_dump = (int *) - memory->srealloc(next_dump,max_dump*sizeof(int),"output:next_dump"); - last_dump = (int *) - memory->srealloc(last_dump,max_dump*sizeof(int),"output:last_dump"); + next_dump = (bigint *) + memory->srealloc(next_dump,max_dump*sizeof(bigint),"output:next_dump"); + last_dump = (bigint *) + memory->srealloc(last_dump,max_dump*sizeof(bigint),"output:last_dump"); var_dump = (char **) memory->srealloc(var_dump,max_dump*sizeof(char *),"output:var_dump"); ivar_dump = (int *) memory->srealloc(ivar_dump,max_dump*sizeof(int),"output:ivar_dump"); } // create the Dump if (0) return; // dummy line to enable else-if macro expansion #define DUMP_CLASS #define DumpStyle(key,Class) \ else if (strcmp(arg[2],#key) == 0) dump[ndump] = new Class(lmp,narg,arg); #include "style_dump.h" #undef DUMP_CLASS else error->all("Invalid dump style"); every_dump[ndump] = atoi(arg[3]); if (every_dump[ndump] <= 0) error->all("Illegal dump command"); last_dump[ndump] = -1; var_dump[ndump] = NULL; ndump++; } /* ---------------------------------------------------------------------- modify parameters of a Dump ------------------------------------------------------------------------- */ void Output::modify_dump(int narg, char **arg) { if (narg < 1) error->all("Illegal dump_modify command"); // find which dump it is int idump; for (idump = 0; idump < ndump; idump++) if (strcmp(arg[0],dump[idump]->id) == 0) break; if (idump == ndump) error->all("Cound not find dump_modify ID"); dump[idump]->modify_params(narg-1,&arg[1]); } /* ---------------------------------------------------------------------- delete a Dump from list of Dumps ------------------------------------------------------------------------- */ void Output::delete_dump(char *id) { // find which dump it is and delete it int idump; for (idump = 0; idump < ndump; idump++) if (strcmp(id,dump[idump]->id) == 0) break; if (idump == ndump) error->all("Could not find undump ID"); delete dump[idump]; delete [] var_dump[idump]; // move other dumps down in list one slot for (int i = idump+1; i < ndump; i++) { dump[i-1] = dump[i]; every_dump[i-1] = every_dump[i]; next_dump[i-1] = next_dump[i]; last_dump[i-1] = last_dump[i]; var_dump[i-1] = var_dump[i]; ivar_dump[i-1] = ivar_dump[i]; } ndump--; } /* ---------------------------------------------------------------------- new Thermo style ------------------------------------------------------------------------- */ void Output::create_thermo(int narg, char **arg) { if (narg < 1) error->all("Illegal thermo_style command"); // don't allow this so that dipole style can safely allocate inertia vector if (domain->box_exist == 0) error->all("Thermo_style command before simulation box is defined"); // warn if previous thermo had been modified via thermo_modify command if (thermo->modified && comm->me == 0) error->warning("New thermo_style command, " "previous thermo_modify settings will be lost"); // set thermo = NULL in case new Thermo throws an error delete thermo; thermo = NULL; thermo = new Thermo(lmp,narg,arg); } /* ---------------------------------------------------------------------- setup restart capability if only one filename and it contains no "*", then append ".*" ------------------------------------------------------------------------- */ void Output::create_restart(int narg, char **arg) { if (narg < 1) error->all("Illegal restart command"); if (restart) delete restart; delete [] restart1; delete [] restart2; restart = NULL; restart1 = restart2 = NULL; last_restart = -1; restart_every = atoi(arg[0]); if (restart_every == 0) { if (narg != 1) error->all("Illegal restart command"); return; } restart = new WriteRestart(lmp); int n = strlen(arg[1]) + 3; restart1 = new char[n]; strcpy(restart1,arg[1]); if (narg == 2) { restart_toggle = 0; restart2 = NULL; if (strchr(restart1,'*') == NULL) strcat(restart1,".*"); } else if (narg == 3) { restart_toggle = 1; n = strlen(arg[2]) + 1; restart2 = new char[n]; strcpy(restart2,arg[2]); } else error->all("Illegal restart command"); } /* ---------------------------------------------------------------------- sum and print memory usage is only memory on proc 0, not averaged across procs ------------------------------------------------------------------------- */ void Output::memory_usage() { double bytes = 0.0; bytes += atom->memory_usage(); bytes += neighbor->memory_usage(); bytes += comm->memory_usage(); bytes += update->memory_usage(); bytes += force->memory_usage(); bytes += modify->memory_usage(); for (int i = 0; i < ndump; i++) bytes += dump[i]->memory_usage(); double mbytes = bytes/1024.0/1024.0; if (comm->me == 0) { if (screen) fprintf(screen,"Memory usage per processor = %g Mbytes\n",mbytes); if (logfile) fprintf(logfile,"Memory usage per processor = %g Mbytes\n",mbytes); } } diff --git a/src/output.h b/src/output.h index 12668c2cf..9e0c72acb 100644 --- a/src/output.h +++ b/src/output.h @@ -1,70 +1,71 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain 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_OUTPUT_H #define LMP_OUTPUT_H #include "pointers.h" +#include "lmptype.h" namespace LAMMPS_NS { class Output : protected Pointers { public: - int next; // next timestep for any kind of output + bigint next; // next timestep for any kind of output - int next_thermo; // next timestep for thermo output + bigint next_thermo; // next timestep for thermo output int thermo_every; // thermo output every this many steps - int last_thermo; // last timestep thermo was output + bigint last_thermo; // last timestep thermo was output char *var_thermo; // variable name for thermo frequency int ivar_thermo; // variable index for thermo frequency class Thermo *thermo; // Thermodynamic computations int ndump; // # of Dumps defined int max_dump; // max size of Dump list - int next_dump_any; // next timestep for any Dump + bigint next_dump_any; // next timestep for any Dump int *every_dump; // output of each Dump every this many steps - int *next_dump; // next timestep to do each Dump - int *last_dump; // last timestep each a snapshot was output + bigint *next_dump; // next timestep to do each Dump + bigint *last_dump; // last timestep each snapshot was output char **var_dump; // variable name for dump frequency int *ivar_dump; // variable index for dump frequency class Dump **dump; // list of defined Dumps - int next_restart; // next timestep to write a restart file + bigint next_restart; // next timestep to write a restart file int restart_every; // write a restart file every this many steps - int last_restart; // last timestep a restart file was output + bigint last_restart; // last timestep a restart file was output int restart_toggle; // 0 if use restart1 as prefix // 1 if use restart1 as file, 2 for restart2 char *restart1,*restart2; // names for restart files class WriteRestart *restart; // Restart output Output(class LAMMPS *); ~Output(); void init(); void setup(int); // initial output before run/min - void write(int); // output for current timestep - void write_dump(int); // force output of dump snapshots - void write_restart(int); // force output of a restart file + void write(bigint); // output for current timestep + void write_dump(bigint); // force output of dump snapshots + void write_restart(bigint); // force output of a restart file void add_dump(int, char **); // add a Dump to Dump list void modify_dump(int, char **); // modify a Dump void delete_dump(char *); // delete a Dump from Dump list void create_thermo(int, char **); // create a thermo style void create_restart(int, char **); // create Restart and restart files void memory_usage(); // print out memory usage }; } #endif diff --git a/src/read_data.cpp b/src/read_data.cpp index f8229bdfd..b38f22869 100644 --- a/src/read_data.cpp +++ b/src/read_data.cpp @@ -1,1364 +1,1390 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ #include "math.h" #include "mpi.h" #include "string.h" #include "stdlib.h" #include "read_data.h" #include "lmptype.h" #include "atom.h" #include "atom_vec.h" #include "comm.h" #include "update.h" #include "force.h" #include "pair.h" #include "domain.h" #include "bond.h" #include "angle.h" #include "dihedral.h" #include "improper.h" #include "error.h" #include "memory.h" #include "special.h" using namespace LAMMPS_NS; #define MAXLINE 256 #define LB_FACTOR 1.1 #define CHUNK 1024 #define DELTA 4 // must be 2 or larger #define NSECTIONS 22 // change when add to header::section_keywords #define MIN(a,b) ((a) < (b) ? (a) : (b)) #define MAX(a,b) ((a) > (b) ? (a) : (b)) /* ---------------------------------------------------------------------- */ ReadData::ReadData(LAMMPS *lmp) : Pointers(lmp) { MPI_Comm_rank(world,&me); line = new char[MAXLINE]; keyword = new char[MAXLINE]; buffer = new char[CHUNK*MAXLINE]; narg = maxarg = 0; arg = NULL; } /* ---------------------------------------------------------------------- */ ReadData::~ReadData() { delete [] line; delete [] keyword; delete [] buffer; memory->sfree(arg); } /* ---------------------------------------------------------------------- */ void ReadData::command(int narg, char **arg) { if (narg != 1) error->all("Illegal read_data command"); if (domain->box_exist) error->all("Cannot read_data after simulation box is defined"); if (domain->dimension == 2 && domain->zperiodic == 0) error->all("Cannot run 2d simulation with nonperiodic Z dimension"); // scan data file to determine max topology needed per atom // allocate initial topology arrays if (atom->molecular) { if (me == 0) { if (screen) fprintf(screen,"Scanning data file ...\n"); open(arg[0]); header(0); scan(atom->bond_per_atom,atom->angle_per_atom, atom->dihedral_per_atom,atom->improper_per_atom); if (compressed) pclose(fp); else fclose(fp); atom->bond_per_atom += atom->extra_bond_per_atom; } MPI_Bcast(&atom->bond_per_atom,1,MPI_INT,0,world); MPI_Bcast(&atom->angle_per_atom,1,MPI_INT,0,world); MPI_Bcast(&atom->dihedral_per_atom,1,MPI_INT,0,world); MPI_Bcast(&atom->improper_per_atom,1,MPI_INT,0,world); } else atom->bond_per_atom = atom->angle_per_atom = atom->dihedral_per_atom = atom->improper_per_atom = 0; // read header info if (me == 0) { if (screen) fprintf(screen,"Reading data file ...\n"); open(arg[0]); } header(1); domain->box_exist = 1; // problem setup using info from header update->ntimestep = 0; int n; if (comm->nprocs == 1) n = static_cast<int> (atom->natoms); else n = static_cast<int> (LB_FACTOR * atom->natoms / comm->nprocs); atom->allocate_type_arrays(); atom->avec->grow(n); n = atom->nmax; domain->print_box(" "); domain->set_initial_box(); domain->set_global_box(); comm->set_procs(); domain->set_local_box(); // read rest of file in free format // if add a section keyword, add to header::section_keywords and NSECTIONS int atomflag = 0; while (strlen(keyword)) { if (strcmp(keyword,"Atoms") == 0) { atoms(); atomflag = 1; } else if (strcmp(keyword,"Velocities") == 0) { if (atomflag == 0) error->all("Must read Atoms before Velocities"); velocities(); } else if (strcmp(keyword,"Bonds") == 0) { if (atom->avec->bonds_allow == 0) error->all("Invalid data file section: Bonds"); if (atomflag == 0) error->all("Must read Atoms before Bonds"); bonds(); } else if (strcmp(keyword,"Angles") == 0) { if (atom->avec->angles_allow == 0) error->all("Invalid data file section: Angles"); if (atomflag == 0) error->all("Must read Atoms before Angles"); angles(); } else if (strcmp(keyword,"Dihedrals") == 0) { if (atom->avec->dihedrals_allow == 0) error->all("Invalid data file section: Dihedrals"); if (atomflag == 0) error->all("Must read Atoms before Dihedrals"); dihedrals(); } else if (strcmp(keyword,"Impropers") == 0) { if (atom->avec->impropers_allow == 0) error->all("Invalid data file section: Impropers"); if (atomflag == 0) error->all("Must read Atoms before Impropers"); impropers(); } else if (strcmp(keyword,"Masses") == 0) { mass(); } else if (strcmp(keyword,"Shapes") == 0) { shape(); } else if (strcmp(keyword,"Dipoles") == 0) { dipole(); } else if (strcmp(keyword,"Pair Coeffs") == 0) { if (force->pair == NULL) error->all("Must define pair_style before Pair Coeffs"); paircoeffs(); } else if (strcmp(keyword,"Bond Coeffs") == 0) { if (atom->avec->bonds_allow == 0) error->all("Invalid data file section: Bond Coeffs"); if (force->bond == NULL) error->all("Must define bond_style before Bond Coeffs"); bondcoeffs(); } else if (strcmp(keyword,"Angle Coeffs") == 0) { if (atom->avec->angles_allow == 0) error->all("Invalid data file section: Angle Coeffs"); if (force->angle == NULL) error->all("Must define angle_style before Angle Coeffs"); anglecoeffs(0); } else if (strcmp(keyword,"Dihedral Coeffs") == 0) { if (atom->avec->dihedrals_allow == 0) error->all("Invalid data file section: Dihedral Coeffs"); if (force->dihedral == NULL) error->all("Must define dihedral_style before Dihedral Coeffs"); dihedralcoeffs(0); } else if (strcmp(keyword,"Improper Coeffs") == 0) { if (atom->avec->impropers_allow == 0) error->all("Invalid data file section: Improper Coeffs"); if (force->improper == NULL) error->all("Must define improper_style before Improper Coeffs"); impropercoeffs(0); } else if (strcmp(keyword,"BondBond Coeffs") == 0) { if (atom->avec->angles_allow == 0) error->all("Invalid data file section: BondBond Coeffs"); if (force->angle == NULL) error->all("Must define angle_style before BondBond Coeffs"); anglecoeffs(1); } else if (strcmp(keyword,"BondAngle Coeffs") == 0) { if (atom->avec->angles_allow == 0) error->all("Invalid data file section: BondAngle Coeffs"); if (force->angle == NULL) error->all("Must define angle_style before BondAngle Coeffs"); anglecoeffs(2); } else if (strcmp(keyword,"MiddleBondTorsion Coeffs") == 0) { if (atom->avec->dihedrals_allow == 0) error->all("Invalid data file section: MiddleBondTorsion Coeffs"); if (force->dihedral == NULL) error->all("Must define dihedral_style before MiddleBondTorsion Coeffs"); dihedralcoeffs(1); } else if (strcmp(keyword,"EndBondTorsion Coeffs") == 0) { if (atom->avec->dihedrals_allow == 0) error->all("Invalid data file section: EndBondTorsion Coeffs"); if (force->dihedral == NULL) error->all("Must define dihedral_style before EndBondTorsion Coeffs"); dihedralcoeffs(2); } else if (strcmp(keyword,"AngleTorsion Coeffs") == 0) { if (atom->avec->dihedrals_allow == 0) error->all("Invalid data file section: AngleTorsion Coeffs"); if (force->dihedral == NULL) error->all("Must define dihedral_style before AngleTorsion Coeffs"); dihedralcoeffs(3); } else if (strcmp(keyword,"AngleAngleTorsion Coeffs") == 0) { if (atom->avec->dihedrals_allow == 0) error->all("Invalid data file section: AngleAngleTorsion Coeffs"); if (force->dihedral == NULL) error->all("Must define dihedral_style before AngleAngleTorsion Coeffs"); dihedralcoeffs(4); } else if (strcmp(keyword,"BondBond13 Coeffs") == 0) { if (atom->avec->dihedrals_allow == 0) error->all("Invalid data file section: BondBond13 Coeffs"); if (force->dihedral == NULL) error->all("Must define dihedral_style before BondBond13 Coeffs"); dihedralcoeffs(5); } else if (strcmp(keyword,"AngleAngle Coeffs") == 0) { if (atom->avec->impropers_allow == 0) error->all("Invalid data file section: AngleAngle Coeffs"); if (force->improper == NULL) error->all("Must define improper_style before AngleAngle Coeffs"); impropercoeffs(1); } else { char str[128]; sprintf(str,"Unknown identifier in data file: %s",keyword); error->all(str); } parse_keyword(0,1); } // close file if (me == 0) { if (compressed) pclose(fp); else fclose(fp); } // error if natoms > 0 yet no atoms were read if (atom->natoms > 0 && atomflag == 0) error->all("No atoms in data file"); // create bond topology now that system is defined if (atom->molecular) { Special special(lmp); special.build(); } } /* ---------------------------------------------------------------------- read free-format header of data file if flag = 0, only called by proc 0 if flag = 1, called by all procs so bcast lines as read them 1st line and blank lines are skipped non-blank lines are checked for header keywords and leading value is read header ends with EOF or non-blank line containing no header keyword if EOF, line is set to blank line else line has first keyword line for rest of file ------------------------------------------------------------------------- */ void ReadData::header(int flag) { int n; char *ptr; char *section_keywords[NSECTIONS] = {"Atoms","Velocities","Bonds","Angles","Dihedrals","Impropers", "Masses","Shapes","Dipoles", "Pair Coeffs","Bond Coeffs","Angle Coeffs", "Dihedral Coeffs","Improper Coeffs", "BondBond Coeffs","BondAngle Coeffs","MiddleBondTorsion Coeffs", "EndBondTorsion Coeffs","AngleTorsion Coeffs", "AngleAngleTorsion Coeffs","BondBond13 Coeffs","AngleAngle Coeffs"}; // skip 1st line of file if (me == 0) { char *eof = fgets(line,MAXLINE,fp); if (eof == NULL) error->one("Unexpected end of data file"); } while (1) { // read a line and bcast length if flag is set if (me == 0) { if (fgets(line,MAXLINE,fp) == NULL) n = 0; else n = strlen(line) + 1; } if (flag) MPI_Bcast(&n,1,MPI_INT,0,world); // if n = 0 then end-of-file so return with blank line if (n == 0) { line[0] = '\0'; return; } // bcast line if flag is set if (flag) MPI_Bcast(line,n,MPI_CHAR,0,world); // trim anything from '#' onward // if line is blank, continue if (ptr = strchr(line,'#')) *ptr = '\0'; if (strspn(line," \t\n\r") == strlen(line)) continue; // search line for header keyword and set corresponding variable - if (strstr(line,"atoms")) sscanf(line,"%lu",&atom->natoms); - else if (strstr(line,"bonds")) sscanf(line,"%lu",&atom->nbonds); - else if (strstr(line,"angles")) sscanf(line,"%lu",&atom->nangles); - else if (strstr(line,"dihedrals")) sscanf(line,"%lu",&atom->ndihedrals); - else if (strstr(line,"impropers")) sscanf(line,"%lu",&atom->nimpropers); + if (strstr(line,"atoms")) sscanf(line,BIGINT_FORMAT,&atom->natoms); + + else if (strstr(line,"bonds")) sscanf(line,BIGINT_FORMAT,&atom->nbonds); + else if (strstr(line,"angles")) sscanf(line,BIGINT_FORMAT,&atom->nangles); + else if (strstr(line,"dihedrals")) sscanf(line,BIGINT_FORMAT, + &atom->ndihedrals); + else if (strstr(line,"impropers")) sscanf(line,BIGINT_FORMAT, + &atom->nimpropers); else if (strstr(line,"atom types")) sscanf(line,"%d",&atom->ntypes); else if (strstr(line,"bond types")) sscanf(line,"%d",&atom->nbondtypes); else if (strstr(line,"angle types")) sscanf(line,"%d",&atom->nangletypes); else if (strstr(line,"dihedral types")) sscanf(line,"%d",&atom->ndihedraltypes); else if (strstr(line,"improper types")) sscanf(line,"%d",&atom->nimpropertypes); else if (strstr(line,"extra bond per atom")) sscanf(line,"%d",&atom->extra_bond_per_atom); else if (strstr(line,"xlo xhi")) sscanf(line,"%lg %lg",&domain->boxlo[0],&domain->boxhi[0]); else if (strstr(line,"ylo yhi")) sscanf(line,"%lg %lg",&domain->boxlo[1],&domain->boxhi[1]); else if (strstr(line,"zlo zhi")) sscanf(line,"%lg %lg",&domain->boxlo[2],&domain->boxhi[2]); else if (strstr(line,"xy xz yz")) { domain->triclinic = 1; sscanf(line,"%lg %lg %lg",&domain->xy,&domain->xz,&domain->yz); } else break; } + // error check on total system size + + if (atom->natoms < 0 || atom->natoms > MAXBIGINT || + atom->nbonds < 0 || atom->nbonds > MAXBIGINT || + atom->nangles < 0 || atom->nangles > MAXBIGINT || + atom->ndihedrals < 0 || atom->ndihedrals > MAXBIGINT || + atom->nimpropers < 0 || atom->nimpropers > MAXBIGINT) { + if (flag == 0) error->one("System in data file is too big"); + else error->all("System in data file is too big"); + } + // check that exiting string is a valid section keyword parse_keyword(1,flag); for (n = 0; n < NSECTIONS; n++) if (strcmp(keyword,section_keywords[n]) == 0) break; if (n == NSECTIONS) { char str[128]; sprintf(str,"Unknown identifier in data file: %s",keyword); error->all(str); } // error check on consistency of header values if ((atom->nbonds || atom->nbondtypes) && atom->avec->bonds_allow == 0) error->one("No bonds allowed with this atom style"); if ((atom->nangles || atom->nangletypes) && atom->avec->angles_allow == 0) error->one("No angles allowed with this atom style"); if ((atom->ndihedrals || atom->ndihedraltypes) && atom->avec->dihedrals_allow == 0) error->one("No dihedrals allowed with this atom style"); if ((atom->nimpropers || atom->nimpropertypes) && atom->avec->impropers_allow == 0) error->one("No impropers allowed with this atom style"); if (atom->nbonds > 0 && atom->nbondtypes <= 0) error->one("Bonds defined but no bond types"); if (atom->nangles > 0 && atom->nangletypes <= 0) error->one("Angles defined but no angle types"); if (atom->ndihedrals > 0 && atom->ndihedraltypes <= 0) error->one("Dihedrals defined but no dihedral types"); if (atom->nimpropers > 0 && atom->nimpropertypes <= 0) error->one("Impropers defined but no improper types"); } /* ---------------------------------------------------------------------- read all atoms ------------------------------------------------------------------------- */ void ReadData::atoms() { int i,m,nchunk; bigint nread = 0; bigint natoms = atom->natoms; while (nread < natoms) { if (natoms-nread > CHUNK) nchunk = CHUNK; else nchunk = natoms-nread; if (me == 0) { char *eof; m = 0; for (i = 0; i < nchunk; i++) { eof = fgets(&buffer[m],MAXLINE,fp); if (eof == NULL) error->one("Unexpected end of data file"); m += strlen(&buffer[m]); } buffer[m++] = '\n'; } MPI_Bcast(&m,1,MPI_INT,0,world); MPI_Bcast(buffer,m,MPI_CHAR,0,world); atom->data_atoms(nchunk,buffer); nread += nchunk; } // check that all atoms were assigned correctly bigint tmp = atom->nlocal; - MPI_Allreduce(&tmp,&natoms,1,MPI_UNSIGNED_LONG_LONG,MPI_SUM,world); + MPI_Allreduce(&tmp,&natoms,1,MPI_LMP_BIGINT,MPI_SUM,world); if (me == 0) { - if (screen) fprintf(screen," %lu atoms\n",natoms); - if (logfile) fprintf(logfile," %lu atoms\n",natoms); + char str[32]; + sprintf(str," %s atoms\n",BIGINT_FORMAT); + if (screen) fprintf(screen,str,natoms); + if (logfile) fprintf(logfile,str,natoms); } if (natoms != atom->natoms) error->all("Did not assign all atoms correctly"); // if any atom ID < 0, error // if all atom IDs = 0, tag_enable = 0 // if any atom ID > 0, error if any atom ID == 0 // not checking if atom IDs > natoms or are unique int nlocal = atom->nlocal; int *tag = atom->tag; int flag = 0; for (int i = 0; i < nlocal; i++) if (tag[i] < 0) flag = 1; int flag_all; MPI_Allreduce(&flag,&flag_all,1,MPI_INT,MPI_SUM,world); if (flag_all) error->all("Invalid atom ID in Atoms section of data file"); flag = 0; for (int i = 0; i < nlocal; i++) if (tag[i] > 0) flag = 1; MPI_Allreduce(&flag,&flag_all,1,MPI_INT,MPI_MAX,world); if (flag_all == 0) atom->tag_enable = 0; if (atom->tag_enable) { flag = 0; for (int i = 0; i < nlocal; i++) if (tag[i] == 0) flag = 1; MPI_Allreduce(&flag,&flag_all,1,MPI_INT,MPI_SUM,world); if (flag_all) error->all("Invalid atom ID in Atoms section of data file"); } // create global mapping if (atom->map_style) { atom->map_init(); atom->map_set(); } } /* ---------------------------------------------------------------------- read all velocities to find atoms, must build atom map if not a molecular system ------------------------------------------------------------------------- */ void ReadData::velocities() { int i,m,nchunk; int mapflag = 0; if (atom->map_style == 0) { mapflag = 1; atom->map_style = 1; atom->map_init(); atom->map_set(); } bigint nread = 0; bigint natoms = atom->natoms; while (nread < natoms) { if (natoms-nread > CHUNK) nchunk = CHUNK; else nchunk = natoms-nread; if (me == 0) { char *eof; m = 0; for (i = 0; i < nchunk; i++) { eof = fgets(&buffer[m],MAXLINE,fp); if (eof == NULL) error->one("Unexpected end of data file"); m += strlen(&buffer[m]); } buffer[m++] = '\n'; } MPI_Bcast(&m,1,MPI_INT,0,world); MPI_Bcast(buffer,m,MPI_CHAR,0,world); atom->data_vels(nchunk,buffer); nread += nchunk; } if (mapflag) { atom->map_delete(); atom->map_style = 0; } if (me == 0) { - if (screen) fprintf(screen," %lu velocities\n",natoms); - if (logfile) fprintf(logfile," %lu velocities\n",natoms); + char str[32]; + sprintf(str," %s velocities\n",BIGINT_FORMAT); + if (screen) fprintf(screen,str,natoms); + if (logfile) fprintf(logfile,str,natoms); } } /* ---------------------------------------------------------------------- */ void ReadData::bonds() { int i,m,nchunk; bigint nread = 0; bigint nbonds = atom->nbonds; while (nread < nbonds) { nchunk = MIN(nbonds-nread,CHUNK); if (me == 0) { char *eof; m = 0; for (i = 0; i < nchunk; i++) { eof = fgets(&buffer[m],MAXLINE,fp); if (eof == NULL) error->one("Unexpected end of data file"); m += strlen(&buffer[m]); } buffer[m++] = '\n'; } MPI_Bcast(&m,1,MPI_INT,0,world); MPI_Bcast(buffer,m,MPI_CHAR,0,world); atom->data_bonds(nchunk,buffer); nread += nchunk; } // check that bonds were assigned correctly int nlocal = atom->nlocal; bigint sum; bigint n = 0; for (i = 0; i < nlocal; i++) n += atom->num_bond[i]; - MPI_Allreduce(&n,&sum,1,MPI_UNSIGNED_LONG_LONG,MPI_SUM,world); + MPI_Allreduce(&n,&sum,1,MPI_LMP_BIGINT,MPI_SUM,world); int factor = 1; if (!force->newton_bond) factor = 2; if (me == 0) { - if (screen) fprintf(screen," %lu bonds\n",sum/factor); - if (logfile) fprintf(logfile," %lu bonds\n",sum/factor); + char str[32]; + sprintf(str," %s bonds\n",BIGINT_FORMAT); + if (screen) fprintf(screen,str,sum/factor); + if (logfile) fprintf(logfile,str,sum/factor); } if (sum != factor*atom->nbonds) error->all("Bonds assigned incorrectly"); } /* ---------------------------------------------------------------------- */ void ReadData::angles() { int i,m,nchunk; bigint nread = 0; bigint nangles = atom->nangles; while (nread < nangles) { nchunk = MIN(nangles-nread,CHUNK); if (me == 0) { char *eof; m = 0; for (i = 0; i < nchunk; i++) { eof = fgets(&buffer[m],MAXLINE,fp); if (eof == NULL) error->one("Unexpected end of data file"); m += strlen(&buffer[m]); } buffer[m++] = '\n'; } MPI_Bcast(&m,1,MPI_INT,0,world); MPI_Bcast(buffer,m,MPI_CHAR,0,world); atom->data_angles(nchunk,buffer); nread += nchunk; } // check that ang int nlocal = atom->nlocal; bigint sum; bigint n = 0; for (i = 0; i < nlocal; i++) n += atom->num_angle[i]; - MPI_Allreduce(&n,&sum,1,MPI_UNSIGNED_LONG_LONG,MPI_SUM,world); + MPI_Allreduce(&n,&sum,1,MPI_LMP_BIGINT,MPI_SUM,world); int factor = 1; if (!force->newton_bond) factor = 3; if (me == 0) { - if (screen) fprintf(screen," %lu angles\n",sum/factor); - if (logfile) fprintf(logfile," %lu angles\n",sum/factor); + char str[32]; + sprintf(str," %s angles\n",BIGINT_FORMAT); + if (screen) fprintf(screen,str,sum/factor); + if (logfile) fprintf(logfile,str,sum/factor); } if (sum != factor*atom->nangles) error->all("Angles assigned incorrectly"); } /* ---------------------------------------------------------------------- */ void ReadData::dihedrals() { int i,m,nchunk; bigint nread = 0; bigint ndihedrals = atom->ndihedrals; while (nread < ndihedrals) { nchunk = MIN(ndihedrals-nread,CHUNK); if (me == 0) { char *eof; m = 0; for (i = 0; i < nchunk; i++) { eof = fgets(&buffer[m],MAXLINE,fp); if (eof == NULL) error->one("Unexpected end of data file"); m += strlen(&buffer[m]); } buffer[m++] = '\n'; } MPI_Bcast(&m,1,MPI_INT,0,world); MPI_Bcast(buffer,m,MPI_CHAR,0,world); atom->data_dihedrals(nchunk,buffer); nread += nchunk; } // check that dihedrals were assigned correctly int nlocal = atom->nlocal; bigint sum; bigint n = 0; for (i = 0; i < nlocal; i++) n += atom->num_dihedral[i]; - MPI_Allreduce(&n,&sum,1,MPI_UNSIGNED_LONG_LONG,MPI_SUM,world); + MPI_Allreduce(&n,&sum,1,MPI_LMP_BIGINT,MPI_SUM,world); int factor = 1; if (!force->newton_bond) factor = 4; if (me == 0) { - if (screen) fprintf(screen," %lu dihedrals\n",sum/factor); - if (logfile) fprintf(logfile," %lu dihedrals\n",sum/factor); + char str[32]; + sprintf(str," %s dihedrals\n",BIGINT_FORMAT); + if (screen) fprintf(screen,str,sum/factor); + if (logfile) fprintf(logfile,str,sum/factor); } if (sum != factor*atom->ndihedrals) error->all("Dihedrals assigned incorrectly"); } /* ---------------------------------------------------------------------- */ void ReadData::impropers() { int i,m,nchunk; bigint nread = 0; bigint nimpropers = atom->nimpropers; while (nread < nimpropers) { nchunk = MIN(nimpropers-nread,CHUNK); if (me == 0) { char *eof; m = 0; for (i = 0; i < nchunk; i++) { eof = fgets(&buffer[m],MAXLINE,fp); if (eof == NULL) error->one("Unexpected end of data file"); m += strlen(&buffer[m]); } buffer[m++] = '\n'; } MPI_Bcast(&m,1,MPI_INT,0,world); MPI_Bcast(buffer,m,MPI_CHAR,0,world); atom->data_impropers(nchunk,buffer); nread += nchunk; } // check that impropers were assigned correctly int nlocal = atom->nlocal; bigint sum; bigint n = 0; for (i = 0; i < nlocal; i++) n += atom->num_improper[i]; - MPI_Allreduce(&n,&sum,1,MPI_UNSIGNED_LONG_LONG,MPI_SUM,world); + MPI_Allreduce(&n,&sum,1,MPI_LMP_BIGINT,MPI_SUM,world); int factor = 1; if (!force->newton_bond) factor = 4; if (me == 0) { - if (screen) fprintf(screen," %lu impropers\n",sum/factor); - if (logfile) fprintf(logfile," %lu impropers\n",sum/factor); + char str[32]; + sprintf(str," %s impropers\n",BIGINT_FORMAT); + if (screen) fprintf(screen,str,sum/factor); + if (logfile) fprintf(logfile,str,sum/factor); } if (sum != factor*atom->nimpropers) error->all("Impropers assigned incorrectly"); } /* ---------------------------------------------------------------------- */ void ReadData::mass() { int i,m; char *buf = new char[atom->ntypes*MAXLINE]; char *original = buf; if (me == 0) { char *eof; m = 0; for (i = 0; i < atom->ntypes; i++) { eof = fgets(&buf[m],MAXLINE,fp); if (eof == NULL) error->one("Unexpected end of data file"); m += strlen(&buf[m]); buf[m-1] = '\0'; } } MPI_Bcast(&m,1,MPI_INT,0,world); MPI_Bcast(buf,m,MPI_CHAR,0,world); for (i = 0; i < atom->ntypes; i++) { atom->set_mass(buf); buf += strlen(buf) + 1; } delete [] original; } /* ---------------------------------------------------------------------- */ void ReadData::shape() { int i,m; char *buf = new char[atom->ntypes*MAXLINE]; char *original = buf; if (me == 0) { char *eof; m = 0; for (i = 0; i < atom->ntypes; i++) { eof = fgets(&buf[m],MAXLINE,fp); if (eof == NULL) error->one("Unexpected end of data file"); m += strlen(&buf[m]); buf[m-1] = '\0'; } } MPI_Bcast(&m,1,MPI_INT,0,world); MPI_Bcast(buf,m,MPI_CHAR,0,world); for (i = 0; i < atom->ntypes; i++) { atom->set_shape(buf); buf += strlen(buf) + 1; } delete [] original; } /* ---------------------------------------------------------------------- */ void ReadData::dipole() { int i,m; char *buf = new char[atom->ntypes*MAXLINE]; char *original = buf; if (me == 0) { char *eof; m = 0; for (i = 0; i < atom->ntypes; i++) { eof = fgets(&buf[m],MAXLINE,fp); if (eof == NULL) error->one("Unexpected end of data file"); m += strlen(&buf[m]); buf[m-1] = '\0'; } } MPI_Bcast(&m,1,MPI_INT,0,world); MPI_Bcast(buf,m,MPI_CHAR,0,world); for (i = 0; i < atom->ntypes; i++) { atom->set_dipole(buf); buf += strlen(buf) + 1; } delete [] original; } /* ---------------------------------------------------------------------- */ void ReadData::paircoeffs() { int i,m; char *buf = new char[atom->ntypes*MAXLINE]; char *original = buf; if (me == 0) { char *eof; m = 0; for (i = 0; i < atom->ntypes; i++) { eof = fgets(&buf[m],MAXLINE,fp); if (eof == NULL) error->one("Unexpected end of data file"); m += strlen(&buf[m]); buf[m-1] = '\0'; } } MPI_Bcast(&m,1,MPI_INT,0,world); MPI_Bcast(buf,m,MPI_CHAR,0,world); for (i = 0; i < atom->ntypes; i++) { m = strlen(buf) + 1; parse_coeffs(buf,NULL,1); force->pair->coeff(narg,arg); buf += m; } delete [] original; } /* ---------------------------------------------------------------------- */ void ReadData::bondcoeffs() { int i,m; char *buf = new char[atom->nbondtypes*MAXLINE]; char *original = buf; if (me == 0) { char *eof; m = 0; for (i = 0; i < atom->nbondtypes; i++) { eof = fgets(&buf[m],MAXLINE,fp); if (eof == NULL) error->one("Unexpected end of data file"); m += strlen(&buf[m]); buf[m-1] = '\0'; } } MPI_Bcast(&m,1,MPI_INT,0,world); MPI_Bcast(buf,m,MPI_CHAR,0,world); for (i = 0; i < atom->nbondtypes; i++) { m = strlen(buf) + 1; parse_coeffs(buf,NULL,0); force->bond->coeff(narg,arg); buf += m; } delete [] original; } /* ---------------------------------------------------------------------- */ void ReadData::anglecoeffs(int which) { int i,m; char *buf = new char[atom->nangletypes*MAXLINE]; char *original = buf; if (me == 0) { char *eof; m = 0; for (i = 0; i < atom->nangletypes; i++) { eof = fgets(&buf[m],MAXLINE,fp); if (eof == NULL) error->one("Unexpected end of data file"); m += strlen(&buf[m]); buf[m-1] = '\0'; } } MPI_Bcast(&m,1,MPI_INT,0,world); MPI_Bcast(buf,m,MPI_CHAR,0,world); for (i = 0; i < atom->nangletypes; i++) { m = strlen(buf) + 1; if (which == 0) parse_coeffs(buf,NULL,0); else if (which == 1) parse_coeffs(buf,"bb",0); else if (which == 2) parse_coeffs(buf,"ba",0); force->angle->coeff(narg,arg); buf += m; } delete [] original; } /* ---------------------------------------------------------------------- */ void ReadData::dihedralcoeffs(int which) { int i,m; char *buf = new char[atom->ndihedraltypes*MAXLINE]; char *original = buf; if (me == 0) { char *eof; m = 0; for (i = 0; i < atom->ndihedraltypes; i++) { eof = fgets(&buf[m],MAXLINE,fp); if (eof == NULL) error->one("Unexpected end of data file"); m += strlen(&buf[m]); buf[m-1] = '\0'; } } MPI_Bcast(&m,1,MPI_INT,0,world); MPI_Bcast(buf,m,MPI_CHAR,0,world); for (i = 0; i < atom->ndihedraltypes; i++) { m = strlen(buf) + 1; if (which == 0) parse_coeffs(buf,NULL,0); else if (which == 1) parse_coeffs(buf,"mbt",0); else if (which == 2) parse_coeffs(buf,"ebt",0); else if (which == 3) parse_coeffs(buf,"at",0); else if (which == 4) parse_coeffs(buf,"aat",0); else if (which == 5) parse_coeffs(buf,"bb13",0); force->dihedral->coeff(narg,arg); buf += m; } delete [] original; } /* ---------------------------------------------------------------------- */ void ReadData::impropercoeffs(int which) { int i,m; char *buf = new char[atom->nimpropertypes*MAXLINE]; char *original = buf; if (me == 0) { char *eof; m = 0; for (i = 0; i < atom->nimpropertypes; i++) { eof = fgets(&buf[m],MAXLINE,fp); if (eof == NULL) error->one("Unexpected end of data file"); m += strlen(&buf[m]); buf[m-1] = '\0'; } } MPI_Bcast(&m,1,MPI_INT,0,world); MPI_Bcast(buf,m,MPI_CHAR,0,world); for (i = 0; i < atom->nimpropertypes; i++) { m = strlen(buf) + 1; if (which == 0) parse_coeffs(buf,NULL,0); else if (which == 1) parse_coeffs(buf,"aa",0); force->improper->coeff(narg,arg); buf += m; } delete [] original; } /* ---------------------------------------------------------------------- proc 0 scans the data file for topology maximums ------------------------------------------------------------------------- */ void ReadData::scan(int &bond_per_atom, int &angle_per_atom, int &dihedral_per_atom, int &improper_per_atom) { int i,tmp1,tmp2,atom1,atom2,atom3,atom4; char *eof; - if (atom->natoms > MAXINT32) + if (atom->natoms > MAXSMALLINT) error->all("Molecular data file has too many atoms"); int natoms = static_cast<int> (atom->natoms); bond_per_atom = angle_per_atom = dihedral_per_atom = improper_per_atom = 0; // allocate topology counting vector // initially, array length = 1 to natoms // will grow via reallocate() if atom IDs > natoms int cmax = natoms + 1; int *count = (int *) memory->smalloc(cmax*sizeof(int),"read_data:count"); while (strlen(keyword)) { if (strcmp(keyword,"Masses") == 0) skip_lines(atom->ntypes); else if (strcmp(keyword,"Dipoles") == 0) skip_lines(atom->ntypes); else if (strcmp(keyword,"Atoms") == 0) skip_lines(natoms); else if (strcmp(keyword,"Velocities") == 0) skip_lines(natoms); else if (strcmp(keyword,"Pair Coeffs") == 0) { if (force->pair == NULL) error->all("Must define pair_style before Pair Coeffs"); skip_lines(atom->ntypes); } else if (strcmp(keyword,"Bond Coeffs") == 0) { if (atom->avec->bonds_allow == 0) error->all("Invalid data file section: Bond Coeffs"); if (force->bond == NULL) error->all("Must define bond_style before Bond Coeffs"); skip_lines(atom->nbondtypes); } else if (strcmp(keyword,"Angle Coeffs") == 0) { if (atom->avec->angles_allow == 0) error->all("Invalid data file section: Angle Coeffs"); if (force->angle == NULL) error->all("Must define angle_style before Angle Coeffs"); skip_lines(atom->nangletypes); } else if (strcmp(keyword,"Dihedral Coeffs") == 0) { skip_lines(atom->ndihedraltypes); if (atom->avec->dihedrals_allow == 0) error->all("Invalid data file section: Dihedral Coeffs"); if (force->dihedral == NULL) error->all("Must define dihedral_style before Dihedral Coeffs"); } else if (strcmp(keyword,"Improper Coeffs") == 0) { if (atom->avec->impropers_allow == 0) error->all("Invalid data file section: Improper Coeffs"); if (force->improper == NULL) error->all("Must define improper_style before Improper Coeffs"); skip_lines(atom->nimpropertypes); } else if (strcmp(keyword,"BondBond Coeffs") == 0) { if (atom->avec->angles_allow == 0) error->all("Invalid data file section: BondBond Coeffs"); if (force->angle == NULL) error->all("Must define angle_style before BondBond Coeffs"); skip_lines(atom->nangletypes); } else if (strcmp(keyword,"BondAngle Coeffs") == 0) { if (atom->avec->angles_allow == 0) error->all("Invalid data file section: BondAngle Coeffs"); if (force->angle == NULL) error->all("Must define angle_style before BondAngle Coeffs"); skip_lines(atom->nangletypes); } else if (strcmp(keyword,"MiddleBondTorsion Coeffs") == 0) { if (atom->avec->dihedrals_allow == 0) error->all("Invalid data file section: MiddleBondTorsion Coeffs"); if (force->dihedral == NULL) error->all("Must define dihedral_style before MiddleBondTorsion Coeffs"); skip_lines(atom->ndihedraltypes); } else if (strcmp(keyword,"EndBondTorsion Coeffs") == 0) { if (atom->avec->dihedrals_allow == 0) error->all("Invalid data file section: EndBondTorsion Coeffs"); if (force->dihedral == NULL) error->all("Must define dihedral_style before EndBondTorsion Coeffs"); skip_lines(atom->ndihedraltypes); } else if (strcmp(keyword,"AngleTorsion Coeffs") == 0) { if (atom->avec->dihedrals_allow == 0) error->all("Invalid data file section: AngleTorsion Coeffs"); if (force->dihedral == NULL) error->all("Must define dihedral_style before AngleTorsion Coeffs"); skip_lines(atom->ndihedraltypes); } else if (strcmp(keyword,"AngleAngleTorsion Coeffs") == 0) { if (atom->avec->dihedrals_allow == 0) error->all("Invalid data file section: AngleAngleTorsion Coeffs"); if (force->dihedral == NULL) error->all("Must define dihedral_style before AngleAngleTorsion Coeffs"); skip_lines(atom->ndihedraltypes); } else if (strcmp(keyword,"BondBond13 Coeffs") == 0) { if (atom->avec->dihedrals_allow == 0) error->all("Invalid data file section: BondBond13 Coeffs"); if (force->dihedral == NULL) error->all("Must define dihedral_style before BondBond13 Coeffs"); skip_lines(atom->ndihedraltypes); } else if (strcmp(keyword,"AngleAngle Coeffs") == 0) { if (atom->avec->impropers_allow == 0) error->all("Invalid data file section: AngleAngle Coeffs"); if (force->improper == NULL) error->all("Must define improper_style before AngleAngle Coeffs"); skip_lines(atom->nimpropertypes); } else if (strcmp(keyword,"Bonds") == 0) { for (i = 1; i < cmax; i++) count[i] = 0; if (force->newton_bond) for (i = 0; i < atom->nbonds; i++) { eof = fgets(line,MAXLINE,fp); if (eof == NULL) error->one("Unexpected end of data file"); sscanf(line,"%d %d %d %d",&tmp1,&tmp2,&atom1,&atom2); if (atom1 >= cmax) cmax = reallocate(&count,cmax,atom1); count[atom1]++; } else for (i = 0; i < atom->nbonds; i++) { eof = fgets(line,MAXLINE,fp); if (eof == NULL) error->one("Unexpected end of data file"); sscanf(line,"%d %d %d %d",&tmp1,&tmp2,&atom1,&atom2); int amax = MAX(atom1,atom2); if (amax >= cmax) cmax = reallocate(&count,cmax,amax); count[atom1]++; count[atom2]++; } for (i = 1; i < cmax; i++) bond_per_atom = MAX(bond_per_atom,count[i]); if (screen) fprintf(screen," %d = max bonds/atom\n",bond_per_atom); if (logfile) fprintf(logfile," %d = max bonds/atom\n",bond_per_atom); } else if (strcmp(keyword,"Angles") == 0) { for (i = 1; i < cmax; i++) count[i] = 0; if (force->newton_bond) for (i = 0; i < atom->nangles; i++) { eof = fgets(line,MAXLINE,fp); if (eof == NULL) error->one("Unexpected end of data file"); sscanf(line,"%d %d %d %d %d",&tmp1,&tmp2,&atom1,&atom2,&atom3); if (atom2 >= cmax) cmax = reallocate(&count,cmax,atom2); count[atom2]++; } else for (i = 0; i < atom->nangles; i++) { eof = fgets(line,MAXLINE,fp); if (eof == NULL) error->one("Unexpected end of data file"); sscanf(line,"%d %d %d %d %d",&tmp1,&tmp2,&atom1,&atom2,&atom3); int amax = MAX(atom1,atom2); amax = MAX(amax,atom3); if (amax >= cmax) cmax = reallocate(&count,cmax,amax); count[atom1]++; count[atom2]++; count[atom3]++; } for (i = 1; i < cmax; i++) angle_per_atom = MAX(angle_per_atom,count[i]); if (screen) fprintf(screen," %d = max angles/atom\n",angle_per_atom); if (logfile) fprintf(logfile," %d = max angles/atom\n",angle_per_atom); } else if (strcmp(keyword,"Dihedrals") == 0) { for (i = 1; i < cmax; i++) count[i] = 0; if (force->newton_bond) for (i = 0; i < atom->ndihedrals; i++) { eof = fgets(line,MAXLINE,fp); if (eof == NULL) error->one("Unexpected end of data file"); sscanf(line,"%d %d %d %d %d %d", &tmp1,&tmp2,&atom1,&atom2,&atom3,&atom4); if (atom2 >= cmax) cmax = reallocate(&count,cmax,atom2); count[atom2]++; } else for (i = 0; i < atom->ndihedrals; i++) { eof = fgets(line,MAXLINE,fp); if (eof == NULL) error->one("Unexpected end of data file"); sscanf(line,"%d %d %d %d %d %d", &tmp1,&tmp2,&atom1,&atom2,&atom3,&atom4); int amax = MAX(atom1,atom2); amax = MAX(amax,atom3); amax = MAX(amax,atom4); if (amax >= cmax) cmax = reallocate(&count,cmax,amax); count[atom1]++; count[atom2]++; count[atom3]++; count[atom4]++; } for (i = 1; i < cmax; i++) dihedral_per_atom = MAX(dihedral_per_atom,count[i]); if (screen) fprintf(screen," %d = max dihedrals/atom\n",dihedral_per_atom); if (logfile) fprintf(logfile," %d = max dihedrals/atom\n",dihedral_per_atom); } else if (strcmp(keyword,"Impropers") == 0) { for (i = 1; i < cmax; i++) count[i] = 0; if (force->newton_bond) for (i = 0; i < atom->nimpropers; i++) { eof = fgets(line,MAXLINE,fp); if (eof == NULL) error->one("Unexpected end of data file"); sscanf(line,"%d %d %d %d %d %d", &tmp1,&tmp2,&atom1,&atom2,&atom3,&atom4); if (atom2 >= cmax) cmax = reallocate(&count,cmax,atom2); count[atom2]++; } else for (i = 0; i < atom->nimpropers; i++) { eof = fgets(line,MAXLINE,fp); if (eof == NULL) error->one("Unexpected end of data file"); sscanf(line,"%d %d %d %d %d %d", &tmp1,&tmp2,&atom1,&atom2,&atom3,&atom4); int amax = MAX(atom1,atom2); amax = MAX(amax,atom3); amax = MAX(amax,atom4); if (amax >= cmax) cmax = reallocate(&count,cmax,amax); count[atom1]++; count[atom2]++; count[atom3]++; count[atom4]++; } for (i = 1; i < cmax; i++) improper_per_atom = MAX(improper_per_atom,count[i]); if (screen) fprintf(screen," %d = max impropers/atom\n",improper_per_atom); if (logfile) fprintf(logfile," %d = max impropers/atom\n",improper_per_atom); } else { char str[128]; sprintf(str,"Unknown identifier in data file: %s",keyword); error->one(str); } parse_keyword(0,0); } // free topology counting vector memory->sfree(count); // error check that topology was specified in file if ((atom->nbonds && !bond_per_atom) || (atom->nangles && !angle_per_atom) || (atom->ndihedrals && !dihedral_per_atom) || (atom->nimpropers && !improper_per_atom)) error->one("Needed topology not in data file"); } /* ---------------------------------------------------------------------- reallocate the count vector from cmax to amax+1 and return new length zero new locations ------------------------------------------------------------------------- */ int ReadData::reallocate(int **pcount, int cmax, int amax) { int *count = *pcount; count = (int *) memory->srealloc(count,(amax+1)*sizeof(int),"read_data:count"); for (int i = cmax; i <= amax; i++) count[i] = 0; *pcount = count; return amax+1; } /* ---------------------------------------------------------------------- proc 0 opens data file test if gzipped ------------------------------------------------------------------------- */ void ReadData::open(char *file) { compressed = 0; char *suffix = file + strlen(file) - 3; if (suffix > file && strcmp(suffix,".gz") == 0) compressed = 1; if (!compressed) fp = fopen(file,"r"); else { #ifdef LAMMPS_GZIP char gunzip[128]; sprintf(gunzip,"gunzip -c %s",file); fp = popen(gunzip,"r"); #else error->one("Cannot open gzipped file"); #endif } if (fp == NULL) { char str[128]; sprintf(str,"Cannot open file %s",file); error->one(str); } } /* ---------------------------------------------------------------------- grab next keyword read lines until one is non-blank keyword is all text on line w/out leading & trailing white space read one additional line (assumed blank) if any read hits EOF, set keyword to empty if first = 1, line variable holds non-blank line that ended header if flag = 0, only proc 0 is calling so no bcast else flag = 1, bcast keyword line to all procs ------------------------------------------------------------------------- */ void ReadData::parse_keyword(int first, int flag) { int eof = 0; // proc 0 reads upto non-blank line plus 1 following line // eof is set to 1 if any read hits end-of-file if (me == 0) { if (!first) { if (fgets(line,MAXLINE,fp) == NULL) eof = 1; } while (eof == 0 && strspn(line," \t\n\r") == strlen(line)) { if (fgets(line,MAXLINE,fp) == NULL) eof = 1; } if (fgets(buffer,MAXLINE,fp) == NULL) eof = 1; } // if eof, set keyword empty and return if (flag) MPI_Bcast(&eof,1,MPI_INT,0,world); if (eof) { keyword[0] = '\0'; return; } // bcast keyword line to all procs if (flag) { int n; if (me == 0) n = strlen(line) + 1; MPI_Bcast(&n,1,MPI_INT,0,world); MPI_Bcast(line,n,MPI_CHAR,0,world); } // copy non-whitespace portion of line into keyword int start = strspn(line," \t\n\r"); int stop = strlen(line) - 1; while (line[stop] == ' ' || line[stop] == '\t' || line[stop] == '\n' || line[stop] == '\r') stop--; line[stop+1] = '\0'; strcpy(keyword,&line[start]); } /* ---------------------------------------------------------------------- proc 0 reads N lines from file ------------------------------------------------------------------------- */ void ReadData::skip_lines(int n) { char *eof; for (int i = 0; i < n; i++) eof = fgets(line,MAXLINE,fp); if (eof == NULL) error->one("Unexpected end of data file"); } /* ---------------------------------------------------------------------- parse a line of coeffs into words, storing them in narg,arg trim anything from '#' onward word strings remain in line, are not copied if addstr != NULL, add addstr as 2nd arg for class2 angle/dihedral/improper if dupflag, duplicate 1st word, so pair_coeff "2" becomes "2 2" ------------------------------------------------------------------------- */ void ReadData::parse_coeffs(char *line, char *addstr, int dupflag) { char *ptr; if (ptr = strchr(line,'#')) *ptr = '\0'; narg = 0; char *word = strtok(line," \t\n\r\f"); while (word) { if (narg == maxarg) { maxarg += DELTA; arg = (char **) memory->srealloc(arg,maxarg*sizeof(char *),"read_data:arg"); } arg[narg++] = word; if (addstr && narg == 1) arg[narg++] = addstr; if (dupflag && narg == 1) arg[narg++] = word; word = strtok(NULL," \t\n\r\f"); } } diff --git a/src/read_restart.cpp b/src/read_restart.cpp index f325bc67b..15ddcf72e 100644 --- a/src/read_restart.cpp +++ b/src/read_restart.cpp @@ -1,824 +1,852 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ #include "mpi.h" #include "string.h" #include "stdlib.h" #include "sys/types.h" #include "dirent.h" #include "read_restart.h" #include "lmptype.h" #include "atom.h" #include "atom_vec.h" #include "domain.h" #include "comm.h" #include "irregular.h" #include "update.h" #include "modify.h" #include "fix.h" #include "fix_read_restart.h" #include "group.h" #include "force.h" #include "pair.h" #include "bond.h" #include "angle.h" #include "dihedral.h" #include "improper.h" #include "special.h" #include "universe.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; // same as write_restart.cpp -enum{VERSION,UNITS,NTIMESTEP,DIMENSION,NPROCS,PROCGRID_0,PROCGRID_1,PROCGRID_2, +enum{VERSION,SMALLINT,TAGINT,BIGINT, + UNITS,NTIMESTEP,DIMENSION,NPROCS,PROCGRID_0,PROCGRID_1,PROCGRID_2, NEWTON_PAIR,NEWTON_BOND,XPERIODIC,YPERIODIC,ZPERIODIC, BOUNDARY_00,BOUNDARY_01,BOUNDARY_10,BOUNDARY_11,BOUNDARY_20,BOUNDARY_21, ATOM_STYLE,NATOMS,NTYPES, NBONDS,NBONDTYPES,BOND_PER_ATOM, NANGLES,NANGLETYPES,ANGLE_PER_ATOM, NDIHEDRALS,NDIHEDRALTYPES,DIHEDRAL_PER_ATOM, NIMPROPERS,NIMPROPERTYPES,IMPROPER_PER_ATOM, BOXLO_0,BOXHI_0,BOXLO_1,BOXHI_1,BOXLO_2,BOXHI_2, SPECIAL_LJ_1,SPECIAL_LJ_2,SPECIAL_LJ_3, SPECIAL_COUL_1,SPECIAL_COUL_2,SPECIAL_COUL_3, XY,XZ,YZ}; enum{MASS,SHAPE,DIPOLE}; enum{PAIR,BOND,ANGLE,DIHEDRAL,IMPROPER}; #define LB_FACTOR 1.1 /* ---------------------------------------------------------------------- */ ReadRestart::ReadRestart(LAMMPS *lmp) : Pointers(lmp) {} /* ---------------------------------------------------------------------- */ void ReadRestart::command(int narg, char **arg) { if (narg != 1) error->all("Illegal read_restart command"); if (domain->box_exist) error->all("Cannot read_restart after simulation box is defined"); MPI_Comm_rank(world,&me); MPI_Comm_size(world,&nprocs); // if filename contains "*", search dir for latest restart file char *file = new char[strlen(arg[0]) + 16]; if (strchr(arg[0],'*')) file_search(arg[0],file); else strcpy(file,arg[0]); // check if filename contains "%" int multiproc; if (strchr(file,'%')) multiproc = 1; else multiproc = 0; // open single restart file or base file for multiproc case if (me == 0) { if (screen) fprintf(screen,"Reading restart file ...\n"); char *hfile; if (multiproc) { hfile = new char[strlen(file) + 16]; char *ptr = strchr(file,'%'); *ptr = '\0'; sprintf(hfile,"%s%s%s",file,"base",ptr+1); *ptr = '%'; } else hfile = file; fp = fopen(hfile,"rb"); if (fp == NULL) { char str[128]; sprintf(str,"Cannot open restart file %s",hfile); error->one(str); } if (multiproc) delete [] hfile; } // read header info and create atom style and simulation box header(); domain->box_exist = 1; // problem setup using info from header int n; if (nprocs == 1) n = static_cast<int> (atom->natoms); else n = static_cast<int> (LB_FACTOR * atom->natoms / nprocs); atom->allocate_type_arrays(); atom->avec->grow(n); n = atom->nmax; domain->print_box(" "); domain->set_initial_box(); domain->set_global_box(); comm->set_procs(); domain->set_local_box(); // read groups, ntype-length arrays, force field, fix info from file // nextra = max # of extra quantities stored with each atom group->read_restart(fp); type_arrays(); force_fields(); int nextra = modify->read_restart(fp); atom->nextra_store = nextra; atom->extra = memory->create_2d_double_array(n,nextra,"atom:extra"); // single file: // nprocs_file = # of chunks in file // proc 0 reads chunks one at a time and bcasts it to other procs // each proc unpacks the atoms, saving ones in it's sub-domain // check for atom in sub-domain differs for orthogonal vs triclinic box // close restart file when done AtomVec *avec = atom->avec; int maxbuf = 0; double *buf = NULL; int m; if (multiproc == 0) { int triclinic = domain->triclinic; double *x,lamda[3]; double *coord,*sublo,*subhi; if (triclinic == 0) { sublo = domain->sublo; subhi = domain->subhi; } else { sublo = domain->sublo_lamda; subhi = domain->subhi_lamda; } for (int iproc = 0; iproc < nprocs_file; iproc++) { if (me == 0) fread(&n,sizeof(int),1,fp); MPI_Bcast(&n,1,MPI_INT,0,world); if (n > maxbuf) { maxbuf = n; memory->sfree(buf); buf = (double *) memory->smalloc(maxbuf*sizeof(double), "read_restart:buf"); } if (n > 0) { if (me == 0) fread(buf,sizeof(double),n,fp); MPI_Bcast(buf,n,MPI_DOUBLE,0,world); } m = 0; while (m < n) { x = &buf[m+1]; if (triclinic) { domain->x2lamda(x,lamda); coord = lamda; } else coord = x; if (coord[0] >= sublo[0] && coord[0] < subhi[0] && coord[1] >= sublo[1] && coord[1] < subhi[1] && coord[2] >= sublo[2] && coord[2] < subhi[2]) { m += avec->unpack_restart(&buf[m]); } else m += static_cast<int> (buf[m]); } } if (me == 0) fclose(fp); // one file per proc: // nprocs_file = # of files // each proc reads 1/P fraction of files, keeping all atoms in the files // perform irregular comm to migrate atoms to correct procs // close restart file when done } else { if (me == 0) fclose(fp); char *perproc = new char[strlen(file) + 16]; char *ptr = strchr(file,'%'); for (int iproc = me; iproc < nprocs_file; iproc += nprocs) { *ptr = '\0'; sprintf(perproc,"%s%d%s",file,iproc,ptr+1); *ptr = '%'; fp = fopen(perproc,"rb"); if (fp == NULL) { char str[128]; sprintf(str,"Cannot open restart file %s",perproc); error->one(str); } fread(&n,sizeof(int),1,fp); if (n > maxbuf) { maxbuf = n; memory->sfree(buf); buf = (double *) memory->smalloc(maxbuf*sizeof(double), "read_restart:buf"); } if (n > 0) fread(buf,sizeof(double),n,fp); m = 0; while (m < n) m += avec->unpack_restart(&buf[m]); fclose(fp); } delete [] perproc; // create a temporary fix to hold and migrate extra atom info // necessary b/c irregular will migrate atoms if (nextra) { char cextra[8],fixextra[8]; sprintf(cextra,"%d",nextra); sprintf(fixextra,"%d",modify->nfix_restart_peratom); char **newarg = new char*[5]; newarg[0] = (char *) "_read_restart"; newarg[1] = (char *) "all"; newarg[2] = (char *) "READ_RESTART"; newarg[3] = cextra; newarg[4] = fixextra; modify->add_fix(5,newarg); delete [] newarg; } // move atoms to new processors via irregular() // in case read by different proc than wrote restart file + // first do map_init() since irregular->migrate_atoms() will do map_clear() + if (atom->map_style) atom->map_init(); if (domain->triclinic) domain->x2lamda(atom->nlocal); Irregular *irregular = new Irregular(lmp); irregular->migrate_atoms(); delete irregular; if (domain->triclinic) domain->lamda2x(atom->nlocal); // put extra atom info held by fix back into atom->extra // destroy temporary fix if (nextra) { memory->destroy_2d_double_array(atom->extra); atom->extra = memory->create_2d_double_array(atom->nmax,nextra, "atom:extra"); int ifix = modify->find_fix("_read_restart"); FixReadRestart *fix = (FixReadRestart *) modify->fix[ifix]; int *count = fix->count; double **extra = fix->extra; double **atom_extra = atom->extra; int nlocal = atom->nlocal; for (int i = 0; i < nlocal; i++) for (int j = 0; j < count[i]; j++) atom_extra[i][j] = extra[i][j]; modify->delete_fix("_read_restart"); } } // clean-up memory delete [] file; memory->sfree(buf); // check that all atoms were assigned to procs bigint natoms; bigint nblocal = atom->nlocal; - MPI_Allreduce(&nblocal,&natoms,1,MPI_UNSIGNED_LONG_LONG,MPI_SUM,world); + MPI_Allreduce(&nblocal,&natoms,1,MPI_LMP_BIGINT,MPI_SUM,world); if (me == 0) { - if (screen) fprintf(screen," %lu atoms\n",natoms); - if (logfile) fprintf(logfile," %lu atoms\n",natoms); + char str[32]; + sprintf(str," %s atoms\n",BIGINT_FORMAT); + if (screen) fprintf(screen,str,natoms); + if (logfile) fprintf(logfile,str,natoms); } if (natoms != atom->natoms) error->all("Did not assign all atoms correctly"); if (me == 0) { if (atom->nbonds) { - if (screen) fprintf(screen," %lu bonds\n",atom->nbonds); - if (logfile) fprintf(logfile," %lu bonds\n",atom->nbonds); + char str[32]; + sprintf(str," %s bonds\n",BIGINT_FORMAT); + if (screen) fprintf(screen,str,atom->nbonds); + if (logfile) fprintf(logfile,str,atom->nbonds); } if (atom->nangles) { - if (screen) fprintf(screen," %lu angles\n",atom->nangles); - if (logfile) fprintf(logfile," %lu angles\n",atom->nangles); + char str[32]; + sprintf(str," %s angles\n",BIGINT_FORMAT); + if (screen) fprintf(screen,str,atom->nangles); + if (logfile) fprintf(logfile,str,atom->nangles); } if (atom->ndihedrals) { - if (screen) fprintf(screen," %lu dihedrals\n",atom->ndihedrals); - if (logfile) fprintf(logfile," %lu dihedrals\n",atom->ndihedrals); + char str[32]; + sprintf(str," %s dihedrals\n",BIGINT_FORMAT); + if (screen) fprintf(screen,str,atom->ndihedrals); + if (logfile) fprintf(logfile,str,atom->ndihedrals); } if (atom->nimpropers) { - if (screen) fprintf(screen," %lu impropers\n",atom->nimpropers); - if (logfile) fprintf(logfile," %lu impropers\n",atom->nimpropers); + char str[32]; + sprintf(str," %s impropers\n",BIGINT_FORMAT); + if (screen) fprintf(screen,str,atom->nimpropers); + if (logfile) fprintf(logfile,str,atom->nimpropers); } } // check if tags are being used // create global mapping and bond topology now that system is defined int flag = 0; for (int i = 0; i < atom->nlocal; i++) if (atom->tag[i] > 0) flag = 1; int flag_all; MPI_Allreduce(&flag,&flag_all,1,MPI_INT,MPI_MAX,world); if (flag_all == 0) atom->tag_enable = 0; if (atom->map_style) { atom->map_init(); atom->map_set(); } if (atom->molecular) { Special special(lmp); special.build(); } } /* ---------------------------------------------------------------------- search for all files matching infile which contains a "*" replace "*" with latest timestep value to create outfile name search dir referenced by initial pathname of file if infile also contains "%", need to use "base" when search directory ------------------------------------------------------------------------- */ void ReadRestart::file_search(char *infile, char *outfile) { char *ptr; // separate infile into dir + filename char *dirname = new char[strlen(infile) + 1]; char *filename = new char[strlen(infile) + 1]; if (strchr(infile,'/')) { ptr = strrchr(infile,'/'); *ptr = '\0'; strcpy(dirname,infile); strcpy(filename,ptr+1); *ptr = '/'; } else { strcpy(dirname,"./"); strcpy(filename,infile); } // if filename contains "%" replace "%" with "base" char *pattern = new char[strlen(filename) + 16]; if (ptr = strchr(filename,'%')) { *ptr = '\0'; sprintf(pattern,"%s%s%s",filename,"base",ptr+1); *ptr = '%'; } else strcpy(pattern,filename); // scan all files in directory, searching for files that match pattern // maxnum = largest int that matches "*" int n = strlen(pattern) + 16; char *begin = new char[n]; char *middle = new char[n]; char *end = new char[n]; ptr = strchr(pattern,'*'); *ptr = '\0'; strcpy(begin,pattern); strcpy(end,ptr+1); int nbegin = strlen(begin); int maxnum = -1; if (me == 0) { struct dirent *ep; DIR *dp = opendir(dirname); if (dp == NULL) error->one("Cannot open dir to search for restart file"); while (ep = readdir(dp)) { if (strstr(ep->d_name,begin) != ep->d_name) continue; if ((ptr = strstr(&ep->d_name[nbegin],end)) == NULL) continue; if (strlen(end) == 0) ptr = ep->d_name + strlen(ep->d_name); *ptr = '\0'; if (strlen(&ep->d_name[nbegin]) < n) { strcpy(middle,&ep->d_name[nbegin]); if (atoi(middle) > maxnum) maxnum = atoi(middle); } } closedir(dp); if (maxnum < 0) error->one("Found no restart file matching pattern"); } // create outfile with maxint substituted for "*" // use original infile, not pattern, since need to retain "%" in filename ptr = strchr(infile,'*'); *ptr = '\0'; sprintf(outfile,"%s%d%s",infile,maxnum,ptr+1); *ptr = '*'; // clean up delete [] dirname; delete [] filename; delete [] pattern; delete [] begin; delete [] middle; delete [] end; } /* ---------------------------------------------------------------------- read header of restart file ------------------------------------------------------------------------- */ void ReadRestart::header() { int px,py,pz; int xperiodic,yperiodic,zperiodic; int boundary[3][2]; // read flags and values until flag = -1 int flag = read_int(); while (flag >= 0) { // check restart file version, warn if different if (flag == VERSION) { char *version = read_char(); if (strcmp(version,universe->version) != 0 && me == 0) { error->warning("Restart file version does not match LAMMPS version"); if (screen) fprintf(screen," restart file = %s, LAMMPS = %s\n", version,universe->version); } delete [] version; + + // check lmptype.h sizes, error if different + + } else if (flag == SMALLINT) { + int size = read_int(); + if (size != sizeof(smallint)) + error->all("Smallint setting in lmptype.h is not compatible"); + } else if (flag == TAGINT) { + int size = read_int(); + if (size != sizeof(tagint)) + error->all("Tagint setting in lmptype.h is not compatible"); + } else if (flag == BIGINT) { + int size = read_int(); + if (size != sizeof(bigint)) + error->all("Bigint setting in lmptype.h is not compatible"); // reset unit_style only if different // so that timestep,neighbor-skin are not changed } else if (flag == UNITS) { char *style = read_char(); if (strcmp(style,update->unit_style) != 0) update->set_units(style); delete [] style; } else if (flag == NTIMESTEP) { - update->ntimestep = read_int(); + update->ntimestep = read_bigint(); // set dimension from restart file } else if (flag == DIMENSION) { int dimension = read_int(); domain->dimension = dimension; if (domain->dimension == 2 && domain->zperiodic == 0) error->all("Cannot run 2d simulation with nonperiodic Z dimension"); // read nprocs from restart file, warn if different } else if (flag == NPROCS) { nprocs_file = read_int(); if (nprocs_file != comm->nprocs && me == 0) error->warning("Restart file used different # of processors"); // don't set procgrid, warn if different } else if (flag == PROCGRID_0) { px = read_int(); } else if (flag == PROCGRID_1) { py = read_int(); } else if (flag == PROCGRID_2) { pz = read_int(); if (comm->user_procgrid[0] != 0 && (px != comm->user_procgrid[0] || py != comm->user_procgrid[1] || pz != comm->user_procgrid[2]) && me == 0) error->warning("Restart file used different 3d processor grid"); // don't set newton_pair, leave input script value unchanged // set newton_bond from restart file // warn if different and input script settings are not default } else if (flag == NEWTON_PAIR) { int newton_pair_file = read_int(); if (force->newton_pair != 1) { if (newton_pair_file != force->newton_pair && me == 0) error->warning("Restart file used different newton pair setting, " "using input script value"); } } else if (flag == NEWTON_BOND) { int newton_bond_file = read_int(); if (force->newton_bond != 1) { if (newton_bond_file != force->newton_bond && me == 0) error->warning("Restart file used different newton bond setting, " "using restart file value"); } force->newton_bond = newton_bond_file; if (force->newton_pair || force->newton_bond) force->newton = 1; else force->newton = 0; // set boundary settings from restart file // warn if different and input script settings are not default } else if (flag == XPERIODIC) { xperiodic = read_int(); } else if (flag == YPERIODIC) { yperiodic = read_int(); } else if (flag == ZPERIODIC) { zperiodic = read_int(); } else if (flag == BOUNDARY_00) { boundary[0][0] = read_int(); } else if (flag == BOUNDARY_01) { boundary[0][1] = read_int(); } else if (flag == BOUNDARY_10) { boundary[1][0] = read_int(); } else if (flag == BOUNDARY_11) { boundary[1][1] = read_int(); } else if (flag == BOUNDARY_20) { boundary[2][0] = read_int(); } else if (flag == BOUNDARY_21) { boundary[2][1] = read_int(); if (domain->boundary[0][0] || domain->boundary[0][1] || domain->boundary[1][0] || domain->boundary[1][1] || domain->boundary[2][0] || domain->boundary[2][1]) { if (boundary[0][0] != domain->boundary[0][0] || boundary[0][1] != domain->boundary[0][1] || boundary[1][0] != domain->boundary[1][0] || boundary[1][1] != domain->boundary[1][1] || boundary[2][0] != domain->boundary[2][0] || boundary[2][1] != domain->boundary[2][1]) { if (me == 0) error->warning("Restart file used different boundary settings, " "using restart file values"); } } domain->boundary[0][0] = boundary[0][0]; domain->boundary[0][1] = boundary[0][1]; domain->boundary[1][0] = boundary[1][0]; domain->boundary[1][1] = boundary[1][1]; domain->boundary[2][0] = boundary[2][0]; domain->boundary[2][1] = boundary[2][1]; domain->periodicity[0] = domain->xperiodic = xperiodic; domain->periodicity[1] = domain->yperiodic = yperiodic; domain->periodicity[2] = domain->zperiodic = zperiodic; domain->nonperiodic = 0; if (xperiodic == 0 || yperiodic == 0 || zperiodic == 0) { domain->nonperiodic = 1; if (boundary[0][0] >= 2 || boundary[0][1] >= 2 || boundary[1][0] >= 2 || boundary[1][1] >= 2 || boundary[2][0] >= 2 || boundary[2][1] >= 2) domain->nonperiodic = 2; } // create new AtomVec class // if style = hybrid, read additional sub-class arguments } else if (flag == ATOM_STYLE) { char *style = read_char(); int nwords = 0; char **words = NULL; if (strcmp(style,"hybrid") == 0) { nwords = read_int(); words = new char*[nwords]; for (int i = 0; i < nwords; i++) words[i] = read_char(); } atom->create_avec(style,nwords,words); for (int i = 0; i < nwords; i++) delete [] words[i]; delete [] words; delete [] style; } else if (flag == NATOMS) { atom->natoms = read_bigint(); } else if (flag == NTYPES) { atom->ntypes = read_int(); } else if (flag == NBONDS) { atom->nbonds = read_bigint(); } else if (flag == NBONDTYPES) { atom->nbondtypes = read_int(); } else if (flag == BOND_PER_ATOM) { atom->bond_per_atom = read_int(); } else if (flag == NANGLES) { atom->nangles = read_bigint(); } else if (flag == NANGLETYPES) { atom->nangletypes = read_int(); } else if (flag == ANGLE_PER_ATOM) { atom->angle_per_atom = read_int(); } else if (flag == NDIHEDRALS) { atom->ndihedrals = read_bigint(); } else if (flag == NDIHEDRALTYPES) { atom->ndihedraltypes = read_int(); } else if (flag == DIHEDRAL_PER_ATOM) { atom->dihedral_per_atom = read_int(); } else if (flag == NIMPROPERS) { atom->nimpropers = read_bigint(); } else if (flag == NIMPROPERTYPES) { atom->nimpropertypes = read_int(); } else if (flag == IMPROPER_PER_ATOM) { atom->improper_per_atom = read_int(); } else if (flag == BOXLO_0) { domain->boxlo[0] = read_double(); } else if (flag == BOXHI_0) { domain->boxhi[0] = read_double(); } else if (flag == BOXLO_1) { domain->boxlo[1] = read_double(); } else if (flag == BOXHI_1) { domain->boxhi[1] = read_double(); } else if (flag == BOXLO_2) { domain->boxlo[2] = read_double(); } else if (flag == BOXHI_2) { domain->boxhi[2] = read_double(); } else if (flag == SPECIAL_LJ_1) { force->special_lj[1] = read_double(); } else if (flag == SPECIAL_LJ_2) { force->special_lj[2] = read_double(); } else if (flag == SPECIAL_LJ_3) { force->special_lj[3] = read_double(); } else if (flag == SPECIAL_COUL_1) { force->special_coul[1] = read_double(); } else if (flag == SPECIAL_COUL_2) { force->special_coul[2] = read_double(); } else if (flag == SPECIAL_COUL_3) { force->special_coul[3] = read_double(); } else if (flag == XY) { domain->triclinic = 1; domain->xy = read_double(); } else if (flag == XZ) { domain->triclinic = 1; domain->xz = read_double(); } else if (flag == YZ) { domain->triclinic = 1; domain->yz = read_double(); } else error->all("Invalid flag in header section of restart file"); flag = read_int(); } } /* ---------------------------------------------------------------------- */ void ReadRestart::type_arrays() { int flag = read_int(); while (flag >= 0) { if (flag == MASS) { double *mass = new double[atom->ntypes+1]; if (me == 0) fread(&mass[1],sizeof(double),atom->ntypes,fp); MPI_Bcast(&mass[1],atom->ntypes,MPI_DOUBLE,0,world); atom->set_mass(mass); delete [] mass; } else if (flag == SHAPE) { double **shape = memory->create_2d_double_array(atom->ntypes+1,3,"restart:shape"); if (me == 0) fread(&shape[1][0],sizeof(double),atom->ntypes*3,fp); MPI_Bcast(&shape[1][0],atom->ntypes*3,MPI_DOUBLE,0,world); atom->set_shape(shape); memory->destroy_2d_double_array(shape); } else if (flag == DIPOLE) { double *dipole = new double[atom->ntypes+1]; if (me == 0) fread(&dipole[1],sizeof(double),atom->ntypes,fp); MPI_Bcast(&dipole[1],atom->ntypes,MPI_DOUBLE,0,world); atom->set_dipole(dipole); delete [] dipole; } else error->all("Invalid flag in type arrays section of restart file"); flag = read_int(); } } /* ---------------------------------------------------------------------- */ void ReadRestart::force_fields() { int n; char *style; int flag = read_int(); while (flag >= 0) { if (flag == PAIR) { if (me == 0) fread(&n,sizeof(int),1,fp); MPI_Bcast(&n,1,MPI_INT,0,world); style = new char[n]; if (me == 0) fread(style,sizeof(char),n,fp); MPI_Bcast(style,n,MPI_CHAR,0,world); force->create_pair(style); delete [] style; force->pair->read_restart(fp); } else if (flag == BOND) { if (me == 0) fread(&n,sizeof(int),1,fp); MPI_Bcast(&n,1,MPI_INT,0,world); style = new char[n]; if (me == 0) fread(style,sizeof(char),n,fp); MPI_Bcast(style,n,MPI_CHAR,0,world); force->create_bond(style); delete [] style; force->bond->read_restart(fp); } else if (flag == ANGLE) { if (me == 0) fread(&n,sizeof(int),1,fp); MPI_Bcast(&n,1,MPI_INT,0,world); style = new char[n]; if (me == 0) fread(style,sizeof(char),n,fp); MPI_Bcast(style,n,MPI_CHAR,0,world); force->create_angle(style); delete [] style; force->angle->read_restart(fp); } else if (flag == DIHEDRAL) { if (me == 0) fread(&n,sizeof(int),1,fp); MPI_Bcast(&n,1,MPI_INT,0,world); style = new char[n]; if (me == 0) fread(style,sizeof(char),n,fp); MPI_Bcast(style,n,MPI_CHAR,0,world); force->create_dihedral(style); delete [] style; force->dihedral->read_restart(fp); } else if (flag == IMPROPER) { if (me == 0) fread(&n,sizeof(int),1,fp); MPI_Bcast(&n,1,MPI_INT,0,world); style = new char[n]; if (me == 0) fread(style,sizeof(char),n,fp); MPI_Bcast(style,n,MPI_CHAR,0,world); force->create_improper(style); delete [] style; force->improper->read_restart(fp); } else error->all("Invalid flag in force field section of restart file"); flag = read_int(); } } /* ---------------------------------------------------------------------- read an int from restart file and bcast it ------------------------------------------------------------------------- */ int ReadRestart::read_int() { int value; if (me == 0) fread(&value,sizeof(int),1,fp); MPI_Bcast(&value,1,MPI_INT,0,world); return value; } /* ---------------------------------------------------------------------- read a double from restart file and bcast it ------------------------------------------------------------------------- */ double ReadRestart::read_double() { double value; if (me == 0) fread(&value,sizeof(double),1,fp); MPI_Bcast(&value,1,MPI_DOUBLE,0,world); return value; } /* ---------------------------------------------------------------------- read a char str from restart file and bcast it str is allocated here, ptr is returned, caller must deallocate ------------------------------------------------------------------------- */ char *ReadRestart::read_char() { int n; if (me == 0) fread(&n,sizeof(int),1,fp); MPI_Bcast(&n,1,MPI_INT,0,world); char *value = new char[n]; if (me == 0) fread(value,sizeof(char),n,fp); MPI_Bcast(value,n,MPI_CHAR,0,world); return value; } /* ---------------------------------------------------------------------- read a bigint from restart file and bcast it ------------------------------------------------------------------------- */ bigint ReadRestart::read_bigint() { bigint value; if (me == 0) fread(&value,sizeof(bigint),1,fp); - MPI_Bcast(&value,1,MPI_UNSIGNED_LONG_LONG,0,world); + MPI_Bcast(&value,1,MPI_LMP_BIGINT,0,world); return value; } diff --git a/src/region.h b/src/region.h index f269958b9..c4a1e18a7 100644 --- a/src/region.h +++ b/src/region.h @@ -1,72 +1,73 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain 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_REGION_H #define LMP_REGION_H #include "pointers.h" +#include "lmptype.h" namespace LAMMPS_NS { class Region : protected Pointers { public: char *id,*style; int interior; // 1 for interior, 0 for exterior int scaleflag; // 1 for lattice, 0 for box double xscale,yscale,zscale; // scale factors for box/lattice units double extent_xlo,extent_xhi; // bounding box on region double extent_ylo,extent_yhi; double extent_zlo,extent_zhi; int bboxflag; // 1 if bounding box is computable // contact = particle near region surface struct Contact { double r; // distance between particle & surf, r > 0.0 double delx,dely,delz; // vector from surface pt to particle }; Contact *contact; // list of contacts int cmax; // max # of contacts possible with region Region(class LAMMPS *, int, char **); virtual ~Region(); void init(); virtual int dynamic_check(); int match(double, double, double); int surface(double, double, double, double); virtual int inside(double, double, double) = 0; virtual int surface_interior(double *, double) = 0; virtual int surface_exterior(double *, double) = 0; protected: void add_contact(int, double *, double, double, double); void options(int, char **); private: int dynamic; // 1 if region changes over time int moveflag,rotateflag; double point[3],axis[3],runit[3]; char *xstr,*ystr,*zstr,*tstr; int xvar,yvar,zvar,tvar; double dx,dy,dz,theta; - int laststep; + bigint laststep; void forward_transform(double &, double &, double &); void inverse_transform(double &, double &, double &); void rotate(double &, double &, double &, double); }; } #endif diff --git a/src/replicate.cpp b/src/replicate.cpp index a4e02bd12..5ade979e6 100644 --- a/src/replicate.cpp +++ b/src/replicate.cpp @@ -1,408 +1,420 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ #include "stdlib.h" #include "string.h" #include "replicate.h" #include "lmptype.h" #include "atom.h" #include "atom_vec.h" #include "atom_vec_hybrid.h" #include "force.h" #include "domain.h" #include "comm.h" #include "special.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; #define LB_FACTOR 1.1 #define EPSILON 1.0e-6 #define MIN(a,b) ((a) < (b) ? (a) : (b)) #define MAX(a,b) ((a) > (b) ? (a) : (b)) /* ---------------------------------------------------------------------- */ Replicate::Replicate(LAMMPS *lmp) : Pointers(lmp) {} /* ---------------------------------------------------------------------- */ void Replicate::command(int narg, char **arg) { int i,j,m,n; if (domain->box_exist == 0) error->all("Replicate command before simulation box is defined"); if (narg != 3) error->all("Illegal replicate command"); int me = comm->me; int nprocs = comm->nprocs; if (me == 0 && screen) fprintf(screen,"Replicating atoms ...\n"); // nrep = total # of replications int nx = atoi(arg[0]); int ny = atoi(arg[1]); int nz = atoi(arg[2]); int nrep = nx*ny*nz; // error and warning checks if (nx <= 0 || ny <= 0 || nz <= 0) error->all("Illegal replicate command"); if (domain->dimension == 2 && nz != 1) error->all("Cannot replicate 2d simulation in z dimension"); if ((nx > 1 && domain->xperiodic == 0) || (ny > 1 && domain->yperiodic == 0) || (nz > 1 && domain->zperiodic == 0)) error->warning("Replicating in a non-periodic dimension"); if (atom->nextra_grow || atom->nextra_restart || atom->nextra_store) error->all("Cannot replicate with fixes that store atom quantities"); // maxtag = largest atom tag across all existing atoms int maxtag = 0; for (i = 0; i < atom->nlocal; i++) maxtag = MAX(atom->tag[i],maxtag); int maxtag_all; MPI_Allreduce(&maxtag,&maxtag_all,1,MPI_INT,MPI_MAX,world); maxtag = maxtag_all; // maxmol = largest molecule tag across all existing atoms int maxmol = 0; if (atom->molecular) { for (i = 0; i < atom->nlocal; i++) maxmol = MAX(atom->molecule[i],maxmol); int maxmol_all; MPI_Allreduce(&maxmol,&maxmol_all,1,MPI_INT,MPI_MAX,world); maxmol = maxmol_all; } // unmap existing atoms via image flags for (i = 0; i < atom->nlocal; i++) domain->unmap(atom->x[i],atom->image[i]); // communication buffer for all my atom's info // max_size = largest buffer needed by any proc // must do before new Atom class created, // since size_restart() uses atom->nlocal int max_size; int send_size = atom->avec->size_restart(); MPI_Allreduce(&send_size,&max_size,1,MPI_INT,MPI_MAX,world); double *buf = (double *) memory->smalloc(max_size*sizeof(double),"replicate:buf"); // old = original atom class // atom = new replicated atom class // if old atom style was hybrid, pass sub-style names to create_avec Atom *old = atom; atom = new Atom(lmp); atom->settings(old); int nstyles = 0; char **keywords = NULL; if (strcmp(old->atom_style,"hybrid") == 0) { AtomVecHybrid *avec_hybrid = (AtomVecHybrid *) old->avec; nstyles = avec_hybrid->nstyles; keywords = avec_hybrid->keywords; } atom->create_avec(old->atom_style,nstyles,keywords); - // check that new problem size will not be too large - // if N > 2^31, turn off tags for existing and new atoms - // if molecular, N/Nbonds/etc cannot be > 2^31 else tags/counts invalid - - double rep = nrep; - if (rep*old->natoms > MAXINT32) atom->tag_enable = 0; - + // check that new system will not be too large + // if molecular and N > MAXTAGINT, error + // if atomic and new N > MAXTAGINT, turn off tags for existing and new atoms + // new system cannot exceed MAXBIGINT + + if (atom->molecular && (nrep*old->natoms < 0 || nrep*old->natoms > MAXTAGINT)) + error->all("Replicated molecular system atom IDs are too big"); + if (nrep*old->natoms < 0 || nrep*old->natoms > MAXTAGINT) + atom->tag_enable = 0; if (atom->tag_enable == 0) for (int i = 0; i < atom->nlocal; i++) atom->tag[i] = 0; - if (atom->molecular) { - if (rep*old->natoms > MAXINT32 || rep*old->nbonds > MAXINT32 || - rep*old->nangles > MAXINT32 || rep*old->ndihedrals > MAXINT32 || - rep*old->nimpropers > MAXINT32) - error->all("Too big a problem to replicate with molecular atom style"); - } + if (nrep*old->natoms < 0 || nrep*old->natoms > MAXBIGINT || + nrep*old->nbonds < 0 || nrep*old->nbonds > MAXBIGINT || + nrep*old->nangles < 0 || nrep*old->nangles > MAXBIGINT || + nrep*old->ndihedrals < 0 || nrep*old->ndihedrals > MAXBIGINT || + nrep*old->nimpropers < 0 || nrep*old->nimpropers > MAXBIGINT) + error->all("Replicated system is too big"); // assign atom and topology counts in new class from old one atom->natoms = old->natoms * nrep; atom->nbonds = old->nbonds * nrep; atom->nangles = old->nangles * nrep; atom->ndihedrals = old->ndihedrals * nrep; atom->nimpropers = old->nimpropers * nrep; atom->ntypes = old->ntypes; atom->nbondtypes = old->nbondtypes; atom->nangletypes = old->nangletypes; atom->ndihedraltypes = old->ndihedraltypes; atom->nimpropertypes = old->nimpropertypes; atom->bond_per_atom = old->bond_per_atom; atom->angle_per_atom = old->angle_per_atom; atom->dihedral_per_atom = old->dihedral_per_atom; atom->improper_per_atom = old->improper_per_atom; // store old simulation box int triclinic = domain->triclinic; double old_xprd = domain->xprd; double old_yprd = domain->yprd; double old_zprd = domain->zprd; double old_xy = domain->xy; double old_xz = domain->xz; double old_yz = domain->yz; // setup new simulation box domain->boxhi[0] = domain->boxlo[0] + nx*old_xprd; domain->boxhi[1] = domain->boxlo[1] + ny*old_yprd; domain->boxhi[2] = domain->boxlo[2] + nz*old_zprd; if (triclinic) { domain->xy *= ny; domain->xz *= nz; domain->yz *= nz; } // new problem setup using new box boundaries if (nprocs == 1) n = static_cast<int> (atom->natoms); else n = static_cast<int> (LB_FACTOR * atom->natoms / nprocs); atom->allocate_type_arrays(); atom->avec->grow(n); n = atom->nmax; domain->print_box(" "); domain->set_initial_box(); domain->set_global_box(); comm->set_procs(); domain->set_local_box(); // copy type arrays to new atom class if (atom->mass) { for (int itype = 1; itype <= atom->ntypes; itype++) { atom->mass_setflag[itype] = old->mass_setflag[itype]; if (atom->mass_setflag[itype]) atom->mass[itype] = old->mass[itype]; } } if (atom->shape) { for (int itype = 1; itype <= atom->ntypes; itype++) { atom->shape_setflag[itype] = old->shape_setflag[itype]; if (atom->shape_setflag[itype]) { atom->shape[itype][0] = old->shape[itype][0]; atom->shape[itype][1] = old->shape[itype][1]; atom->shape[itype][2] = old->shape[itype][2]; } } } if (atom->dipole) { for (int itype = 1; itype <= atom->ntypes; itype++) { atom->dipole_setflag[itype] = old->dipole_setflag[itype]; if (atom->dipole_setflag[itype]) atom->dipole[itype] = old->dipole[itype]; } } // set bounds for my proc // if periodic and I am lo/hi proc, adjust bounds by EPSILON // insures all replicated atoms will be owned even with round-off double sublo[3],subhi[3]; if (triclinic == 0) { sublo[0] = domain->sublo[0]; subhi[0] = domain->subhi[0]; sublo[1] = domain->sublo[1]; subhi[1] = domain->subhi[1]; sublo[2] = domain->sublo[2]; subhi[2] = domain->subhi[2]; } else { sublo[0] = domain->sublo_lamda[0]; subhi[0] = domain->subhi_lamda[0]; sublo[1] = domain->sublo_lamda[1]; subhi[1] = domain->subhi_lamda[1]; sublo[2] = domain->sublo_lamda[2]; subhi[2] = domain->subhi_lamda[2]; } if (domain->xperiodic) { if (comm->myloc[0] == 0) sublo[0] -= EPSILON; if (comm->myloc[0] == comm->procgrid[0]-1) subhi[0] += EPSILON; } if (domain->yperiodic) { if (comm->myloc[1] == 0) sublo[1] -= EPSILON; if (comm->myloc[1] == comm->procgrid[1]-1) subhi[1] += EPSILON; } if (domain->zperiodic) { if (comm->myloc[2] == 0) sublo[2] -= EPSILON; if (comm->myloc[2] == comm->procgrid[2]-1) subhi[2] += EPSILON; } // loop over all procs // if this iteration of loop is me: // pack my unmapped atom data into buf // bcast it to all other procs // performs 3d replicate loop with while loop over atoms in buf // x = new replicated position, remapped into simulation box // unpack atom into new atom class from buf if I own it // adjust tag, mol #, coord, topology info as needed AtomVec *old_avec = old->avec; AtomVec *avec = atom->avec; int ix,iy,iz,image,atom_offset,mol_offset; double x[3],lamda[3]; double *coord; int tag_enable = atom->tag_enable; for (int iproc = 0; iproc < nprocs; iproc++) { if (me == iproc) { n = 0; for (i = 0; i < old->nlocal; i++) n += old_avec->pack_restart(i,&buf[n]); } MPI_Bcast(&n,1,MPI_INT,iproc,world); MPI_Bcast(buf,n,MPI_DOUBLE,iproc,world); for (ix = 0; ix < nx; ix++) { for (iy = 0; iy < ny; iy++) { for (iz = 0; iz < nz; iz++) { // while loop over one proc's atom list m = 0; while (m < n) { image = (512 << 20) | (512 << 10) | 512; if (triclinic == 0) { x[0] = buf[m+1] + ix*old_xprd; x[1] = buf[m+2] + iy*old_yprd; x[2] = buf[m+3] + iz*old_zprd; } else { x[0] = buf[m+1] + ix*old_xprd + iy*old_xy + iz*old_xz; x[1] = buf[m+2] + iy*old_yprd + iz*old_yz; x[2] = buf[m+3] + iz*old_zprd; } domain->remap(x,image); if (triclinic) { domain->x2lamda(x,lamda); coord = lamda; } else coord = x; if (coord[0] >= sublo[0] && coord[0] < subhi[0] && coord[1] >= sublo[1] && coord[1] < subhi[1] && coord[2] >= sublo[2] && coord[2] < subhi[2]) { m += avec->unpack_restart(&buf[m]); i = atom->nlocal - 1; if (tag_enable) atom_offset = iz*ny*nx*maxtag + iy*nx*maxtag + ix*maxtag; else atom_offset = 0; mol_offset = iz*ny*nx*maxmol + iy*nx*maxmol + ix*maxmol; atom->x[i][0] = x[0]; atom->x[i][1] = x[1]; atom->x[i][2] = x[2]; atom->tag[i] += atom_offset; atom->image[i] = image; if (atom->molecular) { if (atom->molecule[i] > 0) atom->molecule[i] += mol_offset; if (atom->avec->bonds_allow) for (j = 0; j < atom->num_bond[i]; j++) atom->bond_atom[i][j] += atom_offset; if (atom->avec->angles_allow) for (j = 0; j < atom->num_angle[i]; j++) { atom->angle_atom1[i][j] += atom_offset; atom->angle_atom2[i][j] += atom_offset; atom->angle_atom3[i][j] += atom_offset; } if (atom->avec->dihedrals_allow) for (j = 0; j < atom->num_dihedral[i]; j++) { atom->dihedral_atom1[i][j] += atom_offset; atom->dihedral_atom2[i][j] += atom_offset; atom->dihedral_atom3[i][j] += atom_offset; atom->dihedral_atom4[i][j] += atom_offset; } if (atom->avec->impropers_allow) for (j = 0; j < atom->num_improper[i]; j++) { atom->improper_atom1[i][j] += atom_offset; atom->improper_atom2[i][j] += atom_offset; atom->improper_atom3[i][j] += atom_offset; atom->improper_atom4[i][j] += atom_offset; } } } else m += static_cast<int> (buf[m]); } } } } } // end of proc loop // free communication buffer and old atom class memory->sfree(buf); delete old; // check that all atoms were assigned to procs bigint natoms; bigint nblocal = atom->nlocal; - MPI_Allreduce(&nblocal,&natoms,1,MPI_UNSIGNED_LONG_LONG,MPI_SUM,world); + MPI_Allreduce(&nblocal,&natoms,1,MPI_LMP_BIGINT,MPI_SUM,world); if (me == 0) { - if (screen) fprintf(screen," %lu atoms\n",natoms); - if (logfile) fprintf(logfile," %lu atoms\n",natoms); + char str[32]; + sprintf(str," %s atoms\n",BIGINT_FORMAT); + if (screen) fprintf(screen,str,natoms); + if (logfile) fprintf(logfile,str,natoms); } if (natoms != atom->natoms) error->all("Replicate did not assign all atoms correctly"); if (me == 0) { if (atom->nbonds) { - if (screen) fprintf(screen," %lu bonds\n",atom->nbonds); - if (logfile) fprintf(logfile," %lu bonds\n",atom->nbonds); + char str[32]; + sprintf(str," %s bonds\n",BIGINT_FORMAT); + if (screen) fprintf(screen,str,atom->nbonds); + if (logfile) fprintf(logfile,str,atom->nbonds); } if (atom->nangles) { - if (screen) fprintf(screen," %lu angles\n",atom->nangles); - if (logfile) fprintf(logfile," %lu angles\n",atom->nangles); + char str[32]; + sprintf(str," %s angles\n",BIGINT_FORMAT); + if (screen) fprintf(screen,str,atom->nangles); + if (logfile) fprintf(logfile,str,atom->nangles); } if (atom->ndihedrals) { - if (screen) fprintf(screen," %lu dihedrals\n",atom->ndihedrals); - if (logfile) fprintf(logfile," %lu dihedrals\n",atom->ndihedrals); + char str[32]; + sprintf(str," %s dihedrals\n",BIGINT_FORMAT); + if (screen) fprintf(screen,str,atom->ndihedrals); + if (logfile) fprintf(logfile,str,atom->ndihedrals); } if (atom->nimpropers) { - if (screen) fprintf(screen," %lu impropers\n",atom->nimpropers); - if (logfile) fprintf(logfile," %lu impropers\n",atom->nimpropers); + char str[32]; + sprintf(str," %s impropers\n",BIGINT_FORMAT); + if (screen) fprintf(screen,str,atom->nimpropers); + if (logfile) fprintf(logfile,str,atom->nimpropers); } } // create global mapping and bond topology now that system is defined if (atom->map_style) { atom->nghost = 0; atom->map_init(); atom->map_set(); } if (atom->molecular) { Special special(lmp); special.build(); } } diff --git a/src/respa.cpp b/src/respa.cpp index 209c7dd16..cb3425b13 100644 --- a/src/respa.cpp +++ b/src/respa.cpp @@ -1,680 +1,680 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain 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 "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_respa.h" #include "memory.h" #include "timer.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("Illegal run_style respa command"); nlevels = atoi(arg[0]); if (nlevels < 1) error->all("Respa levels must be >= 1"); if (narg < nlevels) error->all("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("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("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("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("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("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("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("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("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("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("Illegal run_style respa command"); level_kspace = atoi(arg[iarg+1]) - 1; iarg += 2; } else error->all("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("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("Must set both respa inner and outer"); // middle cannot be set without inner/outer if (level_middle >= 0 && level_inner == -1) error->all("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); 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); 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("Invalid order of forces within respa levels"); if (level_pair >= 0) { if (level_pair < level_improper || level_kspace < level_pair) error->all("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("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("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("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("Respa inner cutoffs are invalid"); if (level_middle >= 0 && (cutoff[3] < cutoff[2] || cutoff[2] < cutoff[1])) error->all("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() { // warn if no fixes if (modify->nfix == 0 && comm->me == 0) error->warning("No fixes defined, atoms won't move"); // 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("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(); // set flags for what arrays to clear in force_clear() // need to clear torques,erforce if arrays exists torqueflag = 0; if (atom->torque_flag) torqueflag = 1; erforceflag = 0; if (atom->erforce_flag) erforceflag = 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(); 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); 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_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_pair == ilevel && force->pair) force->pair->compute(eflag,vflag); if (level_inner == ilevel && force->pair) force->pair->compute_inner(); if (level_middle == ilevel && force->pair) force->pair->compute_middle(); if (level_outer == ilevel && force->pair) force->pair->compute_outer(eflag,vflag); if (level_kspace == ilevel && force->kspace) { force->kspace->setup(); force->kspace->compute(eflag,vflag); } if (newton[ilevel]) comm->reverse_comm(); copy_f_flevel(ilevel); } modify->setup(vflag); sum_flevel_f(); output->setup(1); 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) { 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); 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_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_pair == ilevel && force->pair) force->pair->compute(eflag,vflag); if (level_inner == ilevel && force->pair) force->pair->compute_inner(); if (level_middle == ilevel && force->pair) force->pair->compute_middle(); if (level_outer == ilevel && force->pair) force->pair->compute_outer(eflag,vflag); if (level_kspace == ilevel && force->kspace) { force->kspace->setup(); 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) { - int ntimestep; + bigint ntimestep; for (int i = 0; i < n; i++) { ntimestep = ++update->ntimestep; ev_set(ntimestep); recurse(nlevels-1); if (modify->n_end_of_step) modify->end_of_step(); if (ntimestep == output->next) { timer->stamp(); sum_flevel_f(); output->write(update->ntimestep); timer->stamp(TIME_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"); } /* ---------------------------------------------------------------------- */ 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++) { modify->initial_integrate_respa(vflag,ilevel,iloop); if (modify->n_post_integrate_respa) modify->post_integrate_respa(ilevel,iloop); 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) modify->pre_exchange(); if (triclinic) domain->x2lamda(atom->nlocal); domain->pbc(); if (domain->box_change) { domain->reset_box(); comm->setup(); if (neighbor->style) neighbor->setup_bins(); } timer->stamp(); comm->exchange(); if (atom->sortfreq > 0 && update->ntimestep >= atom->nextsort) atom->sort(); comm->borders(); if (triclinic) domain->lamda2x(atom->nlocal+atom->nghost); timer->stamp(TIME_COMM); if (modify->n_pre_neighbor) modify->pre_neighbor(); neighbor->build(); timer->stamp(TIME_NEIGHBOR); } } else if (ilevel == 0) { timer->stamp(); comm->forward_comm(); timer->stamp(TIME_COMM); } force_clear(newton[ilevel]); if (modify->n_pre_force_respa) modify->pre_force_respa(vflag,ilevel,iloop); timer->stamp(); if (level_bond == ilevel && force->bond) { force->bond->compute(eflag,vflag); timer->stamp(TIME_BOND); } if (level_angle == ilevel && force->angle) { force->angle->compute(eflag,vflag); timer->stamp(TIME_BOND); } if (level_dihedral == ilevel && force->dihedral) { force->dihedral->compute(eflag,vflag); timer->stamp(TIME_BOND); } if (level_improper == ilevel && force->improper) { force->improper->compute(eflag,vflag); timer->stamp(TIME_BOND); } if (level_pair == ilevel && force->pair) { force->pair->compute(eflag,vflag); timer->stamp(TIME_PAIR); } if (level_inner == ilevel && force->pair) { force->pair->compute_inner(); timer->stamp(TIME_PAIR); } if (level_middle == ilevel && force->pair) { force->pair->compute_middle(); timer->stamp(TIME_PAIR); } if (level_outer == ilevel && force->pair) { force->pair->compute_outer(eflag,vflag); timer->stamp(TIME_PAIR); } if (level_kspace == ilevel && force->kspace) { force->kspace->compute(eflag,vflag); timer->stamp(TIME_KSPACE); } if (newton[ilevel]) { comm->reverse_comm(); timer->stamp(TIME_COMM); } if (modify->n_post_force_respa) modify->post_force_respa(vflag,ilevel,iloop); modify->final_integrate_respa(ilevel,iloop); } copy_f_flevel(ilevel); } /* ---------------------------------------------------------------------- clear force on own & ghost atoms ------------------------------------------------------------------------- */ void Respa::force_clear(int newtonflag) { int i; // 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; 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; } } /* ---------------------------------------------------------------------- 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 042a28fce..b3d6cece7 100644 --- a/src/thermo.cpp +++ b/src/thermo.cpp @@ -1,1807 +1,1816 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ #include "mpi.h" #include "math.h" #include "stdlib.h" #include "string.h" #include "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 "memory.h" #include "error.h" using namespace LAMMPS_NS; // customize a new keyword by adding to this list: // step, elapsed, elaplong, dt, 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 // customize a new thermo style by adding a DEFINE to this list #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 MAXLINE 8192 // make this 4x longer than Input::MAXLINE #define DELTA 8 #define MIN(A,B) ((A) < (B)) ? (A) : (B) #define MAX(A,B) ((A) > (B)) ? (A) : (B) /* ---------------------------------------------------------------------- */ 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 line = new char[MAXLINE]; if (strcmp(style,"one") == 0) { strcpy(line,ONE); } else if (strcmp(style,"multi") == 0) { strcpy(line,MULTI); lineflag = MULTILINE; } else if (strcmp(style,"custom") == 0) { if (narg == 1) error->all("Illegal thermo style custom command"); line[0] = '\0'; for (int iarg = 1; iarg < narg; iarg++) { strcat(line,arg[iarg]); strcat(line," "); } line[strlen(line)-1] = '\0'; } else error->all("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 - format_multi = (char *) "---------------- Step %8d ----- " - "CPU = %11.4f (sec) ----------------"; + char *bigint_format = 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"; - format_bigint_one_def = (char *) "%8lu"; - format_bigint_multi_def = (char *) "%14lu"; + 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 int icompute; for (i = 0; i < ncompute; i++) { icompute = modify->find_compute(id_compute[i]); if (icompute < 0) error->all("Could not find thermo compute ID"); computes[i] = modify->compute[icompute]; } // 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("Could not find thermo fix ID"); fixes[i] = modify->fix[ifix]; if (output->thermo_every % fixes[i]->global_freq) error->all("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("Could not find thermo custom 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,line); if (logfile) fprintf(logfile,line); } } /* ---------------------------------------------------------------------- */ void Thermo::compute(int flag) { int i; firststep = flag; - int ntimestep = update->ntimestep; + 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 // which = 0 is global scalar, which = 1 is global vector 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(TIME_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); } } // kludge for RedStorm timing issue // if (ntimestep == 100) return; // print line to screen and logfile if (me == 0) { if (screen) fprintf(screen,line); if (logfile) { fprintf(logfile,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_UNSIGNED_LONG_LONG,MPI_SUM,world); + MPI_Allreduce(&nblocal,&ntotal,1,MPI_LMP_BIGINT,MPI_SUM,world); + if (ntotal < 0 || ntotal > MAXBIGINT) error->all("Too many total atoms"); if (ntotal == atom->natoms) return ntotal; // if not checking or already warned, just return if (lostflag == IGNORE) return ntotal; if (lostflag == WARN && lostbefore == 1) return ntotal; // error message if (lostflag == ERROR) { - char str[128]; - sprintf(str,"Lost atoms: original %lu current %lu",atom->natoms,ntotal); + char fstr[64],str[64]; + sprintf(fstr, + "Lost atoms: original %s current %s",BIGINT_FORMAT,BIGINT_FORMAT); + sprintf(str,fstr,atom->natoms,ntotal); error->all(str); } // warning message - char str[128]; - sprintf(str,"Lost atoms: original %lu current %lu",atom->natoms,ntotal); + char fstr[64],str[64]; + sprintf(fstr, + "Lost atoms: original %s current %s",BIGINT_FORMAT,BIGINT_FORMAT); + sprintf(str,fstr,atom->natoms,ntotal); if (me == 0) error->warning(str,0); lostbefore = 1; return ntotal; } /* ---------------------------------------------------------------------- modify thermo parameters ------------------------------------------------------------------------- */ void Thermo::modify_params(int narg, char **arg) { if (narg == 0) error->all("Illegal thermo_modify command"); modified = 1; int iarg = 0; while (iarg < narg) { if (strcmp(arg[iarg],"every") == 0) { if (iarg+2 > narg) error->all("Illegal thermo_modify command"); if (strstr(arg[iarg+1],"v_") == arg[iarg+1]) { delete [] output->var_thermo; int n = strlen(&arg[iarg+1][2]) + 1; output->var_thermo = new char[n]; strcpy(output->var_thermo,&arg[iarg+1][2]); } else error->all("Illegal thermo_modify command"); output->thermo_every = 0; iarg += 2; } else if (strcmp(arg[iarg],"temp") == 0) { if (iarg+2 > narg) error->all("Illegal thermo_modify command"); if (index_temp < 0) error->all("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("Could not find thermo_modify temperature ID"); temperature = modify->compute[icompute]; if (temperature->tempflag == 0) error->all("Thermo_modify temperature ID does not " "compute temperature"); if (temperature->igroup != 0 && comm->me == 0) error->warning("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("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("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("Illegal thermo_modify command"); if (index_press_scalar < 0 && index_press_vector < 0) error->all("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("Could not find thermo_modify pressure ID"); pressure = modify->compute[icompute]; if (pressure->pressflag == 0) error->all("Thermo_modify pressure ID does not compute pressure"); iarg += 2; } else if (strcmp(arg[iarg],"lost") == 0) { if (iarg+2 > narg) error->all("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("Illegal thermo_modify command"); iarg += 2; } else if (strcmp(arg[iarg],"norm") == 0) { if (iarg+2 > narg) error->all("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("Illegal thermo_modify command"); iarg += 2; } else if (strcmp(arg[iarg],"flush") == 0) { if (iarg+2 > narg) error->all("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("Illegal thermo_modify command"); iarg += 2; } else if (strcmp(arg[iarg],"line") == 0) { if (iarg+2 > narg) error->all("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("Illegal thermo_modify command"); iarg += 2; } else if (strcmp(arg[iarg],"format") == 0) { if (iarg+3 > narg) error->all("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) + 2; + n = strlen(format_int_user) + 3; format_bigint_user = new char[n]; char *ptr = strchr(format_int_user,'d'); if (ptr == NULL) error->all("Thermo_modify int format does not contain d character"); *ptr = '\0'; - sprintf(format_bigint_user,"%s%s%s",format_int_user,"lu",ptr+1); + 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("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("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,INT); + addfield("Step",&Thermo::compute_step,BIGINT); } else if (strcmp(word,"elapsed") == 0) { - addfield("Elapsed",&Thermo::compute_elapsed,INT); + addfield("Elapsed",&Thermo::compute_elapsed,BIGINT); } else if (strcmp(word,"elaplong") == 0) { - addfield("Elaplong",&Thermo::compute_elapsed_long,INT); + addfield("Elaplong",&Thermo::compute_elapsed_long,BIGINT); } else if (strcmp(word,"dt") == 0) { addfield("Dt",&Thermo::compute_dt,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("Thermo keyword requires lattice be defined"); addfield("Xlat",&Thermo::compute_xlat,FLOAT); } else if (strcmp(word,"ylat") == 0) { if (domain->lattice == NULL) error->all("Thermo keyword requires lattice be defined"); addfield("Ylat",&Thermo::compute_ylat,FLOAT); } else if (strcmp(word,"zlat") == 0) { if (domain->lattice == NULL) error->all("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); // 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("Could not find thermo custom compute ID"); if (argindex1[nfield] == 0 && modify->compute[n]->scalar_flag == 0) error->all("Thermo compute does not compute scalar"); if (argindex1[nfield] > 0 && argindex2[nfield] == 0) { if (modify->compute[n]->vector_flag == 0) error->all("Thermo compute does not compute vector"); if (argindex1[nfield] > modify->compute[n]->size_vector) error->all("Thermo compute vector is accessed out-of-range"); } if (argindex1[nfield] > 0 && argindex2[nfield] > 0) { if (modify->compute[n]->array_flag == 0) error->all("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("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("Could not find thermo custom fix ID"); if (argindex1[nfield] == 0 && modify->fix[n]->scalar_flag == 0) error->all("Thermo fix does not compute scalar"); if (argindex1[nfield] > 0 && argindex2[nfield] == 0) { if (modify->fix[n]->vector_flag == 0) error->all("Thermo fix does not compute vector"); if (argindex1[nfield] > modify->fix[n]->size_vector) error->all("Thermo fix vector is accessed out-of-range"); } if (argindex1[nfield] > 0 && argindex2[nfield] > 0) { if (modify->fix[n]->array_flag == 0) error->all("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("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("Could not find thermo custom variable name"); if (input->variable->equalstyle(n) == 0) error->all("Thermo custom variable is not equal-style variable"); if (argindex1[nfield]) error->all("Thermo custom variable cannot be indexed"); field2index[nfield] = add_variable(id); addfield(copy,&Thermo::compute_variable,FLOAT); } delete [] id; } else error->all("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) { // 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 = ivalue; } else if (strcmp(word,"elapsed") == 0) { if (update->whichflag == 0) error->all("This variable thermo keyword cannot be used between runs"); compute_elapsed(); dvalue = ivalue; } else if (strcmp(word,"elaplong") == 0) { if (update->whichflag == 0) error->all("This variable thermo keyword cannot be used between runs"); compute_elapsed_long(); dvalue = ivalue; } else if (strcmp(word,"dt") == 0) { compute_dt(); } else if (strcmp(word,"cpu") == 0) { if (update->whichflag == 0) error->all("This variable thermo keyword cannot be used between runs"); compute_cpu(); } else if (strcmp(word,"tpcpu") == 0) { if (update->whichflag == 0) error->all("This variable thermo keyword cannot be used between runs"); compute_tpcpu(); } else if (strcmp(word,"spcpu") == 0) { if (update->whichflag == 0) error->all("This variable thermo keyword cannot be used between runs"); compute_spcpu(); } else if (strcmp(word,"atoms") == 0) { compute_atoms(); } else if (strcmp(word,"temp") == 0) { if (!temperature) error->all("Thermo keyword in variable requires " "thermo to use/init temp"); if (update->whichflag == 0) { if (temperature->invoked_scalar != update->ntimestep) error->all("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("Thermo keyword in variable requires " "thermo to use/init press"); if (update->whichflag == 0) { if (pressure->invoked_scalar != update->ntimestep) error->all("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("Thermo keyword in variable requires thermo to use/init pe"); if (update->whichflag == 0) { if (pe->invoked_scalar != update->ntimestep) error->all("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("Thermo keyword in variable requires " "thermo to use/init temp"); if (update->whichflag == 0) { if (temperature->invoked_scalar != update->ntimestep) error->all("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("Thermo keyword in variable requires thermo to use/init pe"); if (update->whichflag == 0) { if (pe->invoked_scalar != update->ntimestep) error->all("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("Thermo keyword in variable requires " "thermo to use/init temp"); if (update->whichflag == 0) { if (temperature->invoked_scalar != update->ntimestep) error->all("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("Thermo keyword in variable requires thermo to use/init pe"); if (update->whichflag == 0) { if (pe->invoked_scalar != update->ntimestep) error->all("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("Thermo keyword in variable requires " "thermo to use/init temp"); if (update->whichflag == 0) { if (temperature->invoked_scalar != update->ntimestep) error->all("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("Thermo keyword in variable requires " "thermo to use/init press"); if (update->whichflag == 0) { if (pressure->invoked_scalar != update->ntimestep) error->all("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("Energy was not tallied on needed timestep"); if (!pe) error->all("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("Energy was not tallied on needed timestep"); if (!pe) error->all("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("Energy was not tallied on needed timestep"); if (!pe) error->all("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("Energy was not tallied on needed timestep"); if (!pe) error->all("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("Energy was not tallied on needed timestep"); if (!pe) error->all("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("Energy was not tallied on needed timestep"); if (!pe) error->all("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("Energy was not tallied on needed timestep"); if (!pe) error->all("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("Energy was not tallied on needed timestep"); if (!pe) error->all("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("Energy was not tallied on needed timestep"); if (!pe) error->all("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("Energy was not tallied on needed timestep"); if (!pe) error->all("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("Thermo keyword in variable requires lattice be defined"); compute_xlat(); } else if (strcmp(word,"ylat") == 0) { if (domain->lattice == NULL) error->all("Thermo keyword in variable requires lattice be defined"); compute_ylat(); } else if (strcmp(word,"zlat") == 0) { if (domain->lattice == NULL) error->all("Thermo keyword in variable requires lattice be defined"); compute_zlat(); } else if (strcmp(word,"pxx") == 0) { if (!pressure) error->all("Thermo keyword in variable requires " "thermo to use/init press"); if (update->whichflag == 0) { if (pressure->invoked_vector != update->ntimestep) error->all("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("Thermo keyword in variable requires " "thermo to use/init press"); if (update->whichflag == 0) { if (pressure->invoked_vector != update->ntimestep) error->all("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("Thermo keyword in variable requires " "thermo to use/init press"); if (update->whichflag == 0) { if (pressure->invoked_vector != update->ntimestep) error->all("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("Thermo keyword in variable requires " "thermo to use/init press"); if (update->whichflag == 0) { if (pressure->invoked_vector != update->ntimestep) error->all("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("Thermo keyword in variable requires " "thermo to use/init press"); if (update->whichflag == 0) { if (pressure->invoked_vector != update->ntimestep) error->all("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("Thermo keyword in variable requires " "thermo to use/init press"); if (update->whichflag == 0) { if (pressure->invoked_vector != update->ntimestep) error->all("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 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 if value is integer/double + set ivalue/dvalue/bivalue if value is int/double/bigint customize a new keyword by adding a method ------------------------------------------------------------------------- */ void Thermo::compute_step() { - ivalue = update->ntimestep; + bivalue = update->ntimestep; } /* ---------------------------------------------------------------------- */ void Thermo::compute_elapsed() { - ivalue = update->ntimestep - update->firststep; + bivalue = update->ntimestep - update->firststep; } /* ---------------------------------------------------------------------- */ void Thermo::compute_elapsed_long() { - ivalue = update->ntimestep - update->beginstep; + bivalue = update->ntimestep - update->beginstep; } /* ---------------------------------------------------------------------- */ void Thermo::compute_dt() { dvalue = update->dt; } /* ---------------------------------------------------------------------- */ void Thermo::compute_cpu() { if (firststep == 0) dvalue = 0.0; else dvalue = timer->elapsed(TIME_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(TIME_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(TIME_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 = 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); } diff --git a/src/thermo.h b/src/thermo.h index 526fcfa89..8b954ebb8 100644 --- a/src/thermo.h +++ b/src/thermo.h @@ -1,179 +1,179 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain 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" #include "lmptype.h" namespace LAMMPS_NS { class Thermo : protected Pointers { friend class WriteRestart; // 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 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: int me; char *line; int nfield,nfield_initial; char **keyword; int *vtype; char **format,**format_user; - char *format_multi; char *format_float_one_def,*format_float_multi_def; char *format_int_one_def,*format_int_multi_def; - char *format_bigint_one_def,*format_bigint_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; - int last_step; + bigint last_step; bigint natoms; // data used by routines that compute single values int ivalue; // integer value to print - double dvalue; // dvalue = double 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 if should call scalar() or vector() 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_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(); }; } #endif diff --git a/src/update.cpp b/src/update.cpp index 82b9cf886..a5a79bdb4 100644 --- a/src/update.cpp +++ b/src/update.cpp @@ -1,295 +1,296 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain 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 "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) { int n; char *str; ntimestep = 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"); str = (char *) "verlet"; n = strlen(str) + 1; integrate_style = new char[n]; strcpy(integrate_style,str); integrate = new Verlet(lmp,0,NULL); str = (char *) "cg"; n = strlen(str) + 1; minimize_style = new char[n]; strcpy(minimize_style,str); minimize = new MinCG(lmp); } /* ---------------------------------------------------------------------- */ Update::~Update() { delete [] unit_style; delete [] integrate_style; delete integrate; delete [] minimize_style; delete minimize; } /* ---------------------------------------------------------------------- */ void Update::init() { // 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->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; dt = 0.005; neighbor->skin = 0.3; } else if (strcmp(style,"real") == 0) { force->boltz = 0.0019872067; 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; dt = 1.0; neighbor->skin = 2.0; } else if (strcmp(style,"metal") == 0) { force->boltz = 8.617343e-5; 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; dt = 0.001; neighbor->skin = 2.0; } else if (strcmp(style,"si") == 0) { force->boltz = 1.3806504e-23; 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; dt = 1.0e-8; neighbor->skin = 0.001; } else if (strcmp(style,"cgs") == 0) { force->boltz = 1.3806504e-16; 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; dt = 1.0e-8; neighbor->skin = 0.1; } else if (strcmp(style,"electron") == 0) { force->boltz = 3.16679e-6; force->mvv2e = 1.0; force->ftm2v = 1 / 1.0327499; force->mv2d = 1.0; force->nktv2p = 2.9421e13; force->qqr2e = 1.0; force->qe2f = 1.0; force->vxmu2f = 0.6241509647; force->xxt2kmu = 1.0e-4; dt = 0.001; neighbor->skin = 2.0; } else error->all("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) { if (narg < 1) error->all("Illegal run_style command"); delete [] integrate_style; delete integrate; if (0) return; // dummy line to enable else-if macro expansion #define INTEGRATE_CLASS #define IntegrateStyle(key,Class) \ else if (strcmp(arg[0],#key) == 0) integrate = new Class(lmp,narg-1,&arg[1]); #include "style_integrate.h" #undef INTEGRATE_CLASS else error->all("Illegal run_style command"); int n = strlen(arg[0]) + 1; integrate_style = new char[n]; strcpy(integrate_style,arg[0]); } /* ---------------------------------------------------------------------- */ void Update::create_minimize(int narg, char **arg) { if (narg != 1) error->all("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("Illegal min_style command"); int n = strlen(arg[0]) + 1; minimize_style = new char[n]; strcpy(minimize_style,arg[0]); } /* ---------------------------------------------------------------------- reset timestep from input script do not allow dump files or a restart to be defined do not allow any timestep-dependent fixes to be defined do not allow any dynamic regions 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 ------------------------------------------------------------------------- */ void Update::reset_timestep(int narg, char **arg) { if (narg != 1) error->all("Illegal reset_timestep command"); for (int i = 0; i < output->ndump; i++) if (output->last_dump[i] >= 0) error->all("Cannot reset timestep with dump file already written to"); if (output->restart && output->last_restart >= 0) error->all("Cannot reset timestep with restart file already written"); for (int i = 0; i < modify->nfix; i++) if (modify->fix[i]->time_depend) error->all("Cannot reset timestep with a time-dependent fix defined"); for (int i = 0; i < domain->nregion; i++) if (domain->regions[i]->dynamic_check()) error->all("Cannot reset timestep with a dynamic region defined"); 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(); - ntimestep = atoi(arg[0]); + ntimestep = ATOBIGINT(arg[0]); if (ntimestep < 0) error->all("Timestep must be >= 0"); + if (ntimestep > MAXBIGINT) error->all("Too big a timestep"); } /* ---------------------------------------------------------------------- memory usage of update and integrate/minimize ------------------------------------------------------------------------- */ double Update::memory_usage() { double bytes = 0.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 43b7eb0ea..75edc7e2f 100644 --- a/src/update.h +++ b/src/update.h @@ -1,59 +1,60 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain 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" +#include "lmptype.h" namespace LAMMPS_NS { class Update : protected Pointers { public: double dt; // timestep double etol,ftol; // minimizer tolerances on energy/force - int ntimestep; // current step (dynamics or min iterations) + 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 - int firststep,laststep; // 1st & last step of this run - int beginstep,endstep; // 1st and last step of multiple runs + 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 - int eflag_global,eflag_atom; // timestep global/peratom eng is tallied on - int vflag_global,vflag_atom; // ditto for virial + 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 **); void create_minimize(int, char **); void reset_timestep(int, char **); double memory_usage(); }; } #endif diff --git a/src/velocity.cpp b/src/velocity.cpp index 0a9e944b0..4cadf22de 100644 --- a/src/velocity.cpp +++ b/src/velocity.cpp @@ -1,674 +1,674 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ #include "mpi.h" #include "math.h" #include "stdio.h" #include "stdlib.h" #include "string.h" #include "velocity.h" #include "lmptype.h" #include "atom.h" #include "update.h" #include "domain.h" #include "lattice.h" #include "force.h" #include "modify.h" #include "compute.h" #include "compute_temp.h" #include "random_park.h" #include "group.h" #include "comm.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; enum{CREATE,SET,SCALE,RAMP,ZERO}; enum{ALL,LOCAL,GEOM}; #define WARMUP 100 #define SMALL 0.001 #define MIN(a,b) ((a) < (b) ? (a) : (b)) #define MAX(a,b) ((a) > (b) ? (a) : (b)) /* ---------------------------------------------------------------------- */ Velocity::Velocity(LAMMPS *lmp) : Pointers(lmp) {} /* ---------------------------------------------------------------------- */ void Velocity::command(int narg, char **arg) { if (narg < 2) error->all("Illegal velocity command"); if (domain->box_exist == 0) error->all("Velocity command before simulation box is defined"); if (atom->natoms == 0) error->all("Velocity command with no atoms existing"); // atom masses must all be set atom->check_mass(); // identify group igroup = group->find(arg[0]); if (igroup == -1) error->all("Could not find velocity group ID"); groupbit = group->bitmask[igroup]; // identify style if (strcmp(arg[1],"create") == 0) style = CREATE; else if (strcmp(arg[1],"set") == 0) style = SET; else if (strcmp(arg[1],"scale") == 0) style = SCALE; else if (strcmp(arg[1],"ramp") == 0) style = RAMP; else if (strcmp(arg[1],"zero") == 0) style = ZERO; else error->all("Illegal velocity command"); // set defaults temperature = NULL; dist_flag = 0; sum_flag = 0; momentum_flag = 1; rotation_flag = 0; loop_flag = ALL; scale_flag = 1; // read options from end of input line // change defaults as options specify if (style == CREATE) options(narg-4,&arg[4]); else if (style == SET) options(narg-5,&arg[5]); else if (style == SCALE) options(narg-3,&arg[3]); else if (style == RAMP) options(narg-8,&arg[8]); else if (style == ZERO) options(narg-3,&arg[3]); // set scaling for SET and RAMP styles if (style == SET || style == RAMP) { if (scale_flag && domain->lattice == NULL) error->all("Use of velocity with undefined lattice"); if (scale_flag) { xscale = domain->lattice->xlattice; yscale = domain->lattice->ylattice; zscale = domain->lattice->zlattice; } else xscale = yscale = zscale = 1.0; } // initialize velocities based on style // create() invoked differently, so can be called externally if (style == CREATE) { double t_desired = atof(arg[2]); int seed = atoi(arg[3]); create(t_desired,seed); } else if (style == SET) set(narg-2,&arg[2]); else if (style == SCALE) scale(narg-2,&arg[2]); else if (style == RAMP) ramp(narg-2,&arg[2]); else if (style == ZERO) zero(narg-2,&arg[2]); } /* ---------------------------------------------------------------------- initialization of defaults before calling velocity methods externaly ------------------------------------------------------------------------- */ void Velocity::init_external(char *extgroup) { igroup = group->find(extgroup); if (igroup == -1) error->all("Could not find velocity group ID"); groupbit = group->bitmask[igroup]; temperature = NULL; dist_flag = 0; sum_flag = 0; momentum_flag = 1; rotation_flag = 0; loop_flag = ALL; scale_flag = 1; } /* ---------------------------------------------------------------------- */ void Velocity::create(double t_desired, int seed) { int i; if (seed <= 0) error->all("Illegal velocity create command"); // if temperature = NULL, create a new ComputeTemp with the velocity group int tflag = 0; if (temperature == NULL) { char **arg = new char*[3]; arg[0] = (char *) "velocity_temp"; arg[1] = group->names[igroup]; arg[2] = (char *) "temp"; temperature = new ComputeTemp(lmp,3,arg); tflag = 1; delete [] arg; } // initialize temperature computation // warn if groups don't match if (igroup != temperature->igroup && comm->me == 0) error->warning("Mismatch between velocity and compute groups"); temperature->init(); // store a copy of current velocities double **v = atom->v; int nlocal = atom->nlocal; double **vhold = memory->create_2d_double_array(nlocal,3,"velocity:vnew"); for (i = 0; i < nlocal; i++) { vhold[i][0] = v[i][0]; vhold[i][1] = v[i][1]; vhold[i][2] = v[i][2]; } // create new velocities, in uniform or gaussian distribution // loop option determines looping style, ALL is default // ALL = loop over all natoms, only set those I own via atom->map // cannot do this if atom IDs do not span 1-Natoms (some were deleted) // will produce same V, independent of P, if atoms were read-in // will NOT produce same V, independent of P, if used create_atoms // LOCAL = only loop over my atoms, adjust RNG to be proc-specific // will never produce same V, independent of P // GEOM = only loop over my atoms // choose RNG for each atom based on its xyz coord (geometry) // via random->reset() // will always produce same V, independent of P // adjust by factor for atom mass // for 2d, set Vz to 0.0 double *rmass = atom->rmass; double *mass = atom->mass; int *type = atom->type; int *mask = atom->mask; int dimension = domain->dimension; int m; double vx,vy,vz,factor; RanPark *random; if (loop_flag == ALL) { // create an atom map if one doesn't exist already int mapflag = 0; if (atom->map_style == 0) { mapflag = 1; atom->map_style = 1; atom->nghost = 0; atom->map_init(); atom->map_set(); } // error check - if (atom->natoms > MAXINT32) + if (atom->natoms > MAXSMALLINT) error->all("Too big a problem to use velocity create loop all"); if (atom->tag_enable == 0) error->all("Cannot use velocity create loop all unless atoms have IDs"); if (atom->tag_consecutive() == 0) error->all("Atom IDs must be consecutive for velocity create loop all"); // loop over all atoms in system // generate RNGs for all atoms, only assign to ones I own // use either per-type mass or per-atom rmass random = new RanPark(lmp,seed); int natoms = static_cast<int> (atom->natoms); for (i = 1; i <= natoms; i++) { if (dist_flag == 0) { vx = random->uniform(); vy = random->uniform(); vz = random->uniform(); } else { vx = random->gaussian(); vy = random->gaussian(); vz = random->gaussian(); } m = atom->map(i); if (m >= 0 && m < nlocal) { if (mask[m] & groupbit) { if (rmass) factor = 1.0/sqrt(rmass[m]); else factor = 1.0/sqrt(mass[type[m]]); v[m][0] = vx * factor; v[m][1] = vy * factor; if (dimension == 3) v[m][2] = vz * factor; else v[m][2] = 0.0; } } } // delete temporary atom map if (mapflag) { atom->map_delete(); atom->map_style = 0; } } else if (loop_flag == LOCAL) { random = new RanPark(lmp,seed + comm->me); for (i = 0; i < WARMUP; i++) random->uniform(); for (i = 0; i < nlocal; i++) { if (mask[i] & groupbit) { if (dist_flag == 0) { vx = random->uniform(); vy = random->uniform(); vz = random->uniform(); } else { vx = random->gaussian(); vy = random->gaussian(); vz = random->gaussian(); } if (rmass) factor = 1.0/sqrt(rmass[i]); else factor = 1.0/sqrt(mass[type[i]]); v[i][0] = vx * factor; v[i][1] = vy * factor; if (dimension == 3) v[i][2] = vz * factor; else v[i][2] = 0.0; } } } else if (loop_flag == GEOM) { random = new RanPark(lmp,1); double **x = atom->x; for (i = 0; i < nlocal; i++) { if (mask[i] & groupbit) { random->reset(seed,x[i]); if (dist_flag == 0) { vx = random->uniform(); vy = random->uniform(); vz = random->uniform(); } else { vx = random->gaussian(); vy = random->gaussian(); vz = random->gaussian(); } if (rmass) factor = 1.0/sqrt(rmass[i]); else factor = 1.0/sqrt(mass[type[i]]); v[i][0] = vx * factor; v[i][1] = vy * factor; if (dimension == 3) v[i][2] = vz * factor; else v[i][2] = 0.0; } } } // apply momentum and rotation zeroing if (momentum_flag) zero_momentum(); if (rotation_flag) zero_rotation(); // scale temp to desired value double t = temperature->compute_scalar(); rescale(t,t_desired); // if sum_flag set, add back in previous velocities if (sum_flag) { for (i = 0; i < nlocal; i++) { if (mask[i] & groupbit) { v[i][0] += vhold[i][0]; v[i][1] += vhold[i][1]; v[i][2] += vhold[i][2]; } } } // free local memory // if temperature was created, delete it memory->destroy_2d_double_array(vhold); delete random; if (tflag) delete temperature; } /* ---------------------------------------------------------------------- */ void Velocity::set(int narg, char **arg) { int xflag,yflag,zflag; double vx,vy,vz; if (strcmp(arg[0],"NULL") == 0) xflag = 0; else { xflag = 1; vx = xscale * atof(arg[0]); } if (strcmp(arg[1],"NULL") == 0) yflag = 0; else { yflag = 1; vy = yscale * atof(arg[1]); } if (strcmp(arg[2],"NULL") == 0) zflag = 0; else { zflag = 1; vz = zscale * atof(arg[2]); } double **v = atom->v; int *mask = atom->mask; int nlocal = atom->nlocal; int dimension = domain->dimension; for (int i = 0; i < nlocal; i++) { if (mask[i] & groupbit) { if (sum_flag == 0) { if (xflag) v[i][0] = vx; if (yflag) v[i][1] = vy; if (zflag && dimension == 3) v[i][2] = vz; } else { if (xflag) v[i][0] += vx; if (yflag) v[i][1] += vy; if (zflag && dimension == 3) v[i][2] += vz; } } } } /* ---------------------------------------------------------------------- rescale velocities of a group after computing its temperature ------------------------------------------------------------------------- */ void Velocity::scale(int narg, char **arg) { double t_desired = atof(arg[0]); // if temperature = NULL, create a new ComputeTemp with the velocity group int tflag = 0; if (temperature == NULL) { char **arg = new char*[3]; arg[0] = (char *) "velocity_temp"; arg[1] = group->names[igroup]; arg[2] = (char *) "temp"; temperature = new ComputeTemp(lmp,3,arg); tflag = 1; delete [] arg; } // initialize temperature computation // warn if groups don't match if (igroup != temperature->igroup && comm->me == 0) error->warning("Mismatch between velocity and compute groups"); temperature->init(); // scale temp to desired value double t = temperature->compute_scalar(); rescale(t,t_desired); // if temperature was created, delete it if (tflag) delete temperature; } /* ---------------------------------------------------------------------- apply a ramped set of velocities ------------------------------------------------------------------------- */ void Velocity::ramp(int narg, char **arg) { int v_dim; if (strcmp(arg[0],"vx") == 0) v_dim = 0; else if (strcmp(arg[0],"vy") == 0) v_dim = 1; else if (strcmp(arg[0],"vz") == 0) v_dim = 2; else error->all("Illegal velocity command"); if (v_dim == 2 && domain->dimension == 2) error->all("Velocity ramp in z for a 2d problem"); double v_lo,v_hi; if (v_dim == 0) { v_lo = xscale*atof(arg[1]); v_hi = xscale*atof(arg[2]); } else if (v_dim == 1) { v_lo = yscale*atof(arg[1]); v_hi = yscale*atof(arg[2]); } else if (v_dim == 2) { v_lo = zscale*atof(arg[1]); v_hi = zscale*atof(arg[2]); } int coord_dim; if (strcmp(arg[3],"x") == 0) coord_dim = 0; else if (strcmp(arg[3],"y") == 0) coord_dim = 1; else if (strcmp(arg[3],"z") == 0) coord_dim = 2; else error->all("Illegal velocity command"); double coord_lo,coord_hi; if (coord_dim == 0) { coord_lo = xscale*atof(arg[4]); coord_hi = xscale*atof(arg[5]); } else if (coord_dim == 1) { coord_lo = yscale*atof(arg[4]); coord_hi = yscale*atof(arg[5]); } else if (coord_dim == 2) { coord_lo = zscale*atof(arg[4]); coord_hi = zscale*atof(arg[5]); } // vramp = ramped velocity component for v_dim // add or set based on sum_flag double **x = atom->x; double **v = atom->v; int *mask = atom->mask; int nlocal = atom->nlocal; double fraction,vramp; for (int i = 0; i < nlocal; i++) if (mask[i] & groupbit) { fraction = (x[i][coord_dim] - coord_lo) / (coord_hi - coord_lo); fraction = MAX(fraction,0.0); fraction = MIN(fraction,1.0); vramp = v_lo + fraction*(v_hi - v_lo); if (sum_flag) v[i][v_dim] += vramp; else v[i][v_dim] = vramp; } } /* ---------------------------------------------------------------------- zero linear or angular momentum of a group ------------------------------------------------------------------------- */ void Velocity::zero(int narg, char **arg) { if (strcmp(arg[0],"linear") == 0) zero_momentum(); else if (strcmp(arg[0],"angular") == 0) zero_rotation(); else error->all("Illegal velocity command"); } /* ---------------------------------------------------------------------- rescale velocities of group atoms to t_new from t_old ------------------------------------------------------------------------- */ void Velocity::rescale(double t_old, double t_new) { if (t_old == 0.0) error->all("Attempting to rescale a 0.0 temperature"); double factor = sqrt(t_new/t_old); double **v = atom->v; int *mask = atom->mask; int nlocal = atom->nlocal; for (int i = 0; i < nlocal; i++) if (mask[i] & groupbit) { v[i][0] *= factor; v[i][1] *= factor; v[i][2] *= factor; } } /* ---------------------------------------------------------------------- zero the linear momentum of a group of atoms by adjusting v by -Vcm ------------------------------------------------------------------------- */ void Velocity::zero_momentum() { // cannot have 0 atoms in group if (group->count(igroup) == 0) error->all("Cannot zero momentum of 0 atoms"); // compute velocity of center-of-mass of group double masstotal = group->mass(igroup); double vcm[3]; group->vcm(igroup,masstotal,vcm); // adjust velocities by vcm to zero linear momentum double **v = atom->v; int *mask = atom->mask; int nlocal = atom->nlocal; for (int i = 0; i < nlocal; i++) if (mask[i] & groupbit) { v[i][0] -= vcm[0]; v[i][1] -= vcm[1]; v[i][2] -= vcm[2]; } } /* ---------------------------------------------------------------------- zero the angular momentum of a group of atoms by adjusting v by -(w x r) ------------------------------------------------------------------------- */ void Velocity::zero_rotation() { int i; // cannot have 0 atoms in group if (group->count(igroup) == 0) error->all("Cannot zero momentum of 0 atoms"); // compute omega (angular velocity) of group around center-of-mass double xcm[3],angmom[3],inertia[3][3],omega[3]; double masstotal = group->mass(igroup); group->xcm(igroup,masstotal,xcm); group->angmom(igroup,xcm,angmom); group->inertia(igroup,xcm,inertia); group->omega(angmom,inertia,omega); // adjust velocities to zero omega // vnew_i = v_i - w x r_i // must use unwrapped coords to compute r_i correctly double **x = atom->x; double **v = atom->v; int *mask = atom->mask; int *image = atom->image; int nlocal = atom->nlocal; int xbox,ybox,zbox; double dx,dy,dz; double xprd = domain->xprd; double yprd = domain->yprd; double zprd = domain->zprd; for (i = 0; i < nlocal; i++) if (mask[i] & groupbit) { xbox = (image[i] & 1023) - 512; ybox = (image[i] >> 10 & 1023) - 512; zbox = (image[i] >> 20) - 512; dx = (x[i][0] + xbox*xprd) - xcm[0]; dy = (x[i][1] + ybox*yprd) - xcm[1]; dz = (x[i][2] + zbox*zprd) - xcm[2]; v[i][0] -= omega[1]*dz - omega[2]*dy; v[i][1] -= omega[2]*dx - omega[0]*dz; v[i][2] -= omega[0]*dy - omega[1]*dx; } } /* ---------------------------------------------------------------------- parse optional parameters at end of velocity input line ------------------------------------------------------------------------- */ void Velocity::options(int narg, char **arg) { if (narg < 0) error->all("Illegal velocity command"); int iarg = 0; while (iarg < narg) { if (strcmp(arg[iarg],"dist") == 0) { if (iarg+2 > narg) error->all("Illegal velocity command"); if (strcmp(arg[iarg+1],"uniform") == 0) dist_flag = 0; else if (strcmp(arg[iarg+1],"gaussian") == 0) dist_flag = 1; else error->all("Illegal velocity command"); iarg += 2; } else if (strcmp(arg[iarg],"sum") == 0) { if (iarg+2 > narg) error->all("Illegal velocity command"); if (strcmp(arg[iarg+1],"no") == 0) sum_flag = 0; else if (strcmp(arg[iarg+1],"yes") == 0) sum_flag = 1; else error->all("Illegal velocity command"); iarg += 2; } else if (strcmp(arg[iarg],"mom") == 0) { if (iarg+2 > narg) error->all("Illegal velocity command"); if (strcmp(arg[iarg+1],"no") == 0) momentum_flag = 0; else if (strcmp(arg[iarg+1],"yes") == 0) momentum_flag = 1; else error->all("Illegal velocity command"); iarg += 2; } else if (strcmp(arg[iarg],"rot") == 0) { if (iarg+2 > narg) error->all("Illegal velocity command"); if (strcmp(arg[iarg+1],"no") == 0) rotation_flag = 0; else if (strcmp(arg[iarg+1],"yes") == 0) rotation_flag = 1; else error->all("Illegal velocity command"); iarg += 2; } else if (strcmp(arg[iarg],"temp") == 0) { if (iarg+2 > narg) error->all("Illegal velocity command"); int icompute; for (icompute = 0; icompute < modify->ncompute; icompute++) if (strcmp(arg[iarg+1],modify->compute[icompute]->id) == 0) break; if (icompute == modify->ncompute) error->all("Could not find velocity temperature ID"); temperature = modify->compute[icompute]; if (temperature->tempflag == 0) error->all("Velocity temperature ID does not compute temperature"); iarg += 2; } else if (strcmp(arg[iarg],"loop") == 0) { if (iarg+2 > narg) error->all("Illegal velocity command"); if (strcmp(arg[iarg+1],"all") == 0) loop_flag = ALL; else if (strcmp(arg[iarg+1],"local") == 0) loop_flag = LOCAL; else if (strcmp(arg[iarg+1],"geom") == 0) loop_flag = GEOM; else error->all("Illegal velocity command"); iarg += 2; } else if (strcmp(arg[iarg],"units") == 0) { if (iarg+2 > narg) error->all("Illegal velocity command"); if (strcmp(arg[iarg+1],"box") == 0) scale_flag = 0; else if (strcmp(arg[iarg+1],"lattice") == 0) scale_flag = 1; else error->all("Illegal velocity command"); iarg += 2; } else error->all("Illegal velocity command"); } } diff --git a/src/verlet.cpp b/src/verlet.cpp index c7a6180d6..0546e5557 100644 --- a/src/verlet.cpp +++ b/src/verlet.cpp @@ -1,389 +1,390 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ #include "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() { // warn if no fixes if (modify->nfix == 0 && comm->me == 0) error->warning("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_compute via sum over ghost atoms 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(); // set flags for what arrays to clear in force_clear() // need to clear torques,erforce if arrays exists torqueflag = 0; if (atom->torque_flag) torqueflag = 1; erforceflag = 0; if (atom->erforce_flag) erforceflag = 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(); 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); neighbor->build(); neighbor->ncalls = 0; // compute all forces ev_set(update->ntimestep); force_clear(); modify->setup_pre_force(vflag); if (force->pair) force->pair->compute(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(); force->kspace->compute(eflag,vflag); } if (force->newton) comm->reverse_comm(); modify->setup(vflag); output->setup(1); 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) { 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); neighbor->build(); neighbor->ncalls = 0; } // compute all forces ev_set(update->ntimestep); force_clear(); modify->setup_pre_force(vflag); if (force->pair) force->pair->compute(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(); force->kspace->compute(eflag,vflag); } if (force->newton) comm->reverse_comm(); modify->setup(vflag); update->setupflag = 0; } /* ---------------------------------------------------------------------- run for N steps ------------------------------------------------------------------------- */ void Verlet::run(int n) { - int nflag,ntimestep,sortflag; + 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 modify->initial_integrate(vflag); if (n_post_integrate) modify->post_integrate(); // regular communication vs neighbor list rebuild nflag = neighbor->decide(); if (nflag == 0) { timer->stamp(); comm->forward_comm(); timer->stamp(TIME_COMM); } else { if (n_pre_exchange) modify->pre_exchange(); if (triclinic) domain->x2lamda(atom->nlocal); domain->pbc(); if (domain->box_change) { domain->reset_box(); comm->setup(); if (neighbor->style) neighbor->setup_bins(); } timer->stamp(); comm->exchange(); if (sortflag && ntimestep >= atom->nextsort) atom->sort(); comm->borders(); if (triclinic) domain->lamda2x(atom->nlocal+atom->nghost); timer->stamp(TIME_COMM); if (n_pre_neighbor) modify->pre_neighbor(); neighbor->build(); timer->stamp(TIME_NEIGHBOR); } // force computations force_clear(); if (n_pre_force) modify->pre_force(vflag); timer->stamp(); if (force->pair) { force->pair->compute(eflag,vflag); timer->stamp(TIME_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(TIME_BOND); } if (force->kspace) { force->kspace->compute(eflag,vflag); timer->stamp(TIME_KSPACE); } // reverse communication of forces if (force->newton) { comm->reverse_comm(); timer->stamp(TIME_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(); // all output if (ntimestep == output->next) { timer->stamp(); output->write(ntimestep); timer->stamp(TIME_OUTPUT); } } } /* ---------------------------------------------------------------------- */ void Verlet::cleanup() { modify->post_run(); } /* ---------------------------------------------------------------------- clear force on own & ghost atoms setup and clear other arrays as needed ------------------------------------------------------------------------- */ void Verlet::force_clear() { int i; // clear force on all particles // if either newton flag is set, also include ghosts if (neighbor->includegroup == 0) { int nall; if (force->newton) nall = atom->nlocal + atom->nghost; else nall = atom->nlocal; 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; } // 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 (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; } } } } diff --git a/src/version.h b/src/version.h index 872b8d5aa..dbe555b16 100644 --- a/src/version.h +++ b/src/version.h @@ -1 +1 @@ -#define LAMMPS_VERSION "9 Jan 2011" +#define LAMMPS_VERSION "13 Jan 2011" diff --git a/src/write_restart.cpp b/src/write_restart.cpp index 25cba1c04..6fdb24998 100644 --- a/src/write_restart.cpp +++ b/src/write_restart.cpp @@ -1,498 +1,504 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ #include "mpi.h" #include "string.h" #include "write_restart.h" #include "lmptype.h" #include "atom.h" #include "atom_vec.h" #include "atom_vec_hybrid.h" #include "group.h" #include "force.h" #include "pair.h" #include "bond.h" #include "angle.h" #include "dihedral.h" #include "improper.h" #include "update.h" #include "domain.h" #include "modify.h" #include "universe.h" #include "comm.h" #include "output.h" #include "thermo.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; #define MIN(A,B) ((A) < (B)) ? (A) : (B) #define MAX(A,B) ((A) > (B)) ? (A) : (B) // same as read_restart.cpp and tools/restart2data.cpp -enum{VERSION,UNITS,NTIMESTEP,DIMENSION,NPROCS,PROCGRID_0,PROCGRID_1,PROCGRID_2, +enum{VERSION,SMALLINT,TAGINT,BIGINT, + UNITS,NTIMESTEP,DIMENSION,NPROCS,PROCGRID_0,PROCGRID_1,PROCGRID_2, NEWTON_PAIR,NEWTON_BOND,XPERIODIC,YPERIODIC,ZPERIODIC, BOUNDARY_00,BOUNDARY_01,BOUNDARY_10,BOUNDARY_11,BOUNDARY_20,BOUNDARY_21, ATOM_STYLE,NATOMS,NTYPES, NBONDS,NBONDTYPES,BOND_PER_ATOM, NANGLES,NANGLETYPES,ANGLE_PER_ATOM, NDIHEDRALS,NDIHEDRALTYPES,DIHEDRAL_PER_ATOM, NIMPROPERS,NIMPROPERTYPES,IMPROPER_PER_ATOM, BOXLO_0,BOXHI_0,BOXLO_1,BOXHI_1,BOXLO_2,BOXHI_2, SPECIAL_LJ_1,SPECIAL_LJ_2,SPECIAL_LJ_3, SPECIAL_COUL_1,SPECIAL_COUL_2,SPECIAL_COUL_3, XY,XZ,YZ}; enum{MASS,SHAPE,DIPOLE}; enum{PAIR,BOND,ANGLE,DIHEDRAL,IMPROPER}; enum{IGNORE,WARN,ERROR}; // same as thermo.cpp /* ---------------------------------------------------------------------- */ WriteRestart::WriteRestart(LAMMPS *lmp) : Pointers(lmp) { MPI_Comm_rank(world,&me); MPI_Comm_size(world,&nprocs); } /* ---------------------------------------------------------------------- called as write_restart command in input script ------------------------------------------------------------------------- */ void WriteRestart::command(int narg, char **arg) { if (domain->box_exist == 0) error->all("Write_restart command before simulation box is defined"); if (narg != 1) error->all("Illegal write_restart command"); // if filename contains a "*", replace with current timestep char *ptr; int n = strlen(arg[0]) + 16; char *file = new char[n]; if (ptr = strchr(arg[0],'*')) { *ptr = '\0'; - sprintf(file,"%s%d%s",arg[0],update->ntimestep,ptr+1); + char fstr[16]; + sprintf(fstr,"%%s%s%%s",BIGINT_FORMAT); + sprintf(file,fstr,arg[0],update->ntimestep,ptr+1); } else strcpy(file,arg[0]); // init entire system since comm->exchange is done // comm::init needs neighbor::init needs pair::init needs kspace::init, etc if (comm->me == 0 && screen) fprintf(screen,"System init for write_restart ...\n"); lmp->init(); // move atoms to new processors before writing file // enforce PBC before in case atoms are outside box // call borders() to rebuild atom map since exchange() destroys map if (domain->triclinic) domain->x2lamda(atom->nlocal); domain->pbc(); domain->reset_box(); comm->setup(); comm->exchange(); comm->borders(); if (domain->triclinic) domain->lamda2x(atom->nlocal+atom->nghost); write(file); delete [] file; } /* ---------------------------------------------------------------------- called from command() and directly from output within run/minimize loop file = final file name to write, except may contain a "%" ------------------------------------------------------------------------- */ void WriteRestart::write(char *file) { // natoms = sum of nlocal = value to write into restart file // if unequal and thermo lostflag is "error", don't write restart file bigint nblocal = atom->nlocal; - MPI_Allreduce(&nblocal,&natoms,1,MPI_UNSIGNED_LONG_LONG,MPI_SUM,world); + MPI_Allreduce(&nblocal,&natoms,1,MPI_LMP_BIGINT,MPI_SUM,world); if (natoms != atom->natoms && output->thermo->lostflag == ERROR) error->all("Atom count is inconsistent, cannot write restart file"); // check if filename contains "%" int multiproc; if (strchr(file,'%')) multiproc = 1; else multiproc = 0; // open single restart file or base file for multiproc case if (me == 0) { char *hfile; if (multiproc) { hfile = new char[strlen(file) + 16]; char *ptr = strchr(file,'%'); *ptr = '\0'; sprintf(hfile,"%s%s%s",file,"base",ptr+1); *ptr = '%'; } else hfile = file; fp = fopen(hfile,"wb"); if (fp == NULL) { char str[128]; sprintf(str,"Cannot open restart file %s",hfile); error->one(str); } if (multiproc) delete [] hfile; } // proc 0 writes header, groups, ntype-length arrays, force field // all procs write fix info if (me == 0) { header(); group->write_restart(fp); type_arrays(); force_fields(); } modify->write_restart(fp); // communication buffer for all my atom's info // max_size = largest buffer needed by any proc int max_size; int send_size = atom->avec->size_restart(); MPI_Allreduce(&send_size,&max_size,1,MPI_INT,MPI_MAX,world); double *buf; if (me == 0) buf = (double *) memory->smalloc(max_size*sizeof(double),"write_restart:buf"); else buf = (double *) memory->smalloc(send_size*sizeof(double),"write_restart:buf"); // pack my atom data into buf AtomVec *avec = atom->avec; int n = 0; for (int i = 0; i < atom->nlocal; i++) n += avec->pack_restart(i,&buf[n]); // if any fix requires it, remap each atom's coords via PBC // is because fix changes atom coords (excepting an integrate fix) // just remap in buffer, not actual atoms if (modify->restart_pbc_any) { int triclinic = domain->triclinic; double *lo,*hi,*period; if (triclinic == 0) { lo = domain->boxlo; hi = domain->boxhi; period = domain->prd; } else { lo = domain->boxlo_lamda; hi = domain->boxhi_lamda; period = domain->prd_lamda; } int xperiodic = domain->xperiodic; int yperiodic = domain->yperiodic; int zperiodic = domain->zperiodic; double *x; int m = 0; for (int i = 0; i < atom->nlocal; i++) { x = &buf[m+1]; if (triclinic) domain->x2lamda(x,x); if (xperiodic) { if (x[0] < lo[0]) x[0] += period[0]; if (x[0] >= hi[0]) x[0] -= period[0]; x[0] = MAX(x[0],lo[0]); } if (yperiodic) { if (x[1] < lo[1]) x[1] += period[1]; if (x[1] >= hi[1]) x[1] -= period[1]; x[1] = MAX(x[1],lo[1]); } if (zperiodic) { if (x[2] < lo[2]) x[2] += period[2]; if (x[2] >= hi[2]) x[2] -= period[2]; x[2] = MAX(x[2],lo[2]); } if (triclinic) domain->lamda2x(x,x); m += static_cast<int> (buf[m]); } } // if single file: // write one chunk of atoms per proc to file // proc 0 pings each proc, receives its chunk, writes to file // all other procs wait for ping, send their chunk to proc 0 // else if one file per proc: // each proc opens its own file and writes its chunk directly if (multiproc == 0) { int tmp,recv_size; MPI_Status status; MPI_Request request; if (me == 0) { for (int iproc = 0; iproc < nprocs; iproc++) { if (iproc) { MPI_Irecv(buf,max_size,MPI_DOUBLE,iproc,0,world,&request); MPI_Send(&tmp,0,MPI_INT,iproc,0,world); MPI_Wait(&request,&status); MPI_Get_count(&status,MPI_DOUBLE,&recv_size); } else recv_size = send_size; fwrite(&recv_size,sizeof(int),1,fp); fwrite(buf,sizeof(double),recv_size,fp); } fclose(fp); } else { MPI_Recv(&tmp,0,MPI_INT,0,0,world,&status); MPI_Rsend(buf,send_size,MPI_DOUBLE,0,0,world); } } else { if (me == 0) fclose(fp); char *perproc = new char[strlen(file) + 16]; char *ptr = strchr(file,'%'); *ptr = '\0'; sprintf(perproc,"%s%d%s",file,me,ptr+1); *ptr = '%'; fp = fopen(perproc,"wb"); if (fp == NULL) { char str[128]; sprintf(str,"Cannot open restart file %s",perproc); error->one(str); } delete [] perproc; fwrite(&send_size,sizeof(int),1,fp); fwrite(buf,sizeof(double),send_size,fp); fclose(fp); } memory->sfree(buf); } /* ---------------------------------------------------------------------- proc 0 writes out problem description ------------------------------------------------------------------------- */ void WriteRestart::header() { write_char(VERSION,universe->version); + write_int(SMALLINT,sizeof(smallint)); + write_int(TAGINT,sizeof(tagint)); + write_int(BIGINT,sizeof(bigint)); write_char(UNITS,update->unit_style); - write_int(NTIMESTEP,update->ntimestep); + write_bigint(NTIMESTEP,update->ntimestep); write_int(DIMENSION,domain->dimension); write_int(NPROCS,nprocs); write_int(PROCGRID_0,comm->procgrid[0]); write_int(PROCGRID_1,comm->procgrid[1]); write_int(PROCGRID_2,comm->procgrid[2]); write_int(NEWTON_PAIR,force->newton_pair); write_int(NEWTON_BOND,force->newton_bond); write_int(XPERIODIC,domain->xperiodic); write_int(YPERIODIC,domain->yperiodic); write_int(ZPERIODIC,domain->zperiodic); write_int(BOUNDARY_00,domain->boundary[0][0]); write_int(BOUNDARY_01,domain->boundary[0][1]); write_int(BOUNDARY_10,domain->boundary[1][0]); write_int(BOUNDARY_11,domain->boundary[1][1]); write_int(BOUNDARY_20,domain->boundary[2][0]); write_int(BOUNDARY_21,domain->boundary[2][1]); // atom_style must be written before atom class values // so read_restart can create class before reading class values // if style = hybrid, also write sub-class styles write_char(ATOM_STYLE,atom->atom_style); if (strcmp(atom->atom_style,"hybrid") == 0) { AtomVecHybrid *avec_hybrid = (AtomVecHybrid *) atom->avec; int nstyles = avec_hybrid->nstyles; char **keywords = avec_hybrid->keywords; fwrite(&nstyles,sizeof(int),1,fp); for (int i = 0; i < nstyles; i++) { int n = strlen(keywords[i]) + 1; fwrite(&n,sizeof(int),1,fp); fwrite(keywords[i],sizeof(char),n,fp); } } write_bigint(NATOMS,natoms); write_int(NTYPES,atom->ntypes); write_bigint(NBONDS,atom->nbonds); write_int(NBONDTYPES,atom->nbondtypes); write_int(BOND_PER_ATOM,atom->bond_per_atom); write_bigint(NANGLES,atom->nangles); write_int(NANGLETYPES,atom->nangletypes); write_int(ANGLE_PER_ATOM,atom->angle_per_atom); write_bigint(NDIHEDRALS,atom->ndihedrals); write_int(NDIHEDRALTYPES,atom->ndihedraltypes); write_int(DIHEDRAL_PER_ATOM,atom->dihedral_per_atom); write_bigint(NIMPROPERS,atom->nimpropers); write_int(NIMPROPERTYPES,atom->nimpropertypes); write_int(IMPROPER_PER_ATOM,atom->improper_per_atom); write_double(BOXLO_0,domain->boxlo[0]); write_double(BOXHI_0,domain->boxhi[0]); write_double(BOXLO_1,domain->boxlo[1]); write_double(BOXHI_1,domain->boxhi[1]); write_double(BOXLO_2,domain->boxlo[2]); write_double(BOXHI_2,domain->boxhi[2]); write_double(SPECIAL_LJ_1,force->special_lj[1]); write_double(SPECIAL_LJ_2,force->special_lj[2]); write_double(SPECIAL_LJ_3,force->special_lj[3]); write_double(SPECIAL_COUL_1,force->special_coul[1]); write_double(SPECIAL_COUL_2,force->special_coul[2]); write_double(SPECIAL_COUL_3,force->special_coul[3]); if (domain->triclinic) { write_double(XY,domain->xy); write_double(XZ,domain->xz); write_double(YZ,domain->yz); } // -1 flag signals end of header int flag = -1; fwrite(&flag,sizeof(int),1,fp); } /* ---------------------------------------------------------------------- proc 0 writes out any type-based arrays that are defined ------------------------------------------------------------------------- */ void WriteRestart::type_arrays() { if (atom->mass) { int flag = MASS; fwrite(&flag,sizeof(int),1,fp); fwrite(&atom->mass[1],sizeof(double),atom->ntypes,fp); } if (atom->shape) { int flag = SHAPE; fwrite(&flag,sizeof(int),1,fp); fwrite(&atom->shape[1][0],sizeof(double),atom->ntypes*3,fp); } if (atom->dipole) { int flag = DIPOLE; fwrite(&flag,sizeof(int),1,fp); fwrite(&atom->dipole[1],sizeof(double),atom->ntypes,fp); } // -1 flag signals end of type arrays int flag = -1; fwrite(&flag,sizeof(int),1,fp); } /* ---------------------------------------------------------------------- proc 0 writes out and force field styles and data that are defined ------------------------------------------------------------------------- */ void WriteRestart::force_fields() { if (force->pair) { int flag = PAIR; fwrite(&flag,sizeof(int),1,fp); int n = strlen(force->pair_style) + 1; fwrite(&n,sizeof(int),1,fp); fwrite(force->pair_style,sizeof(char),n,fp); force->pair->write_restart(fp); } if (atom->avec->bonds_allow && force->bond) { int flag = BOND; fwrite(&flag,sizeof(int),1,fp); int n = strlen(force->bond_style) + 1; fwrite(&n,sizeof(int),1,fp); fwrite(force->bond_style,sizeof(char),n,fp); force->bond->write_restart(fp); } if (atom->avec->angles_allow && force->angle) { int flag = ANGLE; fwrite(&flag,sizeof(int),1,fp); int n = strlen(force->angle_style) + 1; fwrite(&n,sizeof(int),1,fp); fwrite(force->angle_style,sizeof(char),n,fp); force->angle->write_restart(fp); } if (atom->avec->dihedrals_allow && force->dihedral) { int flag = DIHEDRAL; fwrite(&flag,sizeof(int),1,fp); int n = strlen(force->dihedral_style) + 1; fwrite(&n,sizeof(int),1,fp); fwrite(force->dihedral_style,sizeof(char),n,fp); force->dihedral->write_restart(fp); } if (atom->avec->impropers_allow && force->improper) { int flag = IMPROPER; fwrite(&flag,sizeof(int),1,fp); int n = strlen(force->improper_style) + 1; fwrite(&n,sizeof(int),1,fp); fwrite(force->improper_style,sizeof(char),n,fp); force->improper->write_restart(fp); } // -1 flag signals end of force field info int flag = -1; fwrite(&flag,sizeof(int),1,fp); } /* ---------------------------------------------------------------------- write a flag and an int into restart file ------------------------------------------------------------------------- */ void WriteRestart::write_int(int flag, int value) { fwrite(&flag,sizeof(int),1,fp); fwrite(&value,sizeof(int),1,fp); } /* ---------------------------------------------------------------------- write a flag and a double into restart file ------------------------------------------------------------------------- */ void WriteRestart::write_double(int flag, double value) { fwrite(&flag,sizeof(int),1,fp); fwrite(&value,sizeof(double),1,fp); } /* ---------------------------------------------------------------------- write a flag and a char str into restart file ------------------------------------------------------------------------- */ void WriteRestart::write_char(int flag, char *value) { fwrite(&flag,sizeof(int),1,fp); int n = strlen(value) + 1; fwrite(&n,sizeof(int),1,fp); fwrite(value,sizeof(char),n,fp); } /* ---------------------------------------------------------------------- write a flag and a bigint into restart file ------------------------------------------------------------------------- */ void WriteRestart::write_bigint(int flag, bigint value) { fwrite(&flag,sizeof(int),1,fp); fwrite(&value,sizeof(bigint),1,fp); } diff --git a/tools/binary2txt.cpp b/tools/binary2txt.cpp index aaa0b6cfb..e76db3c9f 100644 --- a/tools/binary2txt.cpp +++ b/tools/binary2txt.cpp @@ -1,135 +1,148 @@ /* ----------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator www.cs.sandia.gov/~sjplimp/lammps.html Steve Plimpton, sjplimp@sandia.gov, Sandia National Laboratories Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------ */ // Convert one or more LAMMPS binary dump files to ASCII text files // // this serial code must be compiled on a platform that can read the binary // dump files since binary formats are not compatible across all platforms // // Syntax: binary2txt file1 file2 ... // Creates: file1.txt file2.txt ... #include "stdio.h" #include "stdlib.h" #include "string.h" +// this should match setting in src/lmptype.h + +typedef int64_t bigint; + main(int narg, char **arg) { int i,j,k,m,n; - int ntimestep,natoms,size_one,nchunk,triclinic; + bigint ntimestep,natoms; + int size_one,nchunk,triclinic; double xlo,xhi,ylo,yhi,zlo,zhi,xy,xz,yz; int maxbuf = 0; double *buf = NULL; if (narg == 1) { printf("Syntax: binary2txt file1 file2 ...\n"); exit(1); } // loop over files for (int iarg = 1; iarg < narg; iarg++) { printf("%s:",arg[iarg]); fflush(stdout); FILE *fp = fopen(arg[iarg],"rb"); if (!fp) { printf("ERROR: Could not open %s\n",arg[iarg]); exit(1); } n = strlen(arg[iarg]) + 1 + 4; char *filetxt = new char[n]; strcpy(filetxt,arg[iarg]); strcat(filetxt,".txt"); FILE *fptxt = fopen(filetxt,"w"); delete [] filetxt; // loop over snapshots in file while (1) { - fread(&ntimestep,sizeof(int),1,fp); + fread(&ntimestep,sizeof(bigint),1,fp); // detect end-of-file if (feof(fp)) { fclose(fp); fclose(fptxt); break; } - fread(&natoms,sizeof(int),1,fp); + fread(&natoms,sizeof(bigint),1,fp); fread(&triclinic,sizeof(int),1,fp); fread(&xlo,sizeof(double),1,fp); fread(&xhi,sizeof(double),1,fp); fread(&ylo,sizeof(double),1,fp); fread(&yhi,sizeof(double),1,fp); fread(&zlo,sizeof(double),1,fp); fread(&zhi,sizeof(double),1,fp); if (triclinic) { fread(&xy,sizeof(double),1,fp); fread(&xz,sizeof(double),1,fp); fread(&yz,sizeof(double),1,fp); } fread(&size_one,sizeof(int),1,fp); fread(&nchunk,sizeof(int),1,fp); - fprintf(fptxt,"ITEM: TIMESTEP\n"); - fprintf(fptxt,"%d\n",ntimestep); - fprintf(fptxt,"ITEM: NUMBER OF ATOMS\n"); - fprintf(fptxt,"%d\n",natoms); + if (sizeof(bigint) == 8) { + fprintf(fptxt,"ITEM: TIMESTEP\n"); + fprintf(fptxt,"%ld\n",ntimestep); + fprintf(fptxt,"ITEM: NUMBER OF ATOMS\n"); + fprintf(fptxt,"%ld\n",natoms); + } else if (sizeof(bigint) == 4) { + fprintf(fptxt,"ITEM: TIMESTEP\n"); + fprintf(fptxt,"%d\n",ntimestep); + fprintf(fptxt,"ITEM: NUMBER OF ATOMS\n"); + fprintf(fptxt,"%d\n",natoms); + } if (!triclinic) { fprintf(fptxt,"ITEM: BOX BOUNDS\n"); fprintf(fptxt,"%g %g\n",xlo,xhi); fprintf(fptxt,"%g %g\n",ylo,yhi); fprintf(fptxt,"%g %g\n",zlo,zhi); } else { fprintf(fptxt,"ITEM: BOX BOUNDS xy xz yz\n"); fprintf(fptxt,"%g %g %g\n",xlo,xhi,xy); fprintf(fptxt,"%g %g %g\n",ylo,yhi,xz); fprintf(fptxt,"%g %g %g\n",zlo,zhi,yz); } fprintf(fptxt,"ITEM: ATOMS\n"); // loop over processor chunks in file for (i = 0; i < nchunk; i++) { fread(&n,sizeof(int),1,fp); // extend buffer to fit chunk size if (n > maxbuf) { if (buf) delete [] buf; buf = new double[n]; maxbuf = n; } // read chunk and write as size_one values per line fread(buf,sizeof(double),n,fp); n /= size_one; m = 0; for (j = 0; j < n; j++) { for (k = 0; k < size_one; k++) fprintf(fptxt,"%g ",buf[m++]); fprintf(fptxt,"\n"); } } - printf(" %d",ntimestep); + if (sizeof(bigint) == 8) printf(" %ld",ntimestep); + else if (sizeof(bigint) == 4) printf(" %d",ntimestep); fflush(stdout); } printf("\n"); } if (buf) delete [] buf; } diff --git a/tools/restart2data.cpp b/tools/restart2data.cpp index 594e4b62e..53b2df532 100644 --- a/tools/restart2data.cpp +++ b/tools/restart2data.cpp @@ -1,3495 +1,3544 @@ /* ----------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator www.cs.sandia.gov/~sjplimp/lammps.html Steve Plimpton, sjplimp@sandia.gov, Sandia National Laboratories Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------ */ // Convert a LAMMPS binary restart file into an ASCII text data file // // Syntax: restart2data restart-file data-file (input-file) // input-file is optional // if specified it will contain LAMMPS input script commands // for mass and force field info // only a few force field styles support this option // // this serial code must be compiled on a platform that can read the binary // restart file since binary formats are not compatible across all platforms // restart-file can have a '%' character to indicate a multiproc restart // file as written by LAMMPS #include "math.h" #include "stdio.h" #include "stdlib.h" #include "string.h" #include "stdint.h" #define MIN(a,b) ((a) < (b) ? (a) : (b)) #define MAX(a,b) ((a) > (b) ? (a) : (b)) #define MAX_GROUP 32 +// these should match settings in src/lmptype.h + +typedef int tagint; +typedef int64_t bigint; +#define BIGINT_FORMAT "%lld" + // same as write_restart.cpp -enum{VERSION,UNITS,NTIMESTEP,DIMENSION,NPROCS,PROCGRID_0,PROCGRID_1,PROCGRID_2, +enum{VERSION,SMALLINT,TAGINT,BIGINT, + UNITS,NTIMESTEP,DIMENSION,NPROCS,PROCGRID_0,PROCGRID_1,PROCGRID_2, NEWTON_PAIR,NEWTON_BOND,XPERIODIC,YPERIODIC,ZPERIODIC, BOUNDARY_00,BOUNDARY_01,BOUNDARY_10,BOUNDARY_11,BOUNDARY_20,BOUNDARY_21, ATOM_STYLE,NATOMS,NTYPES, NBONDS,NBONDTYPES,BOND_PER_ATOM, NANGLES,NANGLETYPES,ANGLE_PER_ATOM, NDIHEDRALS,NDIHEDRALTYPES,DIHEDRAL_PER_ATOM, NIMPROPERS,NIMPROPERTYPES,IMPROPER_PER_ATOM, BOXLO_0,BOXHI_0,BOXLO_1,BOXHI_1,BOXLO_2,BOXHI_2, SPECIAL_LJ_1,SPECIAL_LJ_2,SPECIAL_LJ_3, SPECIAL_COUL_1,SPECIAL_COUL_2,SPECIAL_COUL_3, XY,XZ,YZ}; enum{MASS,SHAPE,DIPOLE}; enum{PAIR,BOND,ANGLE,DIHEDRAL,IMPROPER}; static const char * const cg_type_list[] = {"none", "lj9_6", "lj12_4", "lj12_6"}; // --------------------------------------------------------------------- // Data class to hold problem // --------------------------------------------------------------------- class Data { public: // global settings char *version; - int ntimestep; + int size_smallint,size_tagint,size_bigint; + bigint ntimestep; int nprocs; char *unit_style; int dimension; int px,py,pz; int newton_pair,newton_bond; int xperiodic,yperiodic,zperiodic; int boundary[3][2]; char *atom_style; int style_angle,style_atomic,style_bond,style_charge,style_dipole; int style_ellipsoid,style_full,style_granular; int style_hybrid,style_molecular,style_peri; - uint64_t natoms; - uint64_t nbonds,nangles,ndihedrals,nimpropers; + bigint natoms; + bigint nbonds,nangles,ndihedrals,nimpropers; int ntypes,nbondtypes,nangletypes,ndihedraltypes,nimpropertypes; int bond_per_atom,angle_per_atom,dihedral_per_atom,improper_per_atom; int triclinic; double xlo,xhi,ylo,yhi,zlo,zhi,xy,xz,yz; double special_lj[4],special_coul[4]; double cut_lj_global,cut_coul_global,kappa; int offset_flag,mix_flag; // force fields char *pair_style,*bond_style,*angle_style,*dihedral_style,*improper_style; double *pair_born_A,*pair_born_rho,*pair_born_sigma; double *pair_born_C,*pair_born_D; double *pair_buck_A,*pair_buck_rho,*pair_buck_C; double *pair_colloid_A12,*pair_colloid_sigma; double *pair_colloid_d1,*pair_colloid_d2; double *pair_dipole_epsilon,*pair_dipole_sigma; double *pair_dpd_a0,*pair_dpd_gamma; double *pair_charmm_epsilon,*pair_charmm_sigma; double *pair_charmm_eps14,*pair_charmm_sigma14; double *pair_class2_epsilon,*pair_class2_sigma; double *pair_gb_epsilon,*pair_gb_sigma; double *pair_gb_epsa,*pair_gb_epsb,*pair_gb_epsc; double *pair_lj_epsilon,*pair_lj_sigma; double **pair_cg_epsilon,**pair_cg_sigma; int **pair_cg_cmm_type, **pair_setflag; double **pair_cut_coul, **pair_cut_lj; double *pair_ljexpand_epsilon,*pair_ljexpand_sigma,*pair_ljexpand_shift; double *pair_ljgromacs_epsilon,*pair_ljgromacs_sigma; double *pair_ljsmooth_epsilon,*pair_ljsmooth_sigma; double *pair_morse_d0,*pair_morse_alpha,*pair_morse_r0; double *pair_soft_A; double *pair_yukawa_A; double *bond_class2_r0,*bond_class2_k2,*bond_class2_k3,*bond_class2_k4; double *bond_fene_k,*bond_fene_r0,*bond_fene_epsilon,*bond_fene_sigma; double *bond_feneexpand_k,*bond_feneexpand_r0; double *bond_feneexpand_epsilon,*bond_feneexpand_sigma; double *bond_feneexpand_shift; double *bond_harmonic_k,*bond_harmonic_r0; double *bond_morse_d0,*bond_morse_alpha,*bond_morse_r0; double *bond_nonlinear_epsilon,*bond_nonlinear_r0,*bond_nonlinear_lamda; double *bond_quartic_k,*bond_quartic_b1,*bond_quartic_b2; double *bond_quartic_rc,*bond_quartic_u0; double *angle_charmm_k,*angle_charmm_theta0; double *angle_charmm_k_ub,*angle_charmm_r_ub; double *angle_class2_theta0; double *angle_class2_k2,*angle_class2_k3,*angle_class2_k4; double *angle_class2_bb_k,*angle_class2_bb_r1,*angle_class2_bb_r2; double *angle_class2_ba_k1,*angle_class2_ba_k2; double *angle_class2_ba_r1,*angle_class2_ba_r2; double *angle_cosine_k; double *angle_cosine_squared_k,*angle_cosine_squared_theta0; double *angle_harmonic_k,*angle_harmonic_theta0; double *angle_cg_cmm_epsilon,*angle_cg_cmm_sigma; int *angle_cg_cmm_type; double *dihedral_charmm_k,*dihedral_charmm_weight; int *dihedral_charmm_multiplicity,*dihedral_charmm_sign; double *dihedral_class2_k1,*dihedral_class2_k2,*dihedral_class2_k3; double *dihedral_class2_phi1,*dihedral_class2_phi2,*dihedral_class2_phi3; double *dihedral_class2_mbt_f1,*dihedral_class2_mbt_f2; double *dihedral_class2_mbt_f3,*dihedral_class2_mbt_r0; double *dihedral_class2_ebt_f1_1,*dihedral_class2_ebt_f2_1; double *dihedral_class2_ebt_f3_1,*dihedral_class2_ebt_r0_1; double *dihedral_class2_ebt_f1_2,*dihedral_class2_ebt_f2_2; double *dihedral_class2_ebt_f3_2,*dihedral_class2_ebt_r0_2; double *dihedral_class2_at_f1_1,*dihedral_class2_at_f2_1; double *dihedral_class2_at_f3_1,*dihedral_class2_at_theta0_1; double *dihedral_class2_at_f1_2,*dihedral_class2_at_f2_2; double *dihedral_class2_at_f3_2,*dihedral_class2_at_theta0_2; double *dihedral_class2_aat_k; double *dihedral_class2_aat_theta0_1,*dihedral_class2_aat_theta0_2; double *dihedral_class2_bb13_k; double *dihedral_class2_bb13_r10,*dihedral_class2_bb13_r30; double *dihedral_harmonic_k; int *dihedral_harmonic_multiplicity,*dihedral_harmonic_sign; double *dihedral_helix_aphi,*dihedral_helix_bphi,*dihedral_helix_cphi; double *dihedral_multi_a1,*dihedral_multi_a2,*dihedral_multi_a3; double *dihedral_multi_a4,*dihedral_multi_a5; double *dihedral_opls_k1,*dihedral_opls_k2; double *dihedral_opls_k3,*dihedral_opls_k4; double *improper_class2_k0,*improper_class2_chi0; double *improper_class2_aa_k1,*improper_class2_aa_k2,*improper_class2_aa_k3; double *improper_class2_aa_theta0_1,*improper_class2_aa_theta0_2; double *improper_class2_aa_theta0_3; double *improper_cvff_k; int *improper_cvff_sign,*improper_cvff_multiplicity; double *improper_harmonic_k,*improper_harmonic_chi; // atom quantities int iatoms,ibonds,iangles,idihedrals,iimpropers; double *mass,*shape,*dipole; double *x,*y,*z,*vx,*vy,*vz; double *omegax,*omegay,*omegaz; - int *tag,*type,*mask,*image; + tagint *tag; + int *type,*mask,*image; int *molecule; double *q,*mux,*muy,*muz,*radius,*density,*vfrac,*rmass; double *s0,*x0x,*x0y,*x0z; double *quatw,*quati,*quatj,*quatk,*angmomx,*angmomy,*angmomz; int *bond_type,*angle_type,*dihedral_type,*improper_type; int *bond_atom1,*bond_atom2; int *angle_atom1,*angle_atom2,*angle_atom3; int *dihedral_atom1,*dihedral_atom2,*dihedral_atom3,*dihedral_atom4; int *improper_atom1,*improper_atom2,*improper_atom3,*improper_atom4; // functions Data(); void stats(); void write(FILE *fp, FILE *fp2=NULL); void write_atom_angle(FILE *, int, int, int, int); void write_atom_atomic(FILE *, int, int, int, int); void write_atom_bond(FILE *, int, int, int, int); void write_atom_charge(FILE *, int, int, int, int); void write_atom_dipole(FILE *, int, int, int, int); void write_atom_ellipsoid(FILE *, int, int, int, int); void write_atom_full(FILE *, int, int, int, int); void write_atom_granular(FILE *, int, int, int, int); void write_atom_molecular(FILE *, int, int, int, int); void write_atom_peri(FILE *, int, int, int, int); void write_atom_angle_extra(FILE *, int); void write_atom_atomic_extra(FILE *, int); void write_atom_bond_extra(FILE *, int); void write_atom_charge_extra(FILE *, int); void write_atom_dipole_extra(FILE *, int); void write_atom_ellipsoid_extra(FILE *, int); void write_atom_full_extra(FILE *, int); void write_atom_granular_extra(FILE *, int); void write_atom_molecular_extra(FILE *, int); void write_atom_peri_extra(FILE *, int); void write_vel_angle(FILE *, int); void write_vel_atomic(FILE *, int); void write_vel_bond(FILE *, int); void write_vel_charge(FILE *, int); void write_vel_dipole(FILE *, int); void write_vel_ellipsoid(FILE *, int); void write_vel_full(FILE *, int); void write_vel_granular(FILE *, int); void write_vel_molecular(FILE *, int); void write_vel_peri(FILE *, int); void write_vel_angle_extra(FILE *, int); void write_vel_atomic_extra(FILE *, int); void write_vel_bond_extra(FILE *, int); void write_vel_charge_extra(FILE *, int); void write_vel_dipole_extra(FILE *, int); void write_vel_ellipsoid_extra(FILE *, int); void write_vel_full_extra(FILE *, int); void write_vel_granular_extra(FILE *, int); void write_vel_molecular_extra(FILE *, int); void write_vel_peri_extra(FILE *, int); }; // --------------------------------------------------------------------- // function prototypes // --------------------------------------------------------------------- void header(FILE *, Data &); void set_style(char *, Data &, int); void groups(FILE *); void type_arrays(FILE *, Data &); void force_fields(FILE *, Data &); void modify(FILE *); void pair(FILE *fp, Data &data, char *style, int flag); void bond(FILE *fp, Data &data); void angle(FILE *fp, Data &data); void dihedral(FILE *fp, Data &data); void improper(FILE *fp, Data &data); int atom(double *, Data &data); void allocate_angle(Data &data); void allocate_atomic(Data &data); void allocate_bond(Data &data); void allocate_charge(Data &data); void allocate_dipole(Data &data); void allocate_ellipsoid(Data &data); void allocate_full(Data &data); void allocate_granular(Data &data); void allocate_molecular(Data &data); void allocate_peri(Data &data); int atom_angle(double *, Data &, int); int atom_atomic(double *, Data &, int); int atom_bond(double *, Data &, int); int atom_charge(double *, Data &, int); int atom_dipole(double *, Data &, int); int atom_ellipsoid(double *, Data &, int); int atom_full(double *, Data &, int); int atom_granular(double *, Data &, int); int atom_molecular(double *, Data &, int); int atom_peri(double *, Data &, int); int read_int(FILE *fp); double read_double(FILE *fp); char *read_char(FILE *fp); -uint64_t read_uint64(FILE *fp); +bigint read_bigint(FILE *fp); // --------------------------------------------------------------------- // main program // --------------------------------------------------------------------- int main (int argc, char **argv) { // syntax error check if ((argc != 3) && (argc !=4)) { printf("Syntax: restart2data restart-file data-file (input-file)\n"); return 1; } // if restart file contains '%', file = filename with % replaced by "base" // else file = single file int multiproc; char *file,*ptr; if (ptr = strchr(argv[1],'%')) { multiproc = 1; file = new char[strlen(argv[1]) + 16]; *ptr = '\0'; sprintf(file,"%s%s%s",argv[1],"base",ptr+1); } else { multiproc = 0; file = argv[1]; } // open single restart file or base file for multiproc case printf("Reading restart file ...\n"); FILE *fp = fopen(file,"rb"); if (fp == NULL) { printf("ERROR: Cannot open restart file %s\n",file); return 1; } // read beginning of restart file Data data; header(fp,data); + if (data.size_smallint != sizeof(int) || + data.size_tagint != sizeof(tagint) || + data.size_bigint != sizeof(bigint)) { + printf("ERROR: Data type sizes in restart file " + "are incompatible with restart2data.cpp\n"); + return 1; + } + groups(fp); type_arrays(fp,data); force_fields(fp,data); modify(fp); // read atoms from single or multiple restart files double *buf = NULL; int n,m; int maxbuf = 0; data.iatoms = data.ibonds = data.iangles = data.idihedrals = data.iimpropers = 0; for (int iproc = 0; iproc < data.nprocs; iproc++) { if (multiproc) { fclose(fp); sprintf(file,"%s%d%s",argv[1],iproc,ptr+1); fp = fopen(file,"rb"); if (fp == NULL) { printf("ERROR: Cannot open restart file %s\n",file); return 1; } } n = read_int(fp); if (n > maxbuf) { maxbuf = n; delete [] buf; buf = new double[maxbuf]; } fread(buf,sizeof(double),n,fp); m = 0; while (m < n) m += atom(&buf[m],data); } fclose(fp); // print out stats data.stats(); // write out data file and no input file if (argc == 3) { printf("Writing data file ...\n"); fp = fopen(argv[2],"w"); if (fp == NULL) { printf("ERROR: Cannot open data file %s\n",argv[2]); return 1; } data.write(fp); fclose(fp); // write out data file and input file } else { printf("Writing data file ...\n"); fp = fopen(argv[2],"w"); if (fp == NULL) { printf("ERROR: Cannot open data file %s\n",argv[2]); return 1; } printf("Writing input file ...\n"); FILE *fp2 = fopen(argv[3],"w"); if (fp2 == NULL) { printf("ERROR: Cannot open input file %s\n",argv[3]); return 1; } data.write(fp,fp2); fclose(fp); fclose(fp2); } return 0; } // --------------------------------------------------------------------- // read header of restart file // --------------------------------------------------------------------- void header(FILE *fp, Data &data) { char *version = "6 Jan 2011"; data.triclinic = 0; int flag; flag = read_int(fp); while (flag >= 0) { if (flag == VERSION) { data.version = read_char(fp); if (strcmp(version,data.version) != 0) { char *str = "Restart file version does not match restart2data version"; printf("WARNING %s\n",str); printf(" restart2data version = %s\n",version); } } + else if (flag == SMALLINT) data.size_smallint = read_int(fp); + else if (flag == TAGINT) data.size_tagint = read_int(fp); + else if (flag == BIGINT) data.size_bigint = read_int(fp); else if (flag == UNITS) data.unit_style = read_char(fp); - else if (flag == NTIMESTEP) data.ntimestep = read_int(fp); + else if (flag == NTIMESTEP) data.ntimestep = read_bigint(fp); else if (flag == DIMENSION) data.dimension = read_int(fp); else if (flag == NPROCS) data.nprocs = read_int(fp); else if (flag == PROCGRID_0) data.px = read_int(fp); else if (flag == PROCGRID_1) data.py = read_int(fp); else if (flag == PROCGRID_2) data.pz = read_int(fp); else if (flag == NEWTON_PAIR) data.newton_pair = read_int(fp); else if (flag == NEWTON_BOND) data.newton_bond = read_int(fp); else if (flag == XPERIODIC) data.xperiodic = read_int(fp); else if (flag == YPERIODIC) data.yperiodic = read_int(fp); else if (flag == ZPERIODIC) data.zperiodic = read_int(fp); else if (flag == BOUNDARY_00) data.boundary[0][0] = read_int(fp); else if (flag == BOUNDARY_01) data.boundary[0][1] = read_int(fp); else if (flag == BOUNDARY_10) data.boundary[1][0] = read_int(fp); else if (flag == BOUNDARY_11) data.boundary[1][1] = read_int(fp); else if (flag == BOUNDARY_20) data.boundary[2][0] = read_int(fp); else if (flag == BOUNDARY_21) data.boundary[2][1] = read_int(fp); // if atom_style = hybrid: // set data_style_hybrid to # of sub-styles // read additional sub-class arguments // set sub-styles to 1 to N else if (flag == ATOM_STYLE) { data.style_angle = data.style_atomic = data.style_bond = data.style_charge = data.style_dipole = data.style_ellipsoid = data.style_full = data.style_granular = data.style_hybrid = data.style_molecular = data.style_peri = 0; data.atom_style = read_char(fp); set_style(data.atom_style,data,1); if (strcmp(data.atom_style,"hybrid") == 0) { int nwords = read_int(fp); set_style(data.atom_style,data,nwords); char *substyle; for (int i = 1; i <= nwords; i++) { substyle = read_char(fp); set_style(substyle,data,i); } } } - else if (flag == NATOMS) data.natoms = read_uint64(fp); + else if (flag == NATOMS) data.natoms = read_bigint(fp); else if (flag == NTYPES) data.ntypes = read_int(fp); - else if (flag == NBONDS) data.nbonds = read_uint64(fp); + else if (flag == NBONDS) data.nbonds = read_bigint(fp); else if (flag == NBONDTYPES) data.nbondtypes = read_int(fp); else if (flag == BOND_PER_ATOM) data.bond_per_atom = read_int(fp); - else if (flag == NANGLES) data.nangles = read_uint64(fp); + else if (flag == NANGLES) data.nangles = read_bigint(fp); else if (flag == NANGLETYPES) data.nangletypes = read_int(fp); else if (flag == ANGLE_PER_ATOM) data.angle_per_atom = read_int(fp); - else if (flag == NDIHEDRALS) data.ndihedrals = read_uint64(fp); + else if (flag == NDIHEDRALS) data.ndihedrals = read_bigint(fp); else if (flag == NDIHEDRALTYPES) data.ndihedraltypes = read_int(fp); else if (flag == DIHEDRAL_PER_ATOM) data.dihedral_per_atom = read_int(fp); - else if (flag == NIMPROPERS) data.nimpropers = read_uint64(fp); + else if (flag == NIMPROPERS) data.nimpropers = read_bigint(fp); else if (flag == NIMPROPERTYPES) data.nimpropertypes = read_int(fp); else if (flag == IMPROPER_PER_ATOM) data.improper_per_atom = read_int(fp); else if (flag == BOXLO_0) data.xlo = read_double(fp); else if (flag == BOXHI_0) data.xhi = read_double(fp); else if (flag == BOXLO_1) data.ylo = read_double(fp); else if (flag == BOXHI_1) data.yhi = read_double(fp); else if (flag == BOXLO_2) data.zlo = read_double(fp); else if (flag == BOXHI_2) data.zhi = read_double(fp); else if (flag == SPECIAL_LJ_1) data.special_lj[1] = read_double(fp); else if (flag == SPECIAL_LJ_2) data.special_lj[2] = read_double(fp); else if (flag == SPECIAL_LJ_3) data.special_lj[3] = read_double(fp); else if (flag == SPECIAL_COUL_1) data.special_coul[1] = read_double(fp); else if (flag == SPECIAL_COUL_2) data.special_coul[2] = read_double(fp); else if (flag == SPECIAL_COUL_3) data.special_coul[3] = read_double(fp); else if (flag == XY) { data.triclinic = 1; data.xy = read_double(fp); } else if (flag == XZ) { data.triclinic = 1; data.xz = read_double(fp); } else if (flag == YZ) { data.triclinic = 1; data.yz = read_double(fp); } else { printf("ERROR: Invalid flag in header section of restart file %d\n", flag); exit(1); } flag = read_int(fp); } } // --------------------------------------------------------------------- // set atom style to flag // --------------------------------------------------------------------- void set_style(char *name, Data &data, int flag) { if (strcmp(name,"angle") == 0) data.style_angle = flag; else if (strcmp(name,"atomic") == 0) data.style_atomic = flag; else if (strcmp(name,"bond") == 0) data.style_bond = flag; else if (strcmp(name,"charge") == 0) data.style_charge = flag; else if (strcmp(name,"dipole") == 0) data.style_dipole = flag; else if (strcmp(name,"ellipsoid") == 0) data.style_ellipsoid = flag; else if (strcmp(name,"full") == 0) data.style_full = flag; else if (strcmp(name,"granular") == 0) data.style_granular = flag; else if (strcmp(name,"hybrid") == 0) data.style_hybrid = flag; else if (strcmp(name,"molecular") == 0) data.style_molecular = flag; else if (strcmp(name,"peri") == 0) data.style_peri = flag; else { printf("ERROR: Unknown atom style %s\n",name); exit(1); } } // --------------------------------------------------------------------- // read group info from restart file, just ignore it // --------------------------------------------------------------------- void groups(FILE *fp) { int ngroup = read_int(fp); int n; char *name; // use count to not change restart format with deleted groups // remove this on next major release int count = 0; for (int i = 0; i < MAX_GROUP; i++) { name = read_char(fp); delete [] name; count++; if (count == ngroup) break; } } // --------------------------------------------------------------------- // read type arrays from restart file // --------------------------------------------------------------------- void type_arrays(FILE *fp, Data &data) { data.mass = NULL; data.shape = NULL; data.dipole = NULL; int flag; flag = read_int(fp); while (flag >= 0) { if (flag == MASS) { data.mass = new double[data.ntypes+1]; fread(&data.mass[1],sizeof(double),data.ntypes,fp); } else if (flag == SHAPE) { data.shape = new double[3*(data.ntypes+1)]; fread(&data.shape[3],sizeof(double),3*data.ntypes,fp); } else if (flag == DIPOLE) { data.dipole = new double[data.ntypes+1]; fread(&data.dipole[1],sizeof(double),data.ntypes,fp); } else { printf("ERROR: Invalid flag in type arrays section of restart file %d\n", flag); exit(1); } flag = read_int(fp); } } // --------------------------------------------------------------------- // read force-field info from restart file // --------------------------------------------------------------------- void force_fields(FILE *fp, Data &data) { data.pair_style = data.bond_style = data.angle_style = data.dihedral_style = data.improper_style = NULL; int flag; flag = read_int(fp); while (flag >= 0) { if (flag == PAIR) { data.pair_style = read_char(fp); pair(fp,data,data.pair_style,1); } else if (flag == BOND) { data.bond_style = read_char(fp); bond(fp,data); } else if (flag == ANGLE) { data.angle_style = read_char(fp); angle(fp,data); } else if (flag == DIHEDRAL) { data.dihedral_style = read_char(fp); dihedral(fp,data); } else if (flag == IMPROPER) { data.improper_style = read_char(fp); improper(fp,data); } else { printf("ERROR: Invalid flag in force fields section of restart file %d\n", flag); exit(1); } flag = read_int(fp); } } // --------------------------------------------------------------------- // read fix info from restart file, just ignore it // --------------------------------------------------------------------- void modify(FILE *fp) { char *buf; int n; // nfix = # of fix entries with state int nfix = read_int(fp); // read each entry with id string, style string, chunk of data for (int i = 0; i < nfix; i++) { buf = read_char(fp); delete [] buf; buf = read_char(fp); delete [] buf; buf = read_char(fp); delete [] buf; } // nfix = # of fix entries with peratom info int nfix_peratom = read_int(fp); // read each entry with id string, style string, maxsize of one atom data for (int i = 0; i < nfix_peratom; i++) { buf = read_char(fp); delete [] buf; buf = read_char(fp); delete [] buf; n = read_int(fp); } } // --------------------------------------------------------------------- // read atom info from restart file and store in data struct // --------------------------------------------------------------------- int atom(double *buf, Data &data) { // allocate per-atom arrays if (data.iatoms == 0) { // common to all atom styles data.x = new double[data.natoms]; data.y = new double[data.natoms]; data.z = new double[data.natoms]; data.tag = new int[data.natoms]; data.type = new int[data.natoms]; data.mask = new int[data.natoms]; data.image = new int[data.natoms]; data.vx = new double[data.natoms]; data.vy = new double[data.natoms]; data.vz = new double[data.natoms]; // style-specific arrays // don't worry about re-allocating if style = hybrid if (data.style_angle) allocate_angle(data); if (data.style_atomic) allocate_atomic(data); if (data.style_bond) allocate_bond(data); if (data.style_charge) allocate_charge(data); if (data.style_dipole) allocate_dipole(data); if (data.style_ellipsoid) allocate_ellipsoid(data); if (data.style_full) allocate_full(data); if (data.style_granular) allocate_granular(data); if (data.style_molecular) allocate_molecular(data); if (data.style_peri) allocate_peri(data); } // read atom quantities from buf // if hybrid, loop over all sub-styles in order listed // if hybrid, loop index k will match style setting to insure correct order int nloop = 1; if (data.style_hybrid) nloop = data.style_hybrid; int iatoms = data.iatoms; int m = 0; for (int k = 1; k <= nloop; k++) { if (k == data.style_angle) m += atom_angle(&buf[m],data,iatoms); if (k == data.style_atomic) m += atom_atomic(&buf[m],data,iatoms); if (k == data.style_bond) m += atom_bond(&buf[m],data,iatoms); if (k == data.style_charge) m += atom_charge(&buf[m],data,iatoms); if (k == data.style_dipole) m += atom_dipole(&buf[m],data,iatoms); if (k == data.style_ellipsoid) m += atom_ellipsoid(&buf[m],data,iatoms); if (k == data.style_full) m += atom_full(&buf[m],data,iatoms); if (k == data.style_granular) m += atom_granular(&buf[m],data,iatoms); if (k == data.style_molecular) m += atom_molecular(&buf[m],data,iatoms); if (k == data.style_peri) m += atom_peri(&buf[m],data,iatoms); } data.iatoms++; m = static_cast<int> (buf[0]); return m; } // --------------------------------------------------------------------- // read one atom's info from buffer // one routine per atom style // --------------------------------------------------------------------- int atom_angle(double *buf, Data &data, int iatoms) { int type,atom1,atom2,atom3; int m = 1; data.x[iatoms] = buf[m++]; data.y[iatoms] = buf[m++]; data.z[iatoms] = buf[m++]; data.tag[iatoms] = static_cast<int> (buf[m++]); data.type[iatoms] = static_cast<int> (buf[m++]); data.mask[iatoms] = static_cast<int> (buf[m++]); data.image[iatoms] = static_cast<int> (buf[m++]); data.vx[iatoms] = buf[m++]; data.vy[iatoms] = buf[m++]; data.vz[iatoms] = buf[m++]; data.molecule[iatoms] = static_cast<int> (buf[m++]); int n = static_cast<int> (buf[m++]); for (int k = 0; k < n; k++) { type = static_cast<int> (buf[m++]); atom1 = static_cast<int> (buf[m++]); if (data.newton_bond || data.tag[iatoms] < atom1) { data.bond_type[data.ibonds] = type; data.bond_atom1[data.ibonds] = data.tag[iatoms]; data.bond_atom2[data.ibonds] = atom1; data.ibonds++; } } n = static_cast<int> (buf[m++]); for (int k = 0; k < n; k++) { type = static_cast<int> (buf[m++]); atom1 = static_cast<int> (buf[m++]); atom2 = static_cast<int> (buf[m++]); atom3 = static_cast<int> (buf[m++]); if (data.newton_bond || data.tag[iatoms] == atom2) { data.angle_type[data.iangles] = type; data.angle_atom1[data.iangles] = atom1; data.angle_atom2[data.iangles] = atom2; data.angle_atom3[data.iangles] = atom3; data.iangles++; } } return m; } int atom_atomic(double *buf, Data &data, int iatoms) { int m = 1; data.x[iatoms] = buf[m++]; data.y[iatoms] = buf[m++]; data.z[iatoms] = buf[m++]; data.tag[iatoms] = static_cast<int> (buf[m++]); data.type[iatoms] = static_cast<int> (buf[m++]); data.mask[iatoms] = static_cast<int> (buf[m++]); data.image[iatoms] = static_cast<int> (buf[m++]); data.vx[iatoms] = buf[m++]; data.vy[iatoms] = buf[m++]; data.vz[iatoms] = buf[m++]; return m; } int atom_bond(double *buf, Data &data, int iatoms) { int type,atom1; int m = 1; data.x[iatoms] = buf[m++]; data.y[iatoms] = buf[m++]; data.z[iatoms] = buf[m++]; data.tag[iatoms] = static_cast<int> (buf[m++]); data.type[iatoms] = static_cast<int> (buf[m++]); data.mask[iatoms] = static_cast<int> (buf[m++]); data.image[iatoms] = static_cast<int> (buf[m++]); data.vx[iatoms] = buf[m++]; data.vy[iatoms] = buf[m++]; data.vz[iatoms] = buf[m++]; data.molecule[iatoms] = static_cast<int> (buf[m++]); int n = static_cast<int> (buf[m++]); for (int k = 0; k < n; k++) { type = static_cast<int> (buf[m++]); atom1 = static_cast<int> (buf[m++]); if (data.newton_bond || data.tag[iatoms] < atom1) { data.bond_type[data.ibonds] = type; data.bond_atom1[data.ibonds] = data.tag[iatoms]; data.bond_atom2[data.ibonds] = atom1; data.ibonds++; } } return m; } int atom_charge(double *buf, Data &data, int iatoms) { int m = 1; data.x[iatoms] = buf[m++]; data.y[iatoms] = buf[m++]; data.z[iatoms] = buf[m++]; data.tag[iatoms] = static_cast<int> (buf[m++]); data.type[iatoms] = static_cast<int> (buf[m++]); data.mask[iatoms] = static_cast<int> (buf[m++]); data.image[iatoms] = static_cast<int> (buf[m++]); data.vx[iatoms] = buf[m++]; data.vy[iatoms] = buf[m++]; data.vz[iatoms] = buf[m++]; data.q[iatoms] = buf[m++]; return m; } int atom_dipole(double *buf, Data &data, int iatoms) { int m = 1; data.x[iatoms] = buf[m++]; data.y[iatoms] = buf[m++]; data.z[iatoms] = buf[m++]; data.tag[iatoms] = static_cast<int> (buf[m++]); data.type[iatoms] = static_cast<int> (buf[m++]); data.mask[iatoms] = static_cast<int> (buf[m++]); data.image[iatoms] = static_cast<int> (buf[m++]); data.vx[iatoms] = buf[m++]; data.vy[iatoms] = buf[m++]; data.vz[iatoms] = buf[m++]; data.q[iatoms] = buf[m++]; data.mux[iatoms] = buf[m++]; data.muy[iatoms] = buf[m++]; data.muz[iatoms] = buf[m++]; return m; } int atom_ellipsoid(double *buf, Data &data, int iatoms) { int m = 1; data.x[iatoms] = buf[m++]; data.y[iatoms] = buf[m++]; data.z[iatoms] = buf[m++]; data.tag[iatoms] = static_cast<int> (buf[m++]); data.type[iatoms] = static_cast<int> (buf[m++]); data.mask[iatoms] = static_cast<int> (buf[m++]); data.image[iatoms] = static_cast<int> (buf[m++]); data.vx[iatoms] = buf[m++]; data.vy[iatoms] = buf[m++]; data.vz[iatoms] = buf[m++]; data.quatw[iatoms] = buf[m++]; data.quati[iatoms] = buf[m++]; data.quatj[iatoms] = buf[m++]; data.quatk[iatoms] = buf[m++]; data.angmomx[iatoms] = buf[m++]; data.angmomy[iatoms] = buf[m++]; data.angmomz[iatoms] = buf[m++]; return m; } int atom_granular(double *buf, Data &data, int iatoms) { int m = 1; data.x[iatoms] = buf[m++]; data.y[iatoms] = buf[m++]; data.z[iatoms] = buf[m++]; data.tag[iatoms] = static_cast<int> (buf[m++]); data.type[iatoms] = static_cast<int> (buf[m++]); data.mask[iatoms] = static_cast<int> (buf[m++]); data.image[iatoms] = static_cast<int> (buf[m++]); data.vx[iatoms] = buf[m++]; data.vy[iatoms] = buf[m++]; data.vz[iatoms] = buf[m++]; data.radius[iatoms] = buf[m++]; data.density[iatoms] = buf[m++]; data.omegax[iatoms] = buf[m++]; data.omegay[iatoms] = buf[m++]; data.omegaz[iatoms] = buf[m++]; return m; } int atom_full(double *buf, Data &data, int iatoms) { int type,atom1,atom2,atom3,atom4; int m = 1; data.x[iatoms] = buf[m++]; data.y[iatoms] = buf[m++]; data.z[iatoms] = buf[m++]; data.tag[iatoms] = static_cast<int> (buf[m++]); data.type[iatoms] = static_cast<int> (buf[m++]); data.mask[iatoms] = static_cast<int> (buf[m++]); data.image[iatoms] = static_cast<int> (buf[m++]); data.vx[iatoms] = buf[m++]; data.vy[iatoms] = buf[m++]; data.vz[iatoms] = buf[m++]; data.q[iatoms] = buf[m++]; data.molecule[iatoms] = static_cast<int> (buf[m++]); int n = static_cast<int> (buf[m++]); for (int k = 0; k < n; k++) { type = static_cast<int> (buf[m++]); atom1 = static_cast<int> (buf[m++]); if (data.newton_bond || data.tag[iatoms] < atom1) { data.bond_type[data.ibonds] = type; data.bond_atom1[data.ibonds] = data.tag[iatoms]; data.bond_atom2[data.ibonds] = atom1; data.ibonds++; } } n = static_cast<int> (buf[m++]); for (int k = 0; k < n; k++) { type = static_cast<int> (buf[m++]); atom1 = static_cast<int> (buf[m++]); atom2 = static_cast<int> (buf[m++]); atom3 = static_cast<int> (buf[m++]); if (data.newton_bond || data.tag[iatoms] == atom2) { data.angle_type[data.iangles] = type; data.angle_atom1[data.iangles] = atom1; data.angle_atom2[data.iangles] = atom2; data.angle_atom3[data.iangles] = atom3; data.iangles++; } } n = static_cast<int> (buf[m++]); for (int k = 0; k < n; k++) { type = static_cast<int> (buf[m++]); atom1 = static_cast<int> (buf[m++]); atom2 = static_cast<int> (buf[m++]); atom3 = static_cast<int> (buf[m++]); atom4 = static_cast<int> (buf[m++]); if (data.newton_bond || data.tag[iatoms] == atom2) { data.dihedral_type[data.idihedrals] = type; data.dihedral_atom1[data.idihedrals] = atom1; data.dihedral_atom2[data.idihedrals] = atom2; data.dihedral_atom3[data.idihedrals] = atom3; data.dihedral_atom4[data.idihedrals] = atom4; data.idihedrals++; } } n = static_cast<int> (buf[m++]); for (int k = 0; k < n; k++) { type = static_cast<int> (buf[m++]); atom1 = static_cast<int> (buf[m++]); atom2 = static_cast<int> (buf[m++]); atom3 = static_cast<int> (buf[m++]); atom4 = static_cast<int> (buf[m++]); if (data.newton_bond || data.tag[iatoms] == atom2) { data.improper_type[data.iimpropers] = type; data.improper_atom1[data.iimpropers] = atom1; data.improper_atom2[data.iimpropers] = atom2; data.improper_atom3[data.iimpropers] = atom3; data.improper_atom4[data.iimpropers] = atom4; data.iimpropers++; } } return m; } int atom_molecular(double *buf, Data &data, int iatoms) { int type,atom1,atom2,atom3,atom4; int m = 1; data.x[iatoms] = buf[m++]; data.y[iatoms] = buf[m++]; data.z[iatoms] = buf[m++]; data.tag[iatoms] = static_cast<int> (buf[m++]); data.type[iatoms] = static_cast<int> (buf[m++]); data.mask[iatoms] = static_cast<int> (buf[m++]); data.image[iatoms] = static_cast<int> (buf[m++]); data.vx[iatoms] = buf[m++]; data.vy[iatoms] = buf[m++]; data.vz[iatoms] = buf[m++]; data.molecule[iatoms] = static_cast<int> (buf[m++]); int n = static_cast<int> (buf[m++]); for (int k = 0; k < n; k++) { type = static_cast<int> (buf[m++]); atom1 = static_cast<int> (buf[m++]); if (data.newton_bond || data.tag[iatoms] < atom1) { data.bond_type[data.ibonds] = type; data.bond_atom1[data.ibonds] = data.tag[iatoms]; data.bond_atom2[data.ibonds] = atom1; data.ibonds++; } } n = static_cast<int> (buf[m++]); for (int k = 0; k < n; k++) { type = static_cast<int> (buf[m++]); atom1 = static_cast<int> (buf[m++]); atom2 = static_cast<int> (buf[m++]); atom3 = static_cast<int> (buf[m++]); if (data.newton_bond || data.tag[iatoms] == atom2) { data.angle_type[data.iangles] = type; data.angle_atom1[data.iangles] = atom1; data.angle_atom2[data.iangles] = atom2; data.angle_atom3[data.iangles] = atom3; data.iangles++; } } n = static_cast<int> (buf[m++]); for (int k = 0; k < n; k++) { type = static_cast<int> (buf[m++]); atom1 = static_cast<int> (buf[m++]); atom2 = static_cast<int> (buf[m++]); atom3 = static_cast<int> (buf[m++]); atom4 = static_cast<int> (buf[m++]); if (data.newton_bond || data.tag[iatoms] == atom2) { data.dihedral_type[data.idihedrals] = type; data.dihedral_atom1[data.idihedrals] = atom1; data.dihedral_atom2[data.idihedrals] = atom2; data.dihedral_atom3[data.idihedrals] = atom3; data.dihedral_atom4[data.idihedrals] = atom4; data.idihedrals++; } } n = static_cast<int> (buf[m++]); for (int k = 0; k < n; k++) { type = static_cast<int> (buf[m++]); atom1 = static_cast<int> (buf[m++]); atom2 = static_cast<int> (buf[m++]); atom3 = static_cast<int> (buf[m++]); atom4 = static_cast<int> (buf[m++]); if (data.newton_bond || data.tag[iatoms] == atom2) { data.improper_type[data.iimpropers] = type; data.improper_atom1[data.iimpropers] = atom1; data.improper_atom2[data.iimpropers] = atom2; data.improper_atom3[data.iimpropers] = atom3; data.improper_atom4[data.iimpropers] = atom4; data.iimpropers++; } } return m; } int atom_peri(double *buf, Data &data, int iatoms) { int m = 1; data.x[iatoms] = buf[m++]; data.y[iatoms] = buf[m++]; data.z[iatoms] = buf[m++]; data.tag[iatoms] = static_cast<int> (buf[m++]); data.type[iatoms] = static_cast<int> (buf[m++]); data.mask[iatoms] = static_cast<int> (buf[m++]); data.image[iatoms] = static_cast<int> (buf[m++]); data.vx[iatoms] = buf[m++]; data.vy[iatoms] = buf[m++]; data.vz[iatoms] = buf[m++]; data.vfrac[iatoms] = buf[m++]; data.density[iatoms] = buf[m++]; data.rmass[iatoms] = buf[m++]; data.s0[iatoms] = buf[m++]; data.x0x[iatoms] = buf[m++]; data.x0y[iatoms] = buf[m++]; data.x0z[iatoms] = buf[m++]; return m; } // --------------------------------------------------------------------- // per-atom memory allocation routines // one routine per atom style // --------------------------------------------------------------------- void allocate_angle(Data &data) { data.molecule = new int[data.natoms]; data.bond_type = new int[data.nbonds]; data.bond_atom1 = new int[data.nbonds]; data.bond_atom2 = new int[data.nbonds]; data.angle_type = new int[data.nangles]; data.angle_atom1 = new int[data.nangles]; data.angle_atom2 = new int[data.nangles]; data.angle_atom3 = new int[data.nangles]; } void allocate_atomic(Data &data) {} void allocate_bond(Data &data) { data.molecule = new int[data.natoms]; data.bond_type = new int[data.nbonds]; data.bond_atom1 = new int[data.nbonds]; data.bond_atom2 = new int[data.nbonds]; } void allocate_charge(Data &data) { data.q = new double[data.natoms]; } void allocate_dipole(Data &data) { data.q = new double[data.natoms]; data.mux = new double[data.natoms]; data.muy = new double[data.natoms]; data.muz = new double[data.natoms]; } void allocate_full(Data &data) { data.q = new double[data.natoms]; data.molecule = new int[data.natoms]; data.bond_type = new int[data.nbonds]; data.bond_atom1 = new int[data.nbonds]; data.bond_atom2 = new int[data.nbonds]; data.angle_type = new int[data.nangles]; data.angle_atom1 = new int[data.nangles]; data.angle_atom2 = new int[data.nangles]; data.angle_atom3 = new int[data.nangles]; data.dihedral_type = new int[data.ndihedrals]; data.dihedral_atom1 = new int[data.ndihedrals]; data.dihedral_atom2 = new int[data.ndihedrals]; data.dihedral_atom3 = new int[data.ndihedrals]; data.dihedral_atom4 = new int[data.ndihedrals]; data.improper_type = new int[data.nimpropers]; data.improper_atom1 = new int[data.nimpropers]; data.improper_atom2 = new int[data.nimpropers]; data.improper_atom3 = new int[data.nimpropers]; data.improper_atom4 = new int[data.nimpropers]; } void allocate_ellipsoid(Data &data) { data.quatw = new double[data.natoms]; data.quati = new double[data.natoms]; data.quatj = new double[data.natoms]; data.quatk = new double[data.natoms]; data.angmomx = new double[data.natoms]; data.angmomy = new double[data.natoms]; data.angmomz = new double[data.natoms]; } void allocate_granular(Data &data) { data.radius = new double[data.natoms]; data.density = new double[data.natoms]; data.omegax = new double[data.natoms]; data.omegay = new double[data.natoms]; data.omegaz = new double[data.natoms]; } void allocate_molecular(Data &data) { data.molecule = new int[data.natoms]; data.bond_type = new int[data.nbonds]; data.bond_atom1 = new int[data.nbonds]; data.bond_atom2 = new int[data.nbonds]; data.angle_type = new int[data.nangles]; data.angle_atom1 = new int[data.nangles]; data.angle_atom2 = new int[data.nangles]; data.angle_atom3 = new int[data.nangles]; data.dihedral_type = new int[data.ndihedrals]; data.dihedral_atom1 = new int[data.ndihedrals]; data.dihedral_atom2 = new int[data.ndihedrals]; data.dihedral_atom3 = new int[data.ndihedrals]; data.dihedral_atom4 = new int[data.ndihedrals]; data.improper_type = new int[data.nimpropers]; data.improper_atom1 = new int[data.nimpropers]; data.improper_atom2 = new int[data.nimpropers]; data.improper_atom3 = new int[data.nimpropers]; data.improper_atom4 = new int[data.nimpropers]; } void allocate_peri(Data &data) { data.vfrac = new double[data.natoms]; data.density = new double[data.natoms]; data.rmass = new double[data.natoms]; data.s0 = new double[data.natoms]; data.x0x = new double[data.natoms]; data.x0y = new double[data.natoms]; data.x0z = new double[data.natoms]; } // --------------------------------------------------------------------- // pair coeffs // one section for each pair style // flag = 1, read all coeff info and allocation arrays // flag = 0, just read global settings (when called recursively by hybrid) // --------------------------------------------------------------------- void pair(FILE *fp, Data &data, char *style, int flag) { int i,j,m; int itmp; double rtmp; if (strcmp(style,"none") == 0) { } else if (strcmp(style,"airebo") == 0) { } else if (strcmp(style,"born/coul/long") == 0) { double cut_lj_global = read_double(fp); double cut_coul = read_double(fp); int offset_flag = read_int(fp); int mix_flag = read_int(fp); if (!flag) return; data.pair_born_A = new double[data.ntypes+1]; data.pair_born_rho = new double[data.ntypes+1]; data.pair_born_sigma = new double[data.ntypes+1]; data.pair_born_C = new double[data.ntypes+1]; data.pair_born_D = new double[data.ntypes+1]; for (i = 1; i <= data.ntypes; i++) for (j = i; j <= data.ntypes; j++) { itmp = read_int(fp); if (i == j && itmp == 0) { printf("ERROR: Pair coeff %d,%d is not in restart file\n",i,j); exit(1); } if (itmp) { if (i == j) { data.pair_born_A[i] = read_double(fp); data.pair_born_rho[i] = read_double(fp); data.pair_born_sigma[i] = read_double(fp); data.pair_born_C[i] = read_double(fp); data.pair_born_D[i] = read_double(fp); double cut_lj = read_double(fp); } else { double born_A = read_double(fp); double born_rho = read_double(fp); double born_sigma = read_double(fp); double born_C = read_double(fp); double born_D = read_double(fp); double cut_lj = read_double(fp); } } } } else if ((strcmp(style,"buck") == 0) || (strcmp(style,"buck/coul/cut") == 0) || (strcmp(style,"buck/coul/long") == 0) || (strcmp(style,"buck/coul") == 0)) { if (strcmp(style,"buck") == 0) { m = 0; double cut_lj_global = read_double(fp); int offset_flag = read_int(fp); int mix_flag = read_int(fp); } else if (strcmp(style,"buck/coul/cut") == 0) { m = 1; double cut_lj_global = read_double(fp); double cut_lj_coul = read_double(fp); int offset_flag = read_int(fp); int mix_flag = read_int(fp); } else if (strcmp(style,"buck/coul/long") == 0) { m = 0; double cut_lj_global = read_double(fp); double cut_lj_coul = read_double(fp); int offset_flag = read_int(fp); int mix_flag = read_int(fp); } else if (strcmp(style,"buck/coul") == 0) { m = 0; double cut_buck_global = read_double(fp); double cut_coul = read_double(fp); int offset_flag = read_int(fp); int mix_flag = read_int(fp); int ewald_order = read_int(fp); } if (!flag) return; data.pair_buck_A = new double[data.ntypes+1]; data.pair_buck_rho = new double[data.ntypes+1]; data.pair_buck_C = new double[data.ntypes+1]; for (i = 1; i <= data.ntypes; i++) for (j = i; j <= data.ntypes; j++) { itmp = read_int(fp); if (i == j && itmp == 0) { printf("ERROR: Pair coeff %d,%d is not in restart file\n",i,j); exit(1); } if (itmp) { if (i == j) { data.pair_buck_A[i] = read_double(fp); data.pair_buck_rho[i] = read_double(fp); data.pair_buck_C[i] = read_double(fp); double cut_lj = read_double(fp); if (m) double cut_coul = read_double(fp); } else { double buck_A = read_double(fp); double buck_rho = read_double(fp); double buck_C = read_double(fp); double cut_lj = read_double(fp); if (m) double cut_coul = read_double(fp); } } } } else if (strcmp(style,"colloid") == 0) { double cut_global = read_double(fp); int offset_flag = read_int(fp); int mix_flag = read_int(fp); if (!flag) return; data.pair_colloid_A12 = new double[data.ntypes+1]; data.pair_colloid_sigma = new double[data.ntypes+1]; data.pair_colloid_d1 = new double[data.ntypes+1]; data.pair_colloid_d2 = new double[data.ntypes+1]; for (i = 1; i <= data.ntypes; i++) for (j = i; j <= data.ntypes; j++) { itmp = read_int(fp); if (i == j && itmp == 0) { printf("ERROR: Pair coeff %d,%d is not in restart file\n",i,j); exit(1); } if (itmp) { if (i == j) { data.pair_colloid_A12[i] = read_double(fp); data.pair_colloid_sigma[i] = read_double(fp); data.pair_colloid_d1[i] = read_double(fp); data.pair_colloid_d2[i] = read_double(fp); double cut_lj = read_double(fp); } else { double colloid_A12 = read_double(fp); double colloid_sigma = read_double(fp); double colloid_d1 = read_double(fp); double colloid_d2 = read_double(fp); double cut_lj = read_double(fp); } } } } else if ((strcmp(style,"coul/cut") == 0) || (strcmp(style,"coul/debye") == 0) || (strcmp(style,"coul/long") == 0)) { if (strcmp(style,"coul/cut") == 0) { double cut_coul = read_double(fp); int offset_flag = read_int(fp); int mix_flag = read_int(fp); } else if (strcmp(style,"coul/debye") == 0) { m = 1; double cut_coul = read_double(fp); double kappa = read_double(fp); int offset_flag = read_int(fp); int mix_flag = read_int(fp); } else if (strcmp(style,"coul/long") == 0) { double cut_coul = read_double(fp); int offset_flag = read_int(fp); int mix_flag = read_int(fp); } if (!flag) return; for (i = 1; i <= data.ntypes; i++) for (j = i; j <= data.ntypes; j++) { itmp = read_int(fp); if (i == j && itmp == 0) { printf("ERROR: Pair coeff %d,%d is not in restart file\n",i,j); exit(1); } if (itmp) { if (i == j) { double cut_coul = read_double(fp); } else { double cut_coul = read_double(fp); } } } } else if (strcmp(style,"dipole/cut") == 0) { double cut_lj_global = read_double(fp); double cut_coul_global = read_double(fp); int offset_flag = read_int(fp); int mix_flag = read_int(fp); if (!flag) return; data.pair_dipole_epsilon = new double[data.ntypes+1]; data.pair_dipole_sigma = new double[data.ntypes+1]; for (i = 1; i <= data.ntypes; i++) for (j = i; j <= data.ntypes; j++) { itmp = read_int(fp); if (i == j && itmp == 0) { printf("ERROR: Pair coeff %d,%d is not in restart file\n",i,j); exit(1); } if (itmp) { if (i == j) { data.pair_dipole_epsilon[i] = read_double(fp); data.pair_dipole_sigma[i] = read_double(fp); double cut_lj = read_double(fp); double cut_coul = read_double(fp); } else { double dipole_epsilon = read_double(fp); double dipole_sigma = read_double(fp); double cut_lj = read_double(fp); double cut_coul = read_double(fp); } } } } else if (strcmp(style,"dpd") == 0) { double temperature = read_double(fp); double cut_global = read_double(fp); int seed = read_int(fp); int mix_flag = read_int(fp); if (!flag) return; data.pair_dpd_a0 = new double[data.ntypes+1]; data.pair_dpd_gamma = new double[data.ntypes+1]; for (i = 1; i <= data.ntypes; i++) for (j = i; j <= data.ntypes; j++) { itmp = read_int(fp); if (i == j && itmp == 0) { printf("ERROR: Pair coeff %d,%d is not in restart file\n",i,j); exit(1); } if (itmp) { if (i == j) { data.pair_dpd_a0[i] = read_double(fp); data.pair_dpd_gamma[i] = read_double(fp); double cut = read_double(fp); } else { double dpd_a0 = read_double(fp); double dpd_gamma = read_double(fp); double cut = read_double(fp); } } } } else if (strcmp(style,"dpd/tstat") == 0) { double tstart = read_double(fp); double tstop = read_double(fp); double cut_global = read_double(fp); int seed = read_int(fp); int mix_flag = read_int(fp); if (!flag) return; data.pair_dpd_a0 = new double[data.ntypes+1]; data.pair_dpd_gamma = new double[data.ntypes+1]; for (i = 1; i <= data.ntypes; i++) for (j = i; j <= data.ntypes; j++) { itmp = read_int(fp); if (i == j && itmp == 0) { printf("ERROR: Pair coeff %d,%d is not in restart file\n",i,j); exit(1); } if (itmp) { if (i == j) { data.pair_dpd_a0[i] = read_double(fp); data.pair_dpd_gamma[i] = read_double(fp); double cut = read_double(fp); } else { double dpd_a0 = read_double(fp); double dpd_gamma = read_double(fp); double cut = read_double(fp); } } } } else if (strcmp(style,"eam") == 0) { } else if (strcmp(style,"eam/opt") == 0) { } else if (strcmp(style,"eam/alloy") == 0) { } else if (strcmp(style,"eam/alloy/opt") == 0) { } else if (strcmp(style,"eam/fs") == 0) { } else if (strcmp(style,"eam/fs/opt") == 0) { } else if (strcmp(style,"eim") == 0) { } else if (strcmp(style,"eff/cut") == 0) { double cut_coul = read_double(fp); int limit_size_flag = read_int(fp); int flexible_pressure_flag = read_int(fp); int offset_flag = read_int(fp); int mix_flag = read_int(fp); if (!flag) return; for (i = 1; i <= data.ntypes; i++) for (j = i; j <= data.ntypes; j++) { itmp = read_int(fp); if (i == j && itmp == 0) { printf("ERROR: Pair coeff %d,%d is not in restart file\n",i,j); exit(1); } if (itmp) { if (i == j) { double cut = read_double(fp); } else { double cut = read_double(fp); } } } } else if (strcmp(style,"gayberne") == 0) { double gamma = read_double(fp); double upsilon = read_double(fp); double mu = read_double(fp); double cut_global = read_double(fp); int offset_flag = read_int(fp); int mix_flag = read_int(fp); if (!flag) return; data.pair_gb_epsilon = new double[data.ntypes+1]; data.pair_gb_sigma = new double[data.ntypes+1]; data.pair_gb_epsa = new double[data.ntypes+1]; data.pair_gb_epsb = new double[data.ntypes+1]; data.pair_gb_epsc = new double[data.ntypes+1]; for (i = 1; i <= data.ntypes; i++) { itmp = read_int(fp); if (itmp) { data.pair_gb_epsa[i] = read_double(fp); data.pair_gb_epsb[i] = read_double(fp); data.pair_gb_epsc[i] = read_double(fp); data.pair_gb_epsa[i] = pow(data.pair_gb_epsa[i],-mu); data.pair_gb_epsb[i] = pow(data.pair_gb_epsb[i],-mu); data.pair_gb_epsc[i] = pow(data.pair_gb_epsc[i],-mu); } for (j = i; j <= data.ntypes; j++) { itmp = read_int(fp); if (i == j && itmp == 0) { printf("ERROR: Pair coeff %d,%d is not in restart file\n",i,j); exit(1); } if (itmp) { if (i == j) { data.pair_gb_epsilon[i] = read_double(fp); data.pair_gb_sigma[i] = read_double(fp); double cut = read_double(fp); } else { double gb_epsilon = read_double(fp); double gb_sigma = read_double(fp); double cut = read_double(fp); } } } } } else if ((strcmp(style,"gran/hooke") == 0) || (strcmp(style,"gran/hooke/history") == 0) || (strcmp(style,"gran/hertz/history") == 0)) { double kn = read_double(fp); double kt = read_double(fp); double gamman = read_double(fp); double gammat = read_double(fp); double xmu = read_double(fp); int dampflag = read_int(fp); } else if ((strcmp(style,"lj/charmm/coul/charmm") == 0) || (strcmp(style,"lj/charmm/coul/charmm/implicit") == 0) || (strcmp(style,"lj/charmm/coul/long") == 0) || (strcmp(style,"lj/charmm/coul/long/gpu") == 0) || (strcmp(style,"lj/charmm/coul/long/opt") == 0)) { if (strcmp(style,"lj/charmm/coul/charmm") == 0) { double cut_lj_inner = read_double(fp); double cut_lj = read_double(fp); double cut_coul_inner = read_double(fp); double cut_coul = read_double(fp); int offset_flag = read_int(fp); int mix_flag = read_int(fp); } else if (strcmp(style,"lj/charmm/coul/charmm/implicit") == 0) { double cut_lj_inner = read_double(fp); double cut_lj = read_double(fp); double cut_coul_inner = read_double(fp); double cut_coul = read_double(fp); int offset_flag = read_int(fp); int mix_flag = read_int(fp); } else if ((strcmp(style,"lj/charmm/coul/long") == 0) || (strcmp(style,"lj/charmm/coul/long/gpu") == 0) || (strcmp(style,"lj/charmm/coul/long/opt") == 0)) { double cut_lj_inner = read_double(fp); double cut_lj = read_double(fp); double cut_coul = read_double(fp); int offset_flag = read_int(fp); int mix_flag = read_int(fp); } if (!flag) return; data.pair_charmm_epsilon = new double[data.ntypes+1]; data.pair_charmm_sigma = new double[data.ntypes+1]; data.pair_charmm_eps14 = new double[data.ntypes+1]; data.pair_charmm_sigma14 = new double[data.ntypes+1]; for (i = 1; i <= data.ntypes; i++) for (j = i; j <= data.ntypes; j++) { itmp = read_int(fp); if (i == j && itmp == 0) { printf("ERROR: Pair coeff %d,%d is not in restart file\n",i,j); exit(1); } if (itmp) { if (i == j) { data.pair_charmm_epsilon[i] = read_double(fp); data.pair_charmm_sigma[i] = read_double(fp); data.pair_charmm_eps14[i] = read_double(fp); data.pair_charmm_sigma14[i] = read_double(fp); } else { double charmm_epsilon = read_double(fp); double charmm_sigma = read_double(fp); double charmm_eps14 = read_double(fp); double charmm_sigma14 = read_double(fp); } } } } else if ((strcmp(style,"lj/class2") == 0) || (strcmp(style,"lj/class2/coul/cut") == 0) || (strcmp(style,"lj/class2/coul/long") == 0)) { if (strcmp(style,"lj/class2") == 0) { m = 0; double cut_lj_global = read_double(fp); int offset_flag = read_int(fp); int mix_flag = read_int(fp); } else if (strcmp(style,"lj/class2/coul/cut") == 0) { m = 1; double cut_lj_global = read_double(fp); double cut_lj_coul = read_double(fp); int offset_flag = read_int(fp); int mix_flag = read_int(fp); } else if (strcmp(style,"lj/class2/coul/long") == 0) { m = 0; double cut_lj_global = read_double(fp); double cut_lj_coul = read_double(fp); int offset_flag = read_int(fp); int mix_flag = read_int(fp); } if (!flag) return; data.pair_class2_epsilon = new double[data.ntypes+1]; data.pair_class2_sigma = new double[data.ntypes+1]; for (i = 1; i <= data.ntypes; i++) for (j = i; j <= data.ntypes; j++) { itmp = read_int(fp); if (i == j && itmp == 0) { printf("ERROR: Pair coeff %d,%d is not in restart file\n",i,j); exit(1); } if (itmp) { if (i == j) { data.pair_class2_epsilon[i] = read_double(fp); data.pair_class2_sigma[i] = read_double(fp); double cut_lj = read_double(fp); if (m) double cut_coul = read_double(fp); } else { double class2_epsilon = read_double(fp); double class2_sigma = read_double(fp); double cut_lj = read_double(fp); if (m) double cut_coul = read_double(fp); } } } } else if ((strcmp(style,"lj/cut") == 0) || (strcmp(style,"lj/cut/gpu") == 0) || (strcmp(style,"lj/cut/opt") == 0) || (strcmp(style,"lj/cut/coul/cut") == 0) || (strcmp(style,"lj/cut/coul/cut/gpu") == 0) || (strcmp(style,"lj/cut/coul/debye") == 0) || (strcmp(style,"lj/cut/coul/long") == 0) || (strcmp(style,"lj/cut/coul/long/gpu") == 0) || (strcmp(style,"lj/cut/coul/long/tip4p") == 0) || (strcmp(style,"lj/coul") == 0)) { if ((strcmp(style,"lj/cut") == 0) || (strcmp(style,"lj/cut/gpu") == 0) || (strcmp(style,"lj/cut/opt") == 0)) { m = 0; double cut_lj_global = read_double(fp); int offset_flag = read_int(fp); int mix_flag = read_int(fp); } else if ((strcmp(style,"lj/cut/coul/cut") == 0) || (strcmp(style,"lj/cut/coul/cut/gpu") == 0)) { m = 1; double cut_lj_global = read_double(fp); double cut_lj_coul = read_double(fp); int offset_flag = read_int(fp); int mix_flag = read_int(fp); } else if (strcmp(style,"lj/cut/coul/debye") == 0) { m = 1; double cut_lj_global = read_double(fp); double cut_lj_coul = read_double(fp); double kappa = read_double(fp); int offset_flag = read_int(fp); int mix_flag = read_int(fp); } else if ((strcmp(style,"lj/cut/coul/long") == 0) || (strcmp(style,"lj/cut/coul/long/gpu") == 0)) { m = 0; double cut_lj_global = read_double(fp); double cut_lj_coul = read_double(fp); int offset_flag = read_int(fp); int mix_flag = read_int(fp); } else if (strcmp(style,"lj/cut/coul/long/tip4p") == 0) { m = 0; int typeO = read_int(fp); int typeH = read_int(fp); int typeB = read_int(fp); int typeA = read_int(fp); double qdist = read_double(fp); double cut_lj_global = read_double(fp); double cut_lj_coul = read_double(fp); int offset_flag = read_int(fp); int mix_flag = read_int(fp); } else if (strcmp(style,"lj/coul") == 0) { m = 0; double cut_lj_global = read_double(fp); double cut_coul = read_double(fp); int offset_flag = read_int(fp); int mix_flag = read_int(fp); int ewald_order = read_int(fp); } if (!flag) return; data.pair_lj_epsilon = new double[data.ntypes+1]; data.pair_lj_sigma = new double[data.ntypes+1]; for (i = 1; i <= data.ntypes; i++) for (j = i; j <= data.ntypes; j++) { itmp = read_int(fp); if (i == j && itmp == 0) { printf("ERROR: Pair coeff %d,%d is not in restart file\n",i,j); exit(1); } if (itmp) { if (i == j) { data.pair_lj_epsilon[i] = read_double(fp); data.pair_lj_sigma[i] = read_double(fp); double cut_lj = read_double(fp); if (m) double cut_coul = read_double(fp); } else { double lj_epsilon = read_double(fp); double lj_sigma = read_double(fp); double cut_lj = read_double(fp); if (m) double cut_coul = read_double(fp); } } } } else if (strcmp(style,"lj/expand") == 0) { double cut_global = read_double(fp); int offset_flag = read_int(fp); int mix_flag = read_int(fp); if (!flag) return; data.pair_ljexpand_epsilon = new double[data.ntypes+1]; data.pair_ljexpand_sigma = new double[data.ntypes+1]; data.pair_ljexpand_shift = new double[data.ntypes+1]; for (i = 1; i <= data.ntypes; i++) for (j = i; j <= data.ntypes; j++) { itmp = read_int(fp); if (i == j && itmp == 0) { printf("ERROR: Pair coeff %d,%d is not in restart file\n",i,j); exit(1); } if (itmp) { if (i == j) { data.pair_ljexpand_epsilon[i] = read_double(fp); data.pair_ljexpand_sigma[i] = read_double(fp); data.pair_ljexpand_shift[i] = read_double(fp); double cut_lj = read_double(fp); } else { double ljexpand_epsilon = read_double(fp); double ljexpand_sigma = read_double(fp); double ljexpand_shift = read_double(fp); double cut_lj = read_double(fp); } } } } else if ((strcmp(style,"lj/gromacs") == 0) || (strcmp(style,"lj/gromacs/coul/gromacs") == 0)) { if (strcmp(style,"lj/gromacs") == 0) { m = 1; double cut_inner_global = read_double(fp); double cut_global = read_double(fp); int offset_flag = read_int(fp); int mix_flag = read_int(fp); } else if (strcmp(style,"lj/gromacs/coul/gromacs") == 0) { m = 0; double cut_lj_inner_global = read_double(fp); double cut_lj = read_double(fp); double cut_coul_inner_global = read_double(fp); double cut_coul = read_double(fp); int offset_flag = read_int(fp); int mix_flag = read_int(fp); } if (!flag) return; data.pair_ljgromacs_epsilon = new double[data.ntypes+1]; data.pair_ljgromacs_sigma = new double[data.ntypes+1]; for (i = 1; i <= data.ntypes; i++) for (j = i; j <= data.ntypes; j++) { itmp = read_int(fp); if (i == j && itmp == 0) { printf("ERROR: Pair coeff %d,%d is not in restart file\n",i,j); exit(1); } if (itmp) { if (i == j) { data.pair_ljgromacs_epsilon[i] = read_double(fp); data.pair_ljgromacs_sigma[i] = read_double(fp); if (m) { double cut_inner = read_double(fp); double cut = read_double(fp); } } else { double ljgromacs_epsilon = read_double(fp); double ljgromacs_sigma = read_double(fp); if (m) { double cut_inner = read_double(fp); double cut = read_double(fp); } } } } } else if (strcmp(style,"lj/smooth") == 0) { double cut_inner_global = read_double(fp); double cut_global = read_double(fp); int offset_flag = read_int(fp); int mix_flag = read_int(fp); if (!flag) return; data.pair_ljsmooth_epsilon = new double[data.ntypes+1]; data.pair_ljsmooth_sigma = new double[data.ntypes+1]; for (i = 1; i <= data.ntypes; i++) for (j = i; j <= data.ntypes; j++) { itmp = read_int(fp); if (i == j && itmp == 0) { printf("ERROR: Pair coeff %d,%d is not in restart file\n",i,j); exit(1); } if (itmp) { if (i == j) { data.pair_ljsmooth_epsilon[i] = read_double(fp); data.pair_ljsmooth_sigma[i] = read_double(fp); double cut_inner = read_double(fp); double cut = read_double(fp); } else { double ljsmooth_epsilon = read_double(fp); double ljsmooth_sigma = read_double(fp); double cut_inner = read_double(fp); double cut = read_double(fp); } } } } else if (strcmp(style,"meam") == 0) { } else if ((strcmp(style,"morse") == 0) || (strcmp(style,"morse/opt") == 0)) { double cut_global = read_double(fp); int offset_flag = read_int(fp); int mix_flag = read_int(fp); if (!flag) return; data.pair_morse_d0 = new double[data.ntypes+1]; data.pair_morse_alpha = new double[data.ntypes+1]; data.pair_morse_r0 = new double[data.ntypes+1]; for (i = 1; i <= data.ntypes; i++) for (j = i; j <= data.ntypes; j++) { itmp = read_int(fp); if (i == j && itmp == 0) { printf("ERROR: Pair coeff %d,%d is not in restart file\n",i,j); exit(1); } if (itmp) { if (i == j) { data.pair_morse_d0[i] = read_double(fp); data.pair_morse_alpha[i] = read_double(fp); data.pair_morse_r0[i] = read_double(fp); double cut = read_double(fp); } else { double morse_d0 = read_double(fp); double morse_alpha = read_double(fp); double morse_r0 = read_double(fp); double cut = read_double(fp); } } } } else if (strcmp(style,"reax") == 0) { } else if (strcmp(style,"reax/c") == 0) { } else if (strcmp(style,"soft") == 0) { double cut_global = read_double(fp); int mix_flag = read_int(fp); if (!flag) return; data.pair_soft_A = new double[data.ntypes+1]; for (i = 1; i <= data.ntypes; i++) for (j = i; j <= data.ntypes; j++) { itmp = read_int(fp); if (i == j && itmp == 0) { printf("ERROR: Pair coeff %d,%d is not in restart file\n",i,j); exit(1); } if (itmp) { if (i == j) { data.pair_soft_A[i] = read_double(fp); double cut = read_double(fp); } else { double soft_A = read_double(fp); double cut = read_double(fp); } } } } else if (strcmp(style,"sw") == 0) { } else if (strcmp(style,"table") == 0) { int tabstyle = read_int(fp); int n = read_int(fp); } else if (strcmp(style,"tersoff") == 0) { } else if (strcmp(style,"tersoff/zbl") == 0) { } else if (strcmp(style,"yukawa") == 0) { double kappa = read_double(fp); double cut_global = read_double(fp); int offset_flag = read_int(fp); int mix_flag = read_int(fp); if (!flag) return; data.pair_yukawa_A = new double[data.ntypes+1]; for (i = 1; i <= data.ntypes; i++) for (j = i; j <= data.ntypes; j++) { itmp = read_int(fp); if (i == j && itmp == 0) { printf("ERROR: Pair coeff %d,%d is not in restart file\n",i,j); exit(1); } if (itmp) { if (i == j) { data.pair_yukawa_A[i] = read_double(fp); double cut = read_double(fp); } else { double yukawa_A = read_double(fp); double cut = read_double(fp); } } } } else if ((strcmp(style,"cg/cmm") == 0) || (strcmp(style,"cg/cmm/gpu") == 0) || (strcmp(style,"cg/cmm/coul/cut") == 0) || (strcmp(style,"cg/cmm/coul/long") == 0) || (strcmp(style,"cg/cmm/coul/long/gpu") == 0)) { m = 0; data.cut_lj_global = read_double(fp); data.cut_coul_global = read_double(fp); data.kappa = read_double(fp); data.offset_flag = read_int(fp); data.mix_flag = read_int(fp); if (!flag) return; const int numtyp=data.ntypes+1; data.pair_cg_cmm_type = new int*[numtyp]; data.pair_setflag = new int*[numtyp]; data.pair_cg_epsilon = new double*[numtyp]; data.pair_cg_sigma = new double*[numtyp]; data.pair_cut_lj = new double*[numtyp]; if ((strcmp(style,"cg/cmm/coul/cut") == 0) || (strcmp(style,"cg/cmm/coul/long") == 0) || (strcmp(style,"cg/cmm/coul/long/gpu") == 0)) { data.pair_cut_coul = new double*[numtyp]; m=1; } else { data.pair_cut_coul = NULL; m=0; } for (i = 1; i <= data.ntypes; i++) { data.pair_cg_cmm_type[i] = new int[numtyp]; data.pair_setflag[i] = new int[numtyp]; data.pair_cg_epsilon[i] = new double[numtyp]; data.pair_cg_sigma[i] = new double[numtyp]; data.pair_cut_lj[i] = new double[numtyp]; if ((strcmp(style,"cg/cmm/coul/cut") == 0) || (strcmp(style,"cg/cmm/coul/long") == 0) || (strcmp(style,"cg/cmm/coul/long/gpu") == 0)) { data.pair_cut_coul[i] = new double[numtyp]; } for (j = i; j <= data.ntypes; j++) { itmp = read_int(fp); data.pair_setflag[i][j] = itmp; if (i == j && itmp == 0) { printf("ERROR: Pair coeff %d,%d is not in restart file\n",i,j); exit(1); } if (itmp) { data.pair_cg_cmm_type[i][j] = read_int(fp); data.pair_cg_epsilon[i][j] = read_double(fp); data.pair_cg_sigma[i][j] = read_double(fp); data.pair_cut_lj[i][j] = read_double(fp); if (m) { data.pair_cut_lj[i][j] = read_double(fp); data.pair_cut_coul[i][j] = read_double(fp); } } } } } else if ((strcmp(style,"hybrid") == 0) || (strcmp(style,"hybrid/overlay") == 0)) { // for each substyle of hybrid, // read its settings by calling pair() recursively with flag = 0 // so that coeff array allocation is skipped int nstyles = read_int(fp); for (int i = 0; i < nstyles; i++) { char *substyle = read_char(fp); pair(fp,data,substyle,0); } } else { printf("ERROR: Unknown pair style %s\n",style); exit(1); } } // --------------------------------------------------------------------- // bond coeffs // one section for each bond style // --------------------------------------------------------------------- void bond(FILE *fp, Data &data) { if (strcmp(data.bond_style,"none") == 0) { } else if (strcmp(data.bond_style,"class2") == 0) { data.bond_class2_r0 = new double[data.nbondtypes+1]; data.bond_class2_k2 = new double[data.nbondtypes+1]; data.bond_class2_k3 = new double[data.nbondtypes+1]; data.bond_class2_k4 = new double[data.nbondtypes+1]; fread(&data.bond_class2_r0[1],sizeof(double),data.nbondtypes,fp); fread(&data.bond_class2_k2[1],sizeof(double),data.nbondtypes,fp); fread(&data.bond_class2_k3[1],sizeof(double),data.nbondtypes,fp); fread(&data.bond_class2_k4[1],sizeof(double),data.nbondtypes,fp); } else if (strcmp(data.bond_style,"fene") == 0) { data.bond_fene_k = new double[data.nbondtypes+1]; data.bond_fene_r0 = new double[data.nbondtypes+1]; data.bond_fene_epsilon = new double[data.nbondtypes+1]; data.bond_fene_sigma = new double[data.nbondtypes+1]; fread(&data.bond_fene_k[1],sizeof(double),data.nbondtypes,fp); fread(&data.bond_fene_r0[1],sizeof(double),data.nbondtypes,fp); fread(&data.bond_fene_epsilon[1],sizeof(double),data.nbondtypes,fp); fread(&data.bond_fene_sigma[1],sizeof(double),data.nbondtypes,fp); } else if (strcmp(data.bond_style,"fene/expand") == 0) { data.bond_feneexpand_k = new double[data.nbondtypes+1]; data.bond_feneexpand_r0 = new double[data.nbondtypes+1]; data.bond_feneexpand_epsilon = new double[data.nbondtypes+1]; data.bond_feneexpand_sigma = new double[data.nbondtypes+1]; data.bond_feneexpand_shift = new double[data.nbondtypes+1]; fread(&data.bond_feneexpand_k[1],sizeof(double),data.nbondtypes,fp); fread(&data.bond_feneexpand_r0[1],sizeof(double),data.nbondtypes,fp); fread(&data.bond_feneexpand_epsilon[1],sizeof(double),data.nbondtypes,fp); fread(&data.bond_feneexpand_sigma[1],sizeof(double),data.nbondtypes,fp); fread(&data.bond_feneexpand_shift[1],sizeof(double),data.nbondtypes,fp); } else if (strcmp(data.bond_style,"harmonic") == 0) { data.bond_harmonic_k = new double[data.nbondtypes+1]; data.bond_harmonic_r0 = new double[data.nbondtypes+1]; fread(&data.bond_harmonic_k[1],sizeof(double),data.nbondtypes,fp); fread(&data.bond_harmonic_r0[1],sizeof(double),data.nbondtypes,fp); } else if (strcmp(data.bond_style,"morse") == 0) { data.bond_morse_d0 = new double[data.nbondtypes+1]; data.bond_morse_alpha = new double[data.nbondtypes+1]; data.bond_morse_r0 = new double[data.nbondtypes+1]; fread(&data.bond_morse_d0[1],sizeof(double),data.nbondtypes,fp); fread(&data.bond_morse_alpha[1],sizeof(double),data.nbondtypes,fp); fread(&data.bond_morse_r0[1],sizeof(double),data.nbondtypes,fp); } else if (strcmp(data.bond_style,"nonlinear") == 0) { data.bond_nonlinear_epsilon = new double[data.nbondtypes+1]; data.bond_nonlinear_r0 = new double[data.nbondtypes+1]; data.bond_nonlinear_lamda = new double[data.nbondtypes+1]; fread(&data.bond_nonlinear_epsilon[1],sizeof(double),data.nbondtypes,fp); fread(&data.bond_nonlinear_r0[1],sizeof(double),data.nbondtypes,fp); fread(&data.bond_nonlinear_lamda[1],sizeof(double),data.nbondtypes,fp); } else if (strcmp(data.bond_style,"quartic") == 0) { data.bond_quartic_k = new double[data.nbondtypes+1]; data.bond_quartic_b1 = new double[data.nbondtypes+1]; data.bond_quartic_b2 = new double[data.nbondtypes+1]; data.bond_quartic_rc = new double[data.nbondtypes+1]; data.bond_quartic_u0 = new double[data.nbondtypes+1]; fread(&data.bond_quartic_k[1],sizeof(double),data.nbondtypes,fp); fread(&data.bond_quartic_b1[1],sizeof(double),data.nbondtypes,fp); fread(&data.bond_quartic_b2[1],sizeof(double),data.nbondtypes,fp); fread(&data.bond_quartic_rc[1],sizeof(double),data.nbondtypes,fp); fread(&data.bond_quartic_u0[1],sizeof(double),data.nbondtypes,fp); } else if (strcmp(data.bond_style,"table") == 0) { int tabstyle = read_int(fp); int n = read_int(fp); } else if (strcmp(data.bond_style,"hybrid") == 0) { int nstyles = read_int(fp); for (int i = 0; i < nstyles; i++) char *substyle = read_char(fp); } else { printf("ERROR: Unknown bond style %s\n",data.bond_style); exit(1); } } // --------------------------------------------------------------------- // angle coeffs // one section for each angle style // --------------------------------------------------------------------- void angle(FILE *fp, Data &data) { if (strcmp(data.angle_style,"none") == 0) { } else if (strcmp(data.angle_style,"cg/cmm") == 0) { data.angle_harmonic_k = new double[data.nangletypes+1]; data.angle_harmonic_theta0 = new double[data.nangletypes+1]; data.angle_cg_cmm_epsilon = new double[data.nangletypes+1]; data.angle_cg_cmm_sigma = new double[data.nangletypes+1]; double *angle_cg_cmm_rcut = new double[data.nangletypes+1]; data.angle_cg_cmm_type = new int[data.nangletypes+1]; fread(&data.angle_harmonic_k[1],sizeof(double),data.nangletypes,fp); fread(&data.angle_harmonic_theta0[1],sizeof(double),data.nangletypes,fp); fread(&data.angle_cg_cmm_epsilon[1],sizeof(double),data.nangletypes,fp); fread(&data.angle_cg_cmm_sigma[1],sizeof(double),data.nangletypes,fp); fread(angle_cg_cmm_rcut,sizeof(double),data.nangletypes,fp); fread(&data.angle_cg_cmm_type[1],sizeof(int),data.nangletypes,fp); } else if (strcmp(data.angle_style,"charmm") == 0) { data.angle_charmm_k = new double[data.nangletypes+1]; data.angle_charmm_theta0 = new double[data.nangletypes+1]; data.angle_charmm_k_ub = new double[data.nangletypes+1]; data.angle_charmm_r_ub = new double[data.nangletypes+1]; fread(&data.angle_charmm_k[1],sizeof(double),data.nangletypes,fp); fread(&data.angle_charmm_theta0[1],sizeof(double),data.nangletypes,fp); fread(&data.angle_charmm_k_ub[1],sizeof(double),data.nangletypes,fp); fread(&data.angle_charmm_r_ub[1],sizeof(double),data.nangletypes,fp); } else if (strcmp(data.angle_style,"class2") == 0) { data.angle_class2_theta0 = new double[data.nangletypes+1]; data.angle_class2_k2 = new double[data.nangletypes+1]; data.angle_class2_k3 = new double[data.nangletypes+1]; data.angle_class2_k4 = new double[data.nangletypes+1]; data.angle_class2_bb_k = new double[data.nangletypes+1]; data.angle_class2_bb_r1 = new double[data.nangletypes+1]; data.angle_class2_bb_r2 = new double[data.nangletypes+1]; data.angle_class2_ba_k1 = new double[data.nangletypes+1]; data.angle_class2_ba_k2 = new double[data.nangletypes+1]; data.angle_class2_ba_r1 = new double[data.nangletypes+1]; data.angle_class2_ba_r2 = new double[data.nangletypes+1]; fread(&data.angle_class2_theta0[1],sizeof(double),data.nangletypes,fp); fread(&data.angle_class2_k2[1],sizeof(double),data.nangletypes,fp); fread(&data.angle_class2_k3[1],sizeof(double),data.nangletypes,fp); fread(&data.angle_class2_k4[1],sizeof(double),data.nangletypes,fp); fread(&data.angle_class2_bb_k[1],sizeof(double),data.nangletypes,fp); fread(&data.angle_class2_bb_r1[1],sizeof(double),data.nangletypes,fp); fread(&data.angle_class2_bb_r2[1],sizeof(double),data.nangletypes,fp); fread(&data.angle_class2_ba_k1[1],sizeof(double),data.nangletypes,fp); fread(&data.angle_class2_ba_k2[1],sizeof(double),data.nangletypes,fp); fread(&data.angle_class2_ba_r1[1],sizeof(double),data.nangletypes,fp); fread(&data.angle_class2_ba_r2[1],sizeof(double),data.nangletypes,fp); } else if (strcmp(data.angle_style,"cosine") == 0) { data.angle_cosine_k = new double[data.nangletypes+1]; fread(&data.angle_cosine_k[1],sizeof(double),data.nangletypes,fp); } else if ((strcmp(data.angle_style,"cosine/squared") == 0) || (strcmp(data.angle_style,"cosine/delta") == 0)) { data.angle_cosine_squared_k = new double[data.nangletypes+1]; data.angle_cosine_squared_theta0 = new double[data.nangletypes+1]; fread(&data.angle_cosine_squared_k[1],sizeof(double),data.nangletypes,fp); fread(&data.angle_cosine_squared_theta0[1], sizeof(double),data.nangletypes,fp); } else if (strcmp(data.angle_style,"harmonic") == 0) { data.angle_harmonic_k = new double[data.nangletypes+1]; data.angle_harmonic_theta0 = new double[data.nangletypes+1]; fread(&data.angle_harmonic_k[1],sizeof(double),data.nangletypes,fp); fread(&data.angle_harmonic_theta0[1],sizeof(double),data.nangletypes,fp); } else if (strcmp(data.angle_style,"table") == 0) { int tabstyle = read_int(fp); int n = read_int(fp); } else if (strcmp(data.angle_style,"hybrid") == 0) { int nstyles = read_int(fp); for (int i = 0; i < nstyles; i++) char *substyle = read_char(fp); } else { printf("ERROR: Unknown angle style %s\n",data.angle_style); exit(1); } } // --------------------------------------------------------------------- // dihedral coeffs // one section for each dihedral style // --------------------------------------------------------------------- void dihedral(FILE *fp, Data &data) { if (strcmp(data.dihedral_style,"none") == 0) { } else if (strcmp(data.dihedral_style,"charmm") == 0) { data.dihedral_charmm_k = new double[data.ndihedraltypes+1]; data.dihedral_charmm_multiplicity = new int[data.ndihedraltypes+1]; data.dihedral_charmm_sign = new int[data.ndihedraltypes+1]; data.dihedral_charmm_weight = new double[data.ndihedraltypes+1]; fread(&data.dihedral_charmm_k[1],sizeof(double),data.ndihedraltypes,fp); fread(&data.dihedral_charmm_multiplicity[1],sizeof(int), data.ndihedraltypes,fp); fread(&data.dihedral_charmm_sign[1],sizeof(int),data.ndihedraltypes,fp); fread(&data.dihedral_charmm_weight[1],sizeof(double), data.ndihedraltypes,fp); } else if (strcmp(data.dihedral_style,"class2") == 0) { data.dihedral_class2_k1 = new double[data.ndihedraltypes+1]; data.dihedral_class2_k2 = new double[data.ndihedraltypes+1]; data.dihedral_class2_k3 = new double[data.ndihedraltypes+1]; data.dihedral_class2_phi1 = new double[data.ndihedraltypes+1]; data.dihedral_class2_phi2 = new double[data.ndihedraltypes+1]; data.dihedral_class2_phi3 = new double[data.ndihedraltypes+1]; data.dihedral_class2_mbt_f1 = new double[data.ndihedraltypes+1]; data.dihedral_class2_mbt_f2 = new double[data.ndihedraltypes+1]; data.dihedral_class2_mbt_f3 = new double[data.ndihedraltypes+1]; data.dihedral_class2_mbt_r0 = new double[data.ndihedraltypes+1]; data.dihedral_class2_ebt_f1_1 = new double[data.ndihedraltypes+1]; data.dihedral_class2_ebt_f2_1 = new double[data.ndihedraltypes+1]; data.dihedral_class2_ebt_f3_1 = new double[data.ndihedraltypes+1]; data.dihedral_class2_ebt_r0_1 = new double[data.ndihedraltypes+1]; data.dihedral_class2_ebt_f1_2 = new double[data.ndihedraltypes+1]; data.dihedral_class2_ebt_f2_2 = new double[data.ndihedraltypes+1]; data.dihedral_class2_ebt_f3_2 = new double[data.ndihedraltypes+1]; data.dihedral_class2_ebt_r0_2 = new double[data.ndihedraltypes+1]; data.dihedral_class2_at_f1_1 = new double[data.ndihedraltypes+1]; data.dihedral_class2_at_f2_1 = new double[data.ndihedraltypes+1]; data.dihedral_class2_at_f3_1 = new double[data.ndihedraltypes+1]; data.dihedral_class2_at_theta0_1 = new double[data.ndihedraltypes+1]; data.dihedral_class2_at_f1_2 = new double[data.ndihedraltypes+1]; data.dihedral_class2_at_f2_2 = new double[data.ndihedraltypes+1]; data.dihedral_class2_at_f3_2 = new double[data.ndihedraltypes+1]; data.dihedral_class2_at_theta0_2 = new double[data.ndihedraltypes+1]; data.dihedral_class2_aat_k = new double[data.ndihedraltypes+1]; data.dihedral_class2_aat_theta0_1 = new double[data.ndihedraltypes+1]; data.dihedral_class2_aat_theta0_2 = new double[data.ndihedraltypes+1]; data.dihedral_class2_bb13_k = new double[data.ndihedraltypes+1]; data.dihedral_class2_bb13_r10 = new double[data.ndihedraltypes+1]; data.dihedral_class2_bb13_r30 = new double[data.ndihedraltypes+1]; fread(&data.dihedral_class2_k1[1],sizeof(double),data.ndihedraltypes,fp); fread(&data.dihedral_class2_k2[1],sizeof(double),data.ndihedraltypes,fp); fread(&data.dihedral_class2_k3[1],sizeof(double),data.ndihedraltypes,fp); fread(&data.dihedral_class2_phi1[1],sizeof(double),data.ndihedraltypes,fp); fread(&data.dihedral_class2_phi2[1],sizeof(double),data.ndihedraltypes,fp); fread(&data.dihedral_class2_phi3[1],sizeof(double),data.ndihedraltypes,fp); fread(&data.dihedral_class2_mbt_f1[1],sizeof(double), data.ndihedraltypes,fp); fread(&data.dihedral_class2_mbt_f2[1],sizeof(double), data.ndihedraltypes,fp); fread(&data.dihedral_class2_mbt_f3[1],sizeof(double), data.ndihedraltypes,fp); fread(&data.dihedral_class2_mbt_r0[1],sizeof(double), data.ndihedraltypes,fp); fread(&data.dihedral_class2_ebt_f1_1[1],sizeof(double), data.ndihedraltypes,fp); fread(&data.dihedral_class2_ebt_f2_1[1],sizeof(double), data.ndihedraltypes,fp); fread(&data.dihedral_class2_ebt_f3_1[1],sizeof(double), data.ndihedraltypes,fp); fread(&data.dihedral_class2_ebt_r0_1[1],sizeof(double), data.ndihedraltypes,fp); fread(&data.dihedral_class2_ebt_f1_2[1],sizeof(double), data.ndihedraltypes,fp); fread(&data.dihedral_class2_ebt_f2_2[1],sizeof(double), data.ndihedraltypes,fp); fread(&data.dihedral_class2_ebt_f3_2[1],sizeof(double), data.ndihedraltypes,fp); fread(&data.dihedral_class2_ebt_r0_2[1],sizeof(double), data.ndihedraltypes,fp); fread(&data.dihedral_class2_at_f1_1[1],sizeof(double), data.ndihedraltypes,fp); fread(&data.dihedral_class2_at_f2_1[1],sizeof(double), data.ndihedraltypes,fp); fread(&data.dihedral_class2_at_f3_1[1],sizeof(double), data.ndihedraltypes,fp); fread(&data.dihedral_class2_at_theta0_1[1],sizeof(double), data.ndihedraltypes,fp); fread(&data.dihedral_class2_at_f1_2[1],sizeof(double), data.ndihedraltypes,fp); fread(&data.dihedral_class2_at_f2_2[1],sizeof(double), data.ndihedraltypes,fp); fread(&data.dihedral_class2_at_f3_2[1],sizeof(double), data.ndihedraltypes,fp); fread(&data.dihedral_class2_at_theta0_2[1],sizeof(double), data.ndihedraltypes,fp); fread(&data.dihedral_class2_aat_k[1],sizeof(double), data.ndihedraltypes,fp); fread(&data.dihedral_class2_aat_theta0_1[1],sizeof(double), data.ndihedraltypes,fp); fread(&data.dihedral_class2_aat_theta0_2[1],sizeof(double), data.ndihedraltypes,fp); fread(&data.dihedral_class2_bb13_k[1],sizeof(double), data.ndihedraltypes,fp); fread(&data.dihedral_class2_bb13_r10[1],sizeof(double), data.ndihedraltypes,fp); fread(&data.dihedral_class2_bb13_r30[1],sizeof(double), data.ndihedraltypes,fp); } else if (strcmp(data.dihedral_style,"harmonic") == 0) { data.dihedral_harmonic_k = new double[data.ndihedraltypes+1]; data.dihedral_harmonic_multiplicity = new int[data.ndihedraltypes+1]; data.dihedral_harmonic_sign = new int[data.ndihedraltypes+1]; fread(&data.dihedral_harmonic_k[1],sizeof(double),data.ndihedraltypes,fp); fread(&data.dihedral_harmonic_multiplicity[1],sizeof(int), data.ndihedraltypes,fp); fread(&data.dihedral_harmonic_sign[1],sizeof(int),data.ndihedraltypes,fp); } else if (strcmp(data.dihedral_style,"helix") == 0) { data.dihedral_helix_aphi = new double[data.ndihedraltypes+1]; data.dihedral_helix_bphi = new double[data.ndihedraltypes+1]; data.dihedral_helix_cphi = new double[data.ndihedraltypes+1]; fread(&data.dihedral_helix_aphi[1],sizeof(double),data.ndihedraltypes,fp); fread(&data.dihedral_helix_bphi[1],sizeof(double),data.ndihedraltypes,fp); fread(&data.dihedral_helix_cphi[1],sizeof(double),data.ndihedraltypes,fp); } else if (strcmp(data.dihedral_style,"multi/harmonic") == 0) { data.dihedral_multi_a1 = new double[data.ndihedraltypes+1]; data.dihedral_multi_a2 = new double[data.ndihedraltypes+1]; data.dihedral_multi_a3 = new double[data.ndihedraltypes+1]; data.dihedral_multi_a4 = new double[data.ndihedraltypes+1]; data.dihedral_multi_a5 = new double[data.ndihedraltypes+1]; fread(&data.dihedral_multi_a1[1],sizeof(double),data.ndihedraltypes,fp); fread(&data.dihedral_multi_a2[1],sizeof(double),data.ndihedraltypes,fp); fread(&data.dihedral_multi_a3[1],sizeof(double),data.ndihedraltypes,fp); fread(&data.dihedral_multi_a4[1],sizeof(double),data.ndihedraltypes,fp); fread(&data.dihedral_multi_a5[1],sizeof(double),data.ndihedraltypes,fp); } else if (strcmp(data.dihedral_style,"opls") == 0) { data.dihedral_opls_k1 = new double[data.ndihedraltypes+1]; data.dihedral_opls_k2 = new double[data.ndihedraltypes+1]; data.dihedral_opls_k3 = new double[data.ndihedraltypes+1]; data.dihedral_opls_k4 = new double[data.ndihedraltypes+1]; fread(&data.dihedral_opls_k1[1],sizeof(double),data.ndihedraltypes,fp); fread(&data.dihedral_opls_k2[1],sizeof(double),data.ndihedraltypes,fp); fread(&data.dihedral_opls_k3[1],sizeof(double),data.ndihedraltypes,fp); fread(&data.dihedral_opls_k4[1],sizeof(double),data.ndihedraltypes,fp); } else if (strcmp(data.dihedral_style,"table") == 0) { int tabstyle = read_int(fp); int n = read_int(fp); } else if (strcmp(data.dihedral_style,"hybrid") == 0) { int nstyles = read_int(fp); for (int i = 0; i < nstyles; i++) char *substyle = read_char(fp); } else { printf("ERROR: Unknown dihedral style %s\n",data.dihedral_style); exit(1); } } // --------------------------------------------------------------------- // improper coeffs // one section for each improper style // --------------------------------------------------------------------- void improper(FILE *fp, Data &data) { if (strcmp(data.improper_style,"none") == 0) { } else if (strcmp(data.improper_style,"class2") == 0) { data.improper_class2_k0 = new double[data.nimpropertypes+1]; data.improper_class2_chi0 = new double[data.nimpropertypes+1]; data.improper_class2_aa_k1 = new double[data.nimpropertypes+1]; data.improper_class2_aa_k2 = new double[data.nimpropertypes+1]; data.improper_class2_aa_k3 = new double[data.nimpropertypes+1]; data.improper_class2_aa_theta0_1 = new double[data.nimpropertypes+1]; data.improper_class2_aa_theta0_2 = new double[data.nimpropertypes+1]; data.improper_class2_aa_theta0_3 = new double[data.nimpropertypes+1]; fread(&data.improper_class2_k0[1],sizeof(double), data.nimpropertypes,fp); fread(&data.improper_class2_chi0[1],sizeof(double), data.nimpropertypes,fp); fread(&data.improper_class2_aa_k1[1],sizeof(double), data.nimpropertypes,fp); fread(&data.improper_class2_aa_k2[1],sizeof(double), data.nimpropertypes,fp); fread(&data.improper_class2_aa_k3[1],sizeof(double), data.nimpropertypes,fp); fread(&data.improper_class2_aa_theta0_1[1],sizeof(double), data.nimpropertypes,fp); fread(&data.improper_class2_aa_theta0_2[1],sizeof(double), data.nimpropertypes,fp); fread(&data.improper_class2_aa_theta0_3[1],sizeof(double), data.nimpropertypes,fp); } else if (strcmp(data.improper_style,"cvff") == 0) { data.improper_cvff_k = new double[data.nimpropertypes+1]; data.improper_cvff_sign = new int[data.nimpropertypes+1]; data.improper_cvff_multiplicity = new int[data.nimpropertypes+1]; fread(&data.improper_cvff_k[1],sizeof(double),data.nimpropertypes,fp); fread(&data.improper_cvff_sign[1],sizeof(int),data.nimpropertypes,fp); fread(&data.improper_cvff_multiplicity[1],sizeof(int), data.nimpropertypes,fp); } else if (strcmp(data.improper_style,"harmonic") == 0) { data.improper_harmonic_k = new double[data.nimpropertypes+1]; data.improper_harmonic_chi = new double[data.nimpropertypes+1]; fread(&data.improper_harmonic_k[1],sizeof(double),data.nimpropertypes,fp); fread(&data.improper_harmonic_chi[1],sizeof(double), data.nimpropertypes,fp); } else if (strcmp(data.improper_style,"hybrid") == 0) { int nstyles = read_int(fp); for (int i = 0; i < nstyles; i++) char *substyle = read_char(fp); } else { printf("ERROR: Unknown improper style %s\n",data.improper_style); exit(1); } } // --------------------------------------------------------------------- // initialize Data // --------------------------------------------------------------------- Data::Data() {} // --------------------------------------------------------------------- // print out stats on problem // --------------------------------------------------------------------- void Data::stats() { + char fstr[64]; + printf(" Restart file version = %s\n",version); - printf(" Ntimestep = %d\n",ntimestep); + sprintf(fstr," Ntimestep = %s\n",BIGINT_FORMAT); + printf(fstr,ntimestep); + printf(" Nprocs = %d\n",nprocs); - printf(" Natoms = %lu\n",natoms); - printf(" Nbonds = %lu\n",nbonds); - printf(" Nangles = %lu\n",nangles); - printf(" Ndihedrals = %lu\n",ndihedrals); - printf(" Nimpropers = %lu\n",nimpropers); + + sprintf(fstr," Natoms = %s\n",BIGINT_FORMAT); + printf(fstr,natoms); + sprintf(fstr," Nbonds = %s\n",BIGINT_FORMAT); + printf(fstr,nbonds); + sprintf(fstr," Nangles = %s\n",BIGINT_FORMAT); + printf(fstr,nangles); + sprintf(fstr," Ndihedrals = %s\n",BIGINT_FORMAT); + printf(fstr,ndihedrals); + sprintf(fstr," Nimpropers = %s\n",BIGINT_FORMAT); + printf(fstr,nimpropers); + printf(" Unit style = %s\n",unit_style); printf(" Atom style = %s\n",atom_style); printf(" Pair style = %s\n",pair_style); printf(" Bond style = %s\n",bond_style); printf(" Angle style = %s\n",angle_style); printf(" Dihedral style = %s\n",dihedral_style); printf(" Improper style = %s\n",improper_style); printf(" Xlo xhi = %g %g\n",xlo,xhi); printf(" Ylo yhi = %g %g\n",ylo,yhi); printf(" Zlo zhi = %g %g\n",zlo,zhi); if (triclinic) printf(" Xy xz yz = %g %g %g\n",xy,xz,yz); printf(" Periodicity = %d %d %d\n",xperiodic,yperiodic,zperiodic); printf(" Boundary = %d %d, %d %d, %d %d\n",boundary[0][0],boundary[0][1], boundary[1][0],boundary[1][1],boundary[2][0],boundary[2][1]); } // --------------------------------------------------------------------- -// write the data file +// write the data file and input file // --------------------------------------------------------------------- void Data::write(FILE *fp, FILE *fp2) { - fprintf(fp,"LAMMPS data file from restart file: timestep = %d, procs = %d\n", - ntimestep,nprocs); - + char fstr[128]; + sprintf(fstr, + "LAMMPS data file from restart file: timestep = %s, procs = %%d\n", + BIGINT_FORMAT); + fprintf(fp,fstr,ntimestep,nprocs); fprintf(fp,"\n"); - fprintf(fp,"%lu atoms\n",natoms); - if (nbonds) fprintf(fp,"%lu bonds\n",nbonds); - if (nangles) fprintf(fp,"%lu angles\n",nangles); - if (ndihedrals) fprintf(fp,"%lu dihedrals\n",ndihedrals); - if (nimpropers) fprintf(fp,"%lu impropers\n",nimpropers); + sprintf(fstr,"%s atoms\n",BIGINT_FORMAT); + fprintf(fp,fstr,natoms); + if (nbonds) { + sprintf(fstr,"%s bonds\n",BIGINT_FORMAT); + fprintf(fp,fstr,nbonds); + } + if (nangles) { + sprintf(fstr,"%s angles\n",BIGINT_FORMAT); + fprintf(fp,fstr,nangles); + } + if (ndihedrals) { + sprintf(fstr,"%s dihedrals\n",BIGINT_FORMAT); + fprintf(fp,fstr,ndihedrals); + } + if (nimpropers) { + sprintf(fstr,"%s impropers\n",BIGINT_FORMAT); + fprintf(fp,fstr,nimpropers); + } fprintf(fp,"\n"); fprintf(fp,"%d atom types\n",ntypes); if (nbondtypes) fprintf(fp,"%d bond types\n",nbondtypes); if (nangletypes) fprintf(fp,"%d angle types\n",nangletypes); if (ndihedraltypes) fprintf(fp,"%d dihedral types\n",ndihedraltypes); if (nimpropertypes) fprintf(fp,"%d improper types\n",nimpropertypes); fprintf(fp,"\n"); fprintf(fp,"%-1.16e %-1.16e xlo xhi\n",xlo,xhi); fprintf(fp,"%-1.16e %-1.16e ylo yhi\n",ylo,yhi); fprintf(fp,"%-1.16e %-1.16e zlo zhi\n",zlo,zhi); if (triclinic) fprintf(fp,"%-1.16e %-1.16e %-1.16e xy xz yz\n",xy,xz,yz); // write ff styles to input file if (fp2) { - fprintf(fp2,"# LAMMPS input file from restart file: timestep = %d, procs = %d\n\n", - ntimestep,nprocs); + sprintf(fstr, + "# LAMMPS input file from restart file: " + "timestep = %s, procs = %%d\n\n", + BIGINT_FORMAT); + fprintf(fp2,fstr,ntimestep,nprocs); + if (pair_style) fprintf(fp2,"pair_style %s\n",pair_style); if (bond_style) fprintf(fp2,"bond_style %s\n",bond_style); if (angle_style) fprintf(fp2,"angle_style %s\n",angle_style); if (dihedral_style) fprintf(fp2,"dihedral_style %s\n",dihedral_style); if (improper_style) fprintf(fp2,"improper_style %s\n",improper_style); fprintf(fp2,"special_bonds %g %g %g %g %g %g\n", special_lj[1],special_lj[2],special_lj[3], special_lj[1],special_coul[2],special_coul[3]); fprintf(fp2,"\n"); } // mass to either data file or input file if (mass) { if (fp2) { fprintf(fp2,"\n"); for (int i = 1; i <= ntypes; i++) fprintf(fp2,"mass %d %g\n",i,mass[i]); fprintf(fp2,"\n"); } else { fprintf(fp,"\nMasses\n\n"); for (int i = 1; i <= ntypes; i++) fprintf(fp,"%d %g\n",i,mass[i]); } } // shape and dipole to data file // convert shape from radius to diameter if (shape) { fprintf(fp,"\nShapes\n\n"); for (int i = 1; i <= ntypes; i++) fprintf(fp,"%d %g %g %g\n",i, 2.0*shape[3*i+0],2.0*shape[3*i+1],2.0*shape[3*i+2]); } if (dipole) { fprintf(fp,"\nDipoles\n\n"); for (int i = 1; i <= ntypes; i++) fprintf(fp,"%d %g\n",i,dipole[i]); } // pair coeffs to data file if (pair_style && fp2 == NULL) { if ((strcmp(pair_style,"none") != 0) && (strcmp(pair_style,"airebo") != 0) && (strcmp(pair_style,"coul/cut") != 0) && (strcmp(pair_style,"coul/debye") != 0) && (strcmp(pair_style,"coul/long") != 0) && (strcmp(pair_style,"eam") != 0) && (strcmp(pair_style,"eam/opt") != 0) && (strcmp(pair_style,"eam/alloy") != 0) && (strcmp(pair_style,"eam/alloy/opt") != 0) && (strcmp(pair_style,"eam/fs") != 0) && (strcmp(pair_style,"eam/fs/opt") != 0) && (strcmp(pair_style,"eim") != 0) && (strcmp(pair_style,"eff/cut") != 0) && (strcmp(pair_style,"gran/history") != 0) && (strcmp(pair_style,"gran/no_history") != 0) && (strcmp(pair_style,"gran/hertzian") != 0) && (strcmp(pair_style,"meam") != 0) && (strcmp(pair_style,"reax") != 0) && (strcmp(pair_style,"reax/c") != 0) && (strcmp(pair_style,"sw") != 0) && (strcmp(pair_style,"table") != 0) && (strcmp(pair_style,"tersoff") != 0) && (strcmp(pair_style,"tersoff/zbl") != 0) && (strcmp(pair_style,"hybrid") != 0) && (strcmp(pair_style,"hybrid/overlay") != 0)) fprintf(fp,"\nPair Coeffs\n\n"); if (strcmp(pair_style,"born/coul/long") == 0) { for (int i = 1; i <= ntypes; i++) fprintf(fp,"%d %g %g %g %g %g\n",i, pair_born_A[i],pair_born_rho[i],pair_born_sigma[i], pair_born_C[i],pair_born_D[i]); } else if ((strcmp(pair_style,"buck") == 0) || (strcmp(pair_style,"buck/coul/cut") == 0) || (strcmp(pair_style,"buck/coul/long") == 0) || (strcmp(pair_style,"buck/long") == 0)) { for (int i = 1; i <= ntypes; i++) fprintf(fp,"%d %g %g %g\n",i, pair_buck_A[i],pair_buck_rho[i],pair_buck_C[i]); } else if (strcmp(pair_style,"colloid") == 0) { for (int i = 1; i <= ntypes; i++) fprintf(fp,"%d %g %g %g %g\n",i, pair_colloid_A12[i],pair_colloid_sigma[i], pair_colloid_d2[i],pair_colloid_d2[i]); } else if (strcmp(pair_style,"dipole/cut") == 0) { for (int i = 1; i <= ntypes; i++) fprintf(fp,"%d %g %g\n",i, pair_dipole_epsilon[i],pair_dipole_sigma[i]); } else if (strcmp(pair_style,"dpd") == 0) { for (int i = 1; i <= ntypes; i++) fprintf(fp,"%d %g %g\n",i, pair_dpd_a0[i],pair_dpd_gamma[i]); } else if (strcmp(pair_style,"dpd/tstat") == 0) { for (int i = 1; i <= ntypes; i++) fprintf(fp,"%d %g\n",i, pair_dpd_gamma[i]); } else if ((strcmp(pair_style,"gayberne") == 0) || (strcmp(pair_style,"gayberne/gpu") == 0)) { for (int i = 1; i <= ntypes; i++) fprintf(fp,"%d %g %g %g %g %g %g %g %g\n",i, pair_gb_epsilon[i],pair_gb_sigma[i], pair_gb_epsa[i],pair_gb_epsb[i],pair_gb_epsc[i], pair_gb_epsa[i],pair_gb_epsb[i],pair_gb_epsc[i]); } else if ((strcmp(pair_style,"lj/charmm/coul/charmm") == 0) || (strcmp(pair_style,"lj/charmm/coul/charmm/implicit") == 0) || (strcmp(pair_style,"lj/charmm/coul/long") == 0) || (strcmp(pair_style,"lj/charmm/coul/long") == 0)) { for (int i = 1; i <= ntypes; i++) fprintf(fp,"%d %g %g %g %g\n",i, pair_charmm_epsilon[i],pair_charmm_sigma[i], pair_charmm_eps14[i],pair_charmm_sigma14[i]); } else if ((strcmp(pair_style,"lj/class2") == 0) || (strcmp(pair_style,"lj/class2/coul/cut") == 0) || (strcmp(pair_style,"lj/class2/coul/long") == 0)) { for (int i = 1; i <= ntypes; i++) fprintf(fp,"%d %g %g\n",i, pair_class2_epsilon[i],pair_class2_sigma[i]); } else if ((strcmp(pair_style,"lj/cut") == 0) || (strcmp(pair_style,"lj/cut/gpu") == 0) || (strcmp(pair_style,"lj/cut/opt") == 0) || (strcmp(pair_style,"lj/cut/coul/cut") == 0) || (strcmp(pair_style,"lj/cut/coul/cut/gpu") == 0) || (strcmp(pair_style,"lj/cut/coul/debye") == 0) || (strcmp(pair_style,"lj/cut/coul/long") == 0) || (strcmp(pair_style,"lj/cut/coul/long/gpu") == 0) || (strcmp(pair_style,"lj/cut/coul/long/tip4p") == 0) || (strcmp(pair_style,"lj/coul") == 0)) { for (int i = 1; i <= ntypes; i++) fprintf(fp,"%d %g %g\n",i, pair_lj_epsilon[i],pair_lj_sigma[i]); } else if (strcmp(pair_style,"lj/expand") == 0) { for (int i = 1; i <= ntypes; i++) fprintf(fp,"%d %g %g %g\n",i, pair_ljexpand_epsilon[i],pair_ljexpand_sigma[i], pair_ljexpand_shift[i]); } else if ((strcmp(pair_style,"lj/gromacs") == 0) || (strcmp(pair_style,"lj/gromacs/coul/gromacs") == 0)) { for (int i = 1; i <= ntypes; i++) fprintf(fp,"%d %g %g\n",i, pair_ljgromacs_epsilon[i],pair_ljgromacs_sigma[i]); } else if (strcmp(pair_style,"lj/smooth") == 0) { for (int i = 1; i <= ntypes; i++) fprintf(fp,"%d %g %g\n",i, pair_ljsmooth_epsilon[i],pair_ljsmooth_sigma[i]); } else if ((strcmp(pair_style,"morse") == 0) || (strcmp(pair_style,"morse/opt") == 0)) { for (int i = 1; i <= ntypes; i++) fprintf(fp,"%d %g %g %g\n",i, pair_morse_d0[i],pair_morse_alpha[i],pair_morse_r0[i]); } else if (strcmp(pair_style,"soft") == 0) { for (int i = 1; i <= ntypes; i++) fprintf(fp,"%d %g\n",i, pair_soft_A[i]); } else if (strcmp(pair_style,"yukawa") == 0) { for (int i = 1; i <= ntypes; i++) fprintf(fp,"%d %g\n",i, pair_yukawa_A[i]); } else if ((strcmp(pair_style,"cg/cmm") == 0) || (strcmp(pair_style,"cg/cmm/coul/cut") == 0) || (strcmp(pair_style,"cg/cmm/coul/long") == 0)) { printf("ERROR: Cannot write pair_style %s to data file\n", pair_style); exit(1); } } // pair coeffs to input file // only supported styles = cg/cmm if (pair_style && fp2) { if ((strcmp(pair_style,"cg/cmm") == 0) || (strcmp(pair_style,"cg/cmm/gpu") == 0) || (strcmp(pair_style,"cg/cmm/coul/cut") == 0) || (strcmp(pair_style,"cg/cmm/coul/long") == 0) || (strcmp(pair_style,"cg/cmm/coul/long/gpu") == 0)) { for (int i = 1; i <= ntypes; i++) { for (int j = i; j <= ntypes; j++) { fprintf(fp2,"pair_coeff %d %d %s %g %g\n",i,j, cg_type_list[pair_cg_cmm_type[i][j]], pair_cg_epsilon[i][j],pair_cg_sigma[i][j]); } } } else { printf("ERROR: Cannot write pair_style %s to input file\n", pair_style); exit(1); } } // bond coeffs to data file if (bond_style && fp2 == NULL) { if ((strcmp(bond_style,"none") != 0) && (strcmp(bond_style,"table") != 0) && (strcmp(bond_style,"hybrid") != 0)) fprintf(fp,"\nBond Coeffs\n\n"); if (strcmp(bond_style,"class2") == 0) { for (int i = 1; i <= nbondtypes; i++) fprintf(fp,"%d %g %g %g %g\n",i, bond_class2_r0[i],bond_class2_k2[i], bond_class2_k3[i],bond_class2_k4[i]); } else if (strcmp(bond_style,"fene") == 0) { for (int i = 1; i <= nbondtypes; i++) fprintf(fp,"%d %g %g %g %g\n",i, bond_fene_k[i],bond_fene_r0[i], bond_fene_epsilon[i],bond_fene_sigma[i]); } else if (strcmp(bond_style,"fene/expand") == 0) { for (int i = 1; i <= nbondtypes; i++) fprintf(fp,"%d %g %g %g %g %g\n",i, bond_feneexpand_k[i],bond_feneexpand_r0[i], bond_feneexpand_epsilon[i],bond_feneexpand_sigma[i], bond_feneexpand_shift[i]); } else if (strcmp(bond_style,"harmonic") == 0) { for (int i = 1; i <= nbondtypes; i++) fprintf(fp,"%d %g %g\n",i, bond_harmonic_k[i],bond_harmonic_r0[i]); } else if (strcmp(bond_style,"morse") == 0) { for (int i = 1; i <= nbondtypes; i++) fprintf(fp,"%d %g %g %g\n",i, bond_morse_d0[i],bond_morse_alpha[i],bond_morse_r0[i]); } else if (strcmp(bond_style,"nonlinear") == 0) { for (int i = 1; i <= nbondtypes; i++) fprintf(fp,"%d %g %g %g\n",i, bond_nonlinear_epsilon[i],bond_nonlinear_r0[i], bond_nonlinear_lamda[i]); } else if (strcmp(bond_style,"quartic") == 0) { for (int i = 1; i <= nbondtypes; i++) fprintf(fp,"%d %g %g %g %g %g\n",i, bond_quartic_k[i],bond_quartic_b1[i],bond_quartic_b2[i], bond_quartic_rc[i],bond_quartic_u0[i]); } } // bond coeffs to input file // only supported styles = harmonic if (bond_style && fp2) { if (strcmp(bond_style,"harmonic") == 0) { for (int i = 1; i <= nbondtypes; i++) fprintf(fp2,"bond_coeff %d %g %g\n",i, bond_harmonic_k[i],bond_harmonic_r0[i]); } else { printf("ERROR: Cannot write bond_style %s to input file\n", bond_style); exit(1); } } // angle coeffs to data file if (angle_style && fp2 == NULL) { double PI = 3.1415926; // convert back to degrees if ((strcmp(angle_style,"none") != 0) && (strcmp(angle_style,"table") != 0) && (strcmp(angle_style,"hybrid") != 0)) fprintf(fp,"\nAngle Coeffs\n\n"); if (strcmp(angle_style,"charmm") == 0) { for (int i = 1; i <= nangletypes; i++) fprintf(fp,"%d %g %g %g %g\n",i, angle_charmm_k[i],angle_charmm_theta0[i]/PI*180.0, angle_charmm_k_ub[i],angle_charmm_r_ub[i]); } else if (strcmp(angle_style,"class2") == 0) { for (int i = 1; i <= nangletypes; i++) fprintf(fp,"%d %g %g %g %g\n",i, angle_class2_theta0[i]/PI*180.0,angle_class2_k2[i], angle_class2_k3[i],angle_class2_k4[i]); fprintf(fp,"\nBondBond Coeffs\n\n"); for (int i = 1; i <= nangletypes; i++) fprintf(fp,"%d %g %g %g\n",i, angle_class2_bb_k[i], angle_class2_bb_r1[i],angle_class2_bb_r2[i]); fprintf(fp,"\nBondAngle Coeffs\n\n"); for (int i = 1; i <= nangletypes; i++) fprintf(fp,"%d %g %g %g %g\n",i, angle_class2_ba_k1[i],angle_class2_ba_k2[i], angle_class2_ba_r1[i],angle_class2_ba_r2[i]); } else if (strcmp(angle_style,"cosine") == 0) { for (int i = 1; i <= nangletypes; i++) fprintf(fp,"%d %g\n",i,angle_cosine_k[i]); } else if ((strcmp(angle_style,"cosine/squared") == 0) || (strcmp(angle_style,"cosine/delta") == 0)) { for (int i = 1; i <= nangletypes; i++) fprintf(fp,"%d %g %g\n",i, angle_cosine_squared_k[i], angle_cosine_squared_theta0[i]/PI*180.0); } else if (strcmp(angle_style,"harmonic") == 0) { for (int i = 1; i <= nangletypes; i++) fprintf(fp,"%d %g %g\n",i, angle_harmonic_k[i],angle_harmonic_theta0[i]/PI*180.0); } else if (strcmp(angle_style,"cg/cmm") == 0) { for (int i = 1; i <= nangletypes; i++) fprintf(fp,"%d %g %g %s %g %g\n",i, angle_harmonic_k[i],angle_harmonic_theta0[i]/PI*180.0, cg_type_list[angle_cg_cmm_type[i]],angle_cg_cmm_epsilon[i], angle_cg_cmm_sigma[i]); } } // angle coeffs to input file // only supported styles = cosine/squared, harmonic, cg/cmm if (angle_style && fp2) { double PI = 3.1415926; // convert back to degrees if ((strcmp(angle_style,"cosine/squared") == 0) || (strcmp(angle_style,"cosine/delta") == 0)) { for (int i = 1; i <= nangletypes; i++) fprintf(fp2,"angle_coeffs %d %g %g\n",i, angle_cosine_squared_k[i], angle_cosine_squared_theta0[i]/PI*180.0); } else if (strcmp(angle_style,"harmonic") == 0) { for (int i = 1; i <= nangletypes; i++) fprintf(fp2,"angle_coeffs %d %g %g\n",i, angle_harmonic_k[i],angle_harmonic_theta0[i]/PI*180.0); } else if (strcmp(angle_style,"cg/cmm") == 0) { for (int i = 1; i <= nangletypes; i++) fprintf(fp2,"angle_coeffs %d %g %g %s %g %g\n",i, angle_harmonic_k[i],angle_harmonic_theta0[i]/PI*180.0, cg_type_list[angle_cg_cmm_type[i]],angle_cg_cmm_epsilon[i], angle_cg_cmm_sigma[i]); } else { printf("ERROR: Cannot write angle_style %s to input file\n", angle_style); exit(1); } } if (dihedral_style) { double PI = 3.1415926; // convert back to degrees if ((strcmp(dihedral_style,"none") != 0) && (strcmp(dihedral_style,"table") != 0) && (strcmp(dihedral_style,"hybrid") != 0)) fprintf(fp,"\nDihedral Coeffs\n\n"); if (strcmp(dihedral_style,"charmm") == 0) { for (int i = 1; i <= ndihedraltypes; i++) fprintf(fp,"%d %g %d %d %g\n",i, dihedral_charmm_k[i],dihedral_charmm_multiplicity[i], dihedral_charmm_sign[i],dihedral_charmm_weight[i]); } else if (strcmp(dihedral_style,"class2") == 0) { for (int i = 1; i <= ndihedraltypes; i++) fprintf(fp,"%d %g %g %g %g %g %g\n",i, dihedral_class2_k1[i], dihedral_class2_phi1[i]/PI*180.0, dihedral_class2_k2[i], dihedral_class2_phi2[i]/PI*180.0, dihedral_class2_k3[i], dihedral_class2_phi3[i]/PI*180.0); fprintf(fp,"\nMiddleBondTorsion Coeffs\n\n"); for (int i = 1; i <= ndihedraltypes; i++) fprintf(fp,"%d %g %g %g %g\n",i, dihedral_class2_mbt_f1[i],dihedral_class2_mbt_f2[i], dihedral_class2_mbt_f3[i],dihedral_class2_mbt_r0[i]); fprintf(fp,"\nEndBondTorsion Coeffs\n\n"); for (int i = 1; i <= ndihedraltypes; i++) fprintf(fp,"%d %g %g %g %g %g %g %g %g\n",i, dihedral_class2_ebt_f1_1[i],dihedral_class2_ebt_f2_1[i], dihedral_class2_ebt_f3_1[i], dihedral_class2_ebt_f1_2[i],dihedral_class2_ebt_f2_2[i], dihedral_class2_ebt_f3_2[i], dihedral_class2_ebt_r0_1[i], dihedral_class2_ebt_r0_2[i]); fprintf(fp,"\nAngleTorsion Coeffs\n\n"); for (int i = 1; i <= ndihedraltypes; i++) fprintf(fp,"%d %g %g %g %g %g %g %g %g\n",i, dihedral_class2_at_f1_1[i],dihedral_class2_at_f2_1[i], dihedral_class2_at_f3_1[i], dihedral_class2_at_f1_2[i],dihedral_class2_at_f2_2[i], dihedral_class2_at_f3_2[i], dihedral_class2_at_theta0_1[i]/PI*180.0, dihedral_class2_at_theta0_2[i]/PI*180.0); fprintf(fp,"\nAngleAngleTorsion Coeffs\n\n"); for (int i = 1; i <= ndihedraltypes; i++) fprintf(fp,"%d %g %g %g\n",i, dihedral_class2_aat_k[i], dihedral_class2_aat_theta0_1[i]/PI*180.0, dihedral_class2_aat_theta0_2[i]/PI*180.0); fprintf(fp,"\nBondBond13 Coeffs\n\n"); for (int i = 1; i <= ndihedraltypes; i++) fprintf(fp,"%d %g %g %g\n",i, dihedral_class2_bb13_k[i], dihedral_class2_bb13_r10[i],dihedral_class2_bb13_r30[i]); } else if (strcmp(dihedral_style,"harmonic") == 0) { for (int i = 1; i <= ndihedraltypes; i++) fprintf(fp,"%d %g %d %d\n",i, dihedral_harmonic_k[i],dihedral_harmonic_multiplicity[i], dihedral_harmonic_sign[i]); } else if (strcmp(dihedral_style,"helix") == 0) { for (int i = 1; i <= ndihedraltypes; i++) fprintf(fp,"%d %g %g %g\n",i,dihedral_helix_aphi[i], dihedral_helix_bphi[i],dihedral_helix_cphi[i]); } else if (strcmp(dihedral_style,"multi/harmonic") == 0) { for (int i = 1; i <= ndihedraltypes; i++) fprintf(fp,"%d %g %g %g %g %g\n",i, dihedral_multi_a1[i],dihedral_multi_a2[i], dihedral_multi_a3[i],dihedral_multi_a4[i], dihedral_multi_a5[i]); } else if (strcmp(dihedral_style,"opls") == 0) { for (int i = 1; i <= ndihedraltypes; i++) // restore factor of 2 fprintf(fp,"%d %g %g %g %g\n",i, 2.0*dihedral_opls_k1[i],2.0*dihedral_opls_k2[i], 2.0*dihedral_opls_k3[i],2.0*dihedral_opls_k4[i]); } } if (improper_style) { double PI = 3.1415926; // convert back to degrees if ((strcmp(improper_style,"none") != 0) && (strcmp(improper_style,"hybrid") != 0)) fprintf(fp,"\nImproper Coeffs\n\n"); if (strcmp(improper_style,"class2") == 0) { for (int i = 1; i <= nimpropertypes; i++) fprintf(fp,"%d %g %g\n",i, improper_class2_k0[i],improper_class2_chi0[i]/PI*180.0); fprintf(fp,"\nAngleAngle Coeffs\n\n"); for (int i = 1; i <= nimpropertypes; i++) fprintf(fp,"%d %g %g %g %g %g %g\n",i, improper_class2_aa_k1[i],improper_class2_aa_k2[i], improper_class2_aa_k3[i], improper_class2_aa_theta0_1[i]/PI*180.0, improper_class2_aa_theta0_2[i]/PI*180.0, improper_class2_aa_theta0_3[i]/PI*180.0); } else if (strcmp(improper_style,"cvff") == 0) { for (int i = 1; i <= nimpropertypes; i++) fprintf(fp,"%d %g %d %d\n",i, improper_cvff_k[i],improper_cvff_sign[i], improper_cvff_multiplicity[i]); } else if (strcmp(improper_style,"harmonic") == 0) { for (int i = 1; i <= nimpropertypes; i++) fprintf(fp,"%d %g %g\n",i, improper_harmonic_k[i],improper_harmonic_chi[i]/PI*180.0); } } if (natoms) { fprintf(fp,"\nAtoms\n\n"); int ix,iy,iz; for (uint64_t i = 0; i < natoms; i++) { ix = (image[i] & 1023) - 512; iy = (image[i] >> 10 & 1023) - 512; iz = (image[i] >> 20) - 512; if (style_hybrid == 0) { if (style_angle) write_atom_angle(fp,i,ix,iy,iz); if (style_atomic) write_atom_atomic(fp,i,ix,iy,iz); if (style_bond) write_atom_bond(fp,i,ix,iy,iz); if (style_charge) write_atom_charge(fp,i,ix,iy,iz); if (style_dipole) write_atom_dipole(fp,i,ix,iy,iz); if (style_ellipsoid) write_atom_ellipsoid(fp,i,ix,iy,iz); if (style_full) write_atom_full(fp,i,ix,iy,iz); if (style_granular) write_atom_granular(fp,i,ix,iy,iz); if (style_molecular) write_atom_molecular(fp,i,ix,iy,iz); if (style_peri) write_atom_peri(fp,i,ix,iy,iz); fprintf(fp,"\n"); } else { fprintf(fp,"%d %d %-1.16e %-1.16e %-1.16e", tag[i],type[i],x[i],y[i],z[i]); for (int k = 1; k <= style_hybrid; k++) { if (k == style_angle) write_atom_angle_extra(fp,i); if (k == style_atomic) write_atom_atomic_extra(fp,i); if (k == style_bond) write_atom_bond_extra(fp,i); if (k == style_charge) write_atom_charge_extra(fp,i); if (k == style_dipole) write_atom_dipole_extra(fp,i); if (k == style_ellipsoid) write_atom_ellipsoid_extra(fp,i); if (k == style_full) write_atom_full_extra(fp,i); if (k == style_granular) write_atom_granular_extra(fp,i); if (k == style_molecular) write_atom_molecular_extra(fp,i); if (k == style_peri) write_atom_peri_extra(fp,i); } fprintf(fp," %d %d %d\n",ix,iy,iz); } } } if (natoms) { fprintf(fp,"\nVelocities\n\n"); for (uint64_t i = 0; i < natoms; i++) if (style_hybrid == 0) { if (style_angle) write_vel_angle(fp,i); if (style_atomic) write_vel_atomic(fp,i); if (style_bond) write_vel_bond(fp,i); if (style_charge) write_vel_charge(fp,i); if (style_dipole) write_vel_dipole(fp,i); if (style_ellipsoid) write_vel_ellipsoid(fp,i); if (style_full) write_vel_full(fp,i); if (style_granular) write_vel_granular(fp,i); if (style_molecular) write_vel_molecular(fp,i); if (style_peri) write_vel_peri(fp,i); fprintf(fp,"\n"); } else { fprintf(fp,"%d %-1.16e %-1.16e %-1.16e",tag[i],vx[i],vy[i],vz[i]); for (int k = 1; k <= style_hybrid; k++) { if (k == style_angle) write_vel_angle_extra(fp,i); if (k == style_atomic) write_vel_atomic_extra(fp,i); if (k == style_bond) write_vel_bond_extra(fp,i); if (k == style_charge) write_vel_charge_extra(fp,i); if (k == style_dipole) write_vel_dipole_extra(fp,i); if (k == style_ellipsoid) write_vel_ellipsoid_extra(fp,i); if (k == style_full) write_vel_full_extra(fp,i); if (k == style_granular) write_vel_granular_extra(fp,i); if (k == style_molecular) write_vel_molecular_extra(fp,i); if (k == style_peri) write_vel_peri_extra(fp,i); } fprintf(fp,"\n"); } } if (nbonds) { fprintf(fp,"\nBonds\n\n"); for (uint64_t i = 0; i < nbonds; i++) fprintf(fp,"%d %d %d %d\n", i+1,bond_type[i],bond_atom1[i],bond_atom2[i]); } if (nangles) { fprintf(fp,"\nAngles\n\n"); for (uint64_t i = 0; i < nangles; i++) fprintf(fp,"%d %d %d %d %d\n", i+1,angle_type[i],angle_atom1[i],angle_atom2[i],angle_atom3[i]); } if (ndihedrals) { fprintf(fp,"\nDihedrals\n\n"); for (uint64_t i = 0; i < ndihedrals; i++) fprintf(fp,"%d %d %d %d %d %d\n", i+1,dihedral_type[i],dihedral_atom1[i],dihedral_atom2[i], dihedral_atom3[i],dihedral_atom4[i]); } if (nimpropers) { fprintf(fp,"\nImpropers\n\n"); for (uint64_t i = 0; i < nimpropers; i++) fprintf(fp,"%d %d %d %d %d %d\n", i+1,improper_type[i],improper_atom1[i],improper_atom2[i], improper_atom3[i],improper_atom4[i]); } } // --------------------------------------------------------------------- // per-atom write routines // one routine per atom style // --------------------------------------------------------------------- void Data::write_atom_angle(FILE *fp, int i, int ix, int iy, int iz) { fprintf(fp,"%d %d %d %-1.16e %-1.16e %-1.16e %d %d %d", tag[i],molecule[i],type[i],x[i],y[i],z[i],ix,iy,iz); } void Data::write_atom_atomic(FILE *fp, int i, int ix, int iy, int iz) { fprintf(fp,"%d %d %-1.16e %-1.16e %-1.16e %d %d %d", tag[i],type[i],x[i],y[i],z[i],ix,iy,iz); } void Data::write_atom_bond(FILE *fp, int i, int ix, int iy, int iz) { fprintf(fp,"%d %d %d %-1.16e %-1.16e %-1.16e %d %d %d", tag[i],molecule[i],type[i],x[i],y[i],z[i],ix,iy,iz); } void Data::write_atom_charge(FILE *fp, int i, int ix, int iy, int iz) { fprintf(fp,"%d %d %-1.16e %-1.16e %-1.16e %-1.16e %d %d %d", tag[i],type[i],q[i],x[i],y[i],z[i],ix,iy,iz); } void Data::write_atom_dipole(FILE *fp, int i, int ix, int iy, int iz) { fprintf(fp,"%d %d %-1.16e %-1.16e %-1.16e %-1.16e %-1.16e %-1.16e %-1.16e %d %d %d", tag[i],type[i],q[i],x[i],y[i],z[i],mux[i],muy[i],muz[i],ix,iy,iz); } void Data::write_atom_ellipsoid(FILE *fp, int i, int ix, int iy, int iz) { fprintf(fp,"%d %d %-1.16e %-1.16e %-1.16e %-1.16e %-1.16e %-1.16e %-1.16e %d %d %d", tag[i],type[i],x[i],y[i],z[i], quatw[i],quati[i],quatj[i],quatk[i],ix,iy,iz); } void Data::write_atom_full(FILE *fp, int i, int ix, int iy, int iz) { fprintf(fp,"%d %d %d %-1.16e %-1.16e %-1.16e %-1.16e %d %d %d", tag[i],molecule[i],type[i],q[i],x[i],y[i],z[i],ix,iy,iz); } void Data::write_atom_granular(FILE *fp, int i, int ix, int iy, int iz) { fprintf(fp,"%d %d %-1.16e %-1.16e %-1.16e %-1.16e %-1.16e %d %d %d", tag[i],type[i],2.0*radius[i],density[i],x[i],y[i],z[i],ix,iy,iz); } void Data::write_atom_molecular(FILE *fp, int i, int ix, int iy, int iz) { fprintf(fp,"%d %d %d %-1.16e %-1.16e %-1.16e %d %d %d", tag[i],molecule[i],type[i],x[i],y[i],z[i],ix,iy,iz); } void Data::write_atom_peri(FILE *fp, int i, int ix, int iy, int iz) { fprintf(fp,"%d %d %-1.16e %-1.16e %-1.16e %-1.16e %-1.16e %-1.16e %d %d %d", tag[i],type[i],vfrac[i],density[i],rmass[i],x[i],y[i],z[i],ix,iy,iz); } // --------------------------------------------------------------------- // per-atom write routines of extra quantities unique to style // one routine per atom style // --------------------------------------------------------------------- void Data::write_atom_angle_extra(FILE *fp, int i) { fprintf(fp," %d",molecule[i]); } void Data::write_atom_atomic_extra(FILE *fp, int i) {} void Data::write_atom_bond_extra(FILE *fp, int i) { fprintf(fp," %d",molecule[i]); } void Data::write_atom_charge_extra(FILE *fp, int i) { fprintf(fp," %-1.16e",q[i]); } void Data::write_atom_dipole_extra(FILE *fp, int i) { fprintf(fp," %-1.16e %-1.16e %-1.16e %-1.16e",q[i],mux[i],muy[i],muz[i]); } void Data::write_atom_ellipsoid_extra(FILE *fp, int i) { fprintf(fp," %-1.16e %-1.16e %-1.16e %-1.16e",quatw[i],quati[i],quatj[i],quatk[i]); } void Data::write_atom_full_extra(FILE *fp, int i) { fprintf(fp," %d %-1.16e",molecule[i],q[i]); } void Data::write_atom_granular_extra(FILE *fp, int i) { fprintf(fp," %-1.16e %-1.16e",2.0*radius[i],density[i]); } void Data::write_atom_molecular_extra(FILE *fp, int i) { fprintf(fp," %d",molecule[i]); } void Data::write_atom_peri_extra(FILE *fp, int i) { fprintf(fp," %-1.16e %-1.16e %-1.16e",vfrac[i],density[i],rmass[i]); } // --------------------------------------------------------------------- // per-atom velocity write routines // one routine per atom style // --------------------------------------------------------------------- void Data::write_vel_angle(FILE *fp, int i) { fprintf(fp,"%d %-1.16e %-1.16e %-1.16e",tag[i],vx[i],vy[i],vz[i]); } void Data::write_vel_atomic(FILE *fp, int i) { fprintf(fp,"%d %-1.16e %-1.16e %-1.16e",tag[i],vx[i],vy[i],vz[i]); } void Data::write_vel_bond(FILE *fp, int i) { fprintf(fp,"%d %-1.16e %-1.16e %-1.16e",tag[i],vx[i],vy[i],vz[i]); } void Data::write_vel_charge(FILE *fp, int i) { fprintf(fp,"%d %-1.16e %-1.16e %-1.16e",tag[i],vx[i],vy[i],vz[i]); } void Data::write_vel_dipole(FILE *fp, int i) { fprintf(fp,"%d %-1.16e %-1.16e %-1.16e",tag[i],vx[i],vy[i],vz[i]); } void Data::write_vel_ellipsoid(FILE *fp, int i) { fprintf(fp,"%d %-1.16e %-1.16e %-1.16e %-1.16e %-1.16e %-1.16e", tag[i],vx[i],vy[i],vz[i],angmomx[i],angmomy[i],angmomz[i]); } void Data::write_vel_full(FILE *fp, int i) { fprintf(fp,"%d %-1.16e %-1.16e %-1.16e",tag[i],vx[i],vy[i],vz[i]); } void Data::write_vel_granular(FILE *fp, int i) { fprintf(fp,"%d %-1.16e %-1.16e %-1.16e %-1.16e %-1.16e %-1.16e", tag[i],vx[i],vy[i],vz[i],omegax[i],omegay[i],omegaz[i]); } void Data::write_vel_molecular(FILE *fp, int i) { fprintf(fp,"%d %-1.16e %-1.16e %-1.16e",tag[i],vx[i],vy[i],vz[i]); } void Data::write_vel_peri(FILE *fp, int i) { fprintf(fp,"%d %-1.16e %-1.16e %-1.16e",tag[i],vx[i],vy[i],vz[i]); } // --------------------------------------------------------------------- // per-atom velocity write routines of extra quantities unique to style // one routine per atom style // --------------------------------------------------------------------- void Data::write_vel_angle_extra(FILE *fp, int i) {} void Data::write_vel_atomic_extra(FILE *fp, int i) {} void Data::write_vel_bond_extra(FILE *fp, int i) {} void Data::write_vel_charge_extra(FILE *fp, int i) {} void Data::write_vel_dipole_extra(FILE *fp, int i) {} void Data::write_vel_ellipsoid_extra(FILE *fp, int i) { fprintf(fp," %-1.16e %-1.16e %-1.16e",angmomx[i],angmomy[i],angmomz[i]); } void Data::write_vel_full_extra(FILE *fp, int i) {} void Data::write_vel_granular_extra(FILE *fp, int i) { fprintf(fp," %-1.16e %-1.16e %-1.16e",omegax[i],omegay[i],omegaz[i]); } void Data::write_vel_molecular_extra(FILE *fp, int i) {} void Data::write_vel_peri_extra(FILE *fp, int i) {} // --------------------------------------------------------------------- // binary reads from restart file // --------------------------------------------------------------------- int read_int(FILE *fp) { int value; fread(&value,sizeof(int),1,fp); return value; } double read_double(FILE *fp) { double value; fread(&value,sizeof(double),1,fp); return value; } char *read_char(FILE *fp) { int n; fread(&n,sizeof(int),1,fp); if (n == 0) return NULL; char *value = new char[n]; fread(value,sizeof(char),n,fp); return value; } -uint64_t read_uint64(FILE *fp) +bigint read_bigint(FILE *fp) { - uint64_t value; - fread(&value,sizeof(uint64_t),1,fp); + bigint value; + fread(&value,sizeof(bigint),1,fp); return value; } -