diff --git a/doc/src/Section_accelerate.txt b/doc/src/Section_accelerate.txt index 881235888..bb0c93b8a 100644 --- a/doc/src/Section_accelerate.txt +++ b/doc/src/Section_accelerate.txt @@ -1,391 +1,391 @@ "Previous Section"_Section_packages.html - "LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc - "Next Section"_Section_howto.html :c :link(lws,http://lammps.sandia.gov) :link(ld,Manual.html) :link(lc,Section_commands.html#comm) :line 5. Accelerating LAMMPS performance :h3 This section describes various methods for improving LAMMPS performance for different classes of problems running on different kinds of machines. There are two thrusts to the discussion that follows. The first is using code options that implement alternate algorithms that can speed-up a simulation. The second is to use one of the several accelerator packages provided with LAMMPS that contain code optimized for certain kinds of hardware, including multi-core CPUs, GPUs, and Intel Xeon Phi coprocessors. 5.1 "Measuring performance"_#acc_1 :ulb,l 5.2 "Algorithms and code options to boost performace"_#acc_2 :l 5.3 "Accelerator packages with optimized styles"_#acc_3 :l 5.3.1 "GPU package"_accelerate_gpu.html :l 5.3.2 "USER-INTEL package"_accelerate_intel.html :l 5.3.3 "KOKKOS package"_accelerate_kokkos.html :l 5.3.4 "USER-OMP package"_accelerate_omp.html :l 5.3.5 "OPT package"_accelerate_opt.html :l 5.4 "Comparison of various accelerator packages"_#acc_4 :l :ule The "Benchmark page"_http://lammps.sandia.gov/bench.html of the LAMMPS web site gives performance results for the various accelerator packages discussed in Section 5.2, for several of the standard LAMMPS benchmark problems, as a function of problem size and number of compute nodes, on different hardware platforms. :line :line 5.1 Measuring performance :h4,link(acc_1) Before trying to make your simulation run faster, you should understand how it currently performs and where the bottlenecks are. The best way to do this is run the your system (actual number of atoms) for a modest number of timesteps (say 100 steps) on several different processor counts, including a single processor if possible. Do this for an equilibrium version of your system, so that the 100-step timings are representative of a much longer run. There is typically no need to run for 1000s of timesteps to get accurate timings; you can simply extrapolate from short runs. For the set of runs, look at the timing data printed to the screen and log file at the end of each LAMMPS run. "This section"_Section_start.html#start_7 of the manual has an overview. Running on one (or a few processors) should give a good estimate of the serial performance and what portions of the timestep are taking the most time. Running the same problem on a few different processor counts should give an estimate of parallel scalability. I.e. if the simulation runs 16x faster on 16 processors, its 100% parallel efficient; if it runs 8x faster on 16 processors, it's 50% efficient. The most important data to look at in the timing info is the timing breakdown and relative percentages. For example, trying different options for speeding up the long-range solvers will have little impact if they only consume 10% of the run time. If the pairwise time is dominating, you may want to look at GPU or OMP versions of the pair style, as discussed below. Comparing how the percentages change as you increase the processor count gives you a sense of how different operations within the timestep are scaling. Note that if you are running with a Kspace solver, there is additional output on the breakdown of the Kspace time. For PPPM, this includes the fraction spent on FFTs, which can be communication intensive. Another important detail in the timing info are the histograms of atoms counts and neighbor counts. If these vary widely across processors, you have a load-imbalance issue. This often results in inaccurate relative timing data, because processors have to wait when communication occurs for other processors to catch up. Thus the reported times for "Communication" or "Other" may be higher than they really are, due to load-imbalance. If this is an issue, you can uncomment the MPI_Barrier() lines in src/timer.cpp, and recompile LAMMPS, to obtain synchronized timings. :line 5.2 General strategies :h4,link(acc_2) NOTE: this section 5.2 is still a work in progress Here is a list of general ideas for improving simulation performance. Most of them are only applicable to certain models and certain bottlenecks in the current performance, so let the timing data you generate be your guide. It is hard, if not impossible, to predict how much difference these options will make, since it is a function of problem size, number of processors used, and your machine. There is no substitute for identifying performance bottlenecks, and trying out various options. rRESPA 2-FFT PPPM Staggered PPPM single vs double PPPM partial charge PPPM verlet/split run style processor command for proc layout and numa layout load-balancing: balance and fix balance :ul 2-FFT PPPM, also called {analytic differentiation} or {ad} PPPM, uses 2 FFTs instead of the 4 FFTs used by the default {ik differentiation} PPPM. However, 2-FFT PPPM also requires a slightly larger mesh size to achieve the same accuracy as 4-FFT PPPM. For problems where the FFT cost is the performance bottleneck (typically large problems running on many processors), 2-FFT PPPM may be faster than 4-FFT PPPM. Staggered PPPM performs calculations using two different meshes, one shifted slightly with respect to the other. This can reduce force aliasing errors and increase the accuracy of the method, but also doubles the amount of work required. For high relative accuracy, using staggered PPPM allows one to half the mesh size in each dimension as compared to regular PPPM, which can give around a 4x speedup in the kspace time. However, for low relative accuracy, using staggered PPPM gives little benefit and can be up to 2x slower in the kspace time. For example, the rhodopsin benchmark was run on a single processor, and results for kspace time vs. relative accuracy for the different methods are shown in the figure below. For this system, staggered PPPM (using ik differentiation) becomes useful when using a relative accuracy of slightly greater than 1e-5 and above. :c,image(JPG/rhodo_staggered.jpg) NOTE: Using staggered PPPM may not give the same increase in accuracy of energy and pressure as it does in forces, so some caution must be used if energy and/or pressure are quantities of interest, such as when using a barostat. :line 5.3 Packages with optimized styles :h4,link(acc_3) Accelerated versions of various "pair_style"_pair_style.html, "fixes"_fix.html, "computes"_compute.html, and other commands have been added to LAMMPS, which will typically run faster than the standard non-accelerated versions. Some require appropriate hardware to be present on your system, e.g. GPUs or Intel Xeon Phi coprocessors. All of these commands are in packages provided with LAMMPS. An overview of packages is give in "Section packages"_Section_packages.html. These are the accelerator packages currently in LAMMPS, either as standard or user packages: "GPU Package"_accelerate_gpu.html : for NVIDIA GPUs as well as OpenCL support "USER-INTEL Package"_accelerate_intel.html : for Intel CPUs and Intel Xeon Phi "KOKKOS Package"_accelerate_kokkos.html : for Nvidia GPUs, Intel Xeon Phi, and OpenMP threading "USER-OMP Package"_accelerate_omp.html : for OpenMP threading and generic CPU optimizations "OPT Package"_accelerate_opt.html : generic CPU optimizations :tb(s=:) Inverting this list, LAMMPS currently has acceleration support for three kinds of hardware, via the listed packages: Many-core CPUs : "USER-INTEL"_accelerate_intel.html, "KOKKOS"_accelerate_kokkos.html, "USER-OMP"_accelerate_omp.html, "OPT"_accelerate_opt.html packages NVIDIA GPUs : "GPU"_accelerate_gpu.html, "KOKKOS"_accelerate_kokkos.html packages Intel Phi : "USER-INTEL"_accelerate_intel.html, "KOKKOS"_accelerate_kokkos.html packages :tb(s=:) Which package is fastest for your hardware may depend on the size problem you are running and what commands (accelerated and non-accelerated) are invoked by your input script. While these doc pages include performance guidelines, there is no substitute for trying out the different packages appropriate to your hardware. Any accelerated style has the same name as the corresponding standard style, except that a suffix is appended. Otherwise, the syntax for the command that uses the style is identical, their functionality is the same, and the numerical results it produces should also be the same, except for precision and round-off effects. For example, all of these styles are accelerated variants of the Lennard-Jones "pair_style lj/cut"_pair_lj.html: "pair_style lj/cut/gpu"_pair_lj.html "pair_style lj/cut/intel"_pair_lj.html "pair_style lj/cut/kk"_pair_lj.html "pair_style lj/cut/omp"_pair_lj.html "pair_style lj/cut/opt"_pair_lj.html :ul To see what accelerate styles are currently available, see "Section 3.5"_Section_commands.html#cmd_5 of the manual. The doc pages for individual commands (e.g. "pair lj/cut"_pair_lj.html or "fix nve"_fix_nve.html) also list any accelerated variants available for that style. To use an accelerator package in LAMMPS, and one or more of the styles it provides, follow these general steps. Details vary from package to package and are explained in the individual accelerator doc pages, listed above: build the accelerator library | only for GPU package | install the accelerator package | make yes-opt, make yes-user-intel, etc | add compile/link flags to Makefile.machine in src/MAKE | only for USER-INTEL, KOKKOS, USER-OMP, OPT packages | re-build LAMMPS | make machine | prepare and test a regular LAMMPS simulation | lmp_machine -in in.script; mpirun -np 32 lmp_machine -in in.script | enable specific accelerator support via '-k on' "command-line switch"_Section_start.html#start_6, | only needed for KOKKOS package | set any needed options for the package via "-pk" "command-line switch"_Section_start.html#start_6 or "package"_package.html command, | only if defaults need to be changed | use accelerated styles in your input via "-sf" "command-line switch"_Section_start.html#start_6 or "suffix"_suffix.html command | lmp_machine -in in.script -sf gpu :tb(c=2,s=|) -Note that the first 4 steps can be done as a single command, using the -src/Make.py tool. This tool is discussed in "Section +Note that the first 4 steps can be done as a single command with +suitable make command invocations. This is discussed in "Section 4"_Section_packages.html of the manual, and its use is illustrated in the individual accelerator sections. Typically these steps only need to be done once, to create an executable that uses one or more accelerator packages. The last 4 steps can all be done from the command-line when LAMMPS is launched, without changing your input script, as illustrated in the individual accelerator sections. Or you can add "package"_package.html and "suffix"_suffix.html commands to your input script. NOTE: With a few exceptions, you can build a single LAMMPS executable with all its accelerator packages installed. Note however that the USER-INTEL and KOKKOS packages require you to choose one of their hardware options when building for a specific platform. I.e. CPU or Phi option for the USER-INTEL package. Or the OpenMP, Cuda, or Phi option for the KOKKOS package. These are the exceptions. You cannot build a single executable with: both the USER-INTEL Phi and KOKKOS Phi options the USER-INTEL Phi or Kokkos Phi option, and the GPU package :ul See the examples/accelerate/README and make.list files for sample Make.py commands that build LAMMPS with any or all of the accelerator packages. As an example, here is a command that builds with all the GPU related packages installed (GPU, KOKKOS with Cuda), including settings to build the needed auxiliary GPU libraries for Kepler GPUs: Make.py -j 16 -p omp gpu kokkos -cc nvcc wrap=mpi \ -gpu mode=double arch=35 -kokkos cuda arch=35 lib-all file mpi :pre The examples/accelerate directory also has input scripts that can be used with all of the accelerator packages. See its README file for details. Likewise, the bench directory has FERMI and KEPLER and PHI sub-directories with Make.py commands and input scripts for using all the accelerator packages on various machines. See the README files in those dirs. As mentioned above, the "Benchmark page"_http://lammps.sandia.gov/bench.html of the LAMMPS web site gives performance results for the various accelerator packages for several of the standard LAMMPS benchmark problems, as a function of problem size and number of compute nodes, on different hardware platforms. Here is a brief summary of what the various packages provide. Details are in the individual accelerator sections. Styles with a "gpu" suffix are part of the GPU package, and can be run on NVIDIA GPUs. The speed-up on a GPU depends on a variety of factors, discussed in the accelerator sections. :ulb,l Styles with an "intel" suffix are part of the USER-INTEL package. These styles support vectorized single and mixed precision calculations, in addition to full double precision. In extreme cases, this can provide speedups over 3.5x on CPUs. The package also supports acceleration in "offload" mode to Intel(R) Xeon Phi(TM) coprocessors. This can result in additional speedup over 2x depending on the hardware configuration. :l Styles with a "kk" suffix are part of the KOKKOS package, and can be run using OpenMP on multicore CPUs, on an NVIDIA GPU, or on an Intel Xeon Phi in "native" mode. The speed-up depends on a variety of factors, as discussed on the KOKKOS accelerator page. :l Styles with an "omp" suffix are part of the USER-OMP package and allow a pair-style to be run in multi-threaded mode using OpenMP. This can be useful on nodes with high-core counts when using less MPI processes than cores is advantageous, e.g. when running with PPPM so that FFTs are run on fewer MPI processors or when the many MPI tasks would overload the available bandwidth for communication. :l Styles with an "opt" suffix are part of the OPT package and typically speed-up the pairwise calculations of your simulation by 5-25% on a CPU. :l :ule The individual accelerator package doc pages explain: what hardware and software the accelerated package requires how to build LAMMPS with the accelerated package how to run with the accelerated package either via command-line switches or modifying the input script speed-ups to expect guidelines for best performance restrictions :ul :line 5.4 Comparison of various accelerator packages :h4,link(acc_4) NOTE: this section still needs to be re-worked with additional KOKKOS and USER-INTEL information. The next section compares and contrasts the various accelerator options, since there are multiple ways to perform OpenMP threading, run on GPUs, and run on Intel Xeon Phi coprocessors. All 3 of these packages accelerate a LAMMPS calculation using NVIDIA hardware, but they do it in different ways. As a consequence, for a particular simulation on specific hardware, one package may be faster than the other. We give guidelines below, but the best way to determine which package is faster for your input script is to try both of them on your machine. See the benchmarking section below for examples where this has been done. [Guidelines for using each package optimally:] The GPU package allows you to assign multiple CPUs (cores) to a single GPU (a common configuration for "hybrid" nodes that contain multicore CPU(s) and GPU(s)) and works effectively in this mode. :ulb,l The GPU package moves per-atom data (coordinates, forces) back-and-forth between the CPU and GPU every timestep. The KOKKOS/CUDA package only does this on timesteps when a CPU calculation is required (e.g. to invoke a fix or compute that is non-GPU-ized). Hence, if you can formulate your input script to only use GPU-ized fixes and computes, and avoid doing I/O too often (thermo output, dump file snapshots, restart files), then the data transfer cost of the KOKKOS/CUDA package can be very low, causing it to run faster than the GPU package. :l The GPU package is often faster than the KOKKOS/CUDA package, if the number of atoms per GPU is smaller. The crossover point, in terms of atoms/GPU at which the KOKKOS/CUDA package becomes faster depends strongly on the pair style. For example, for a simple Lennard Jones system the crossover (in single precision) is often about 50K-100K atoms per GPU. When performing double precision calculations the crossover point can be significantly smaller. :l Both packages compute bonded interactions (bonds, angles, etc) on the CPU. If the GPU package is running with several MPI processes assigned to one GPU, the cost of computing the bonded interactions is spread across more CPUs and hence the GPU package can run faster. :l When using the GPU package with multiple CPUs assigned to one GPU, its performance depends to some extent on high bandwidth between the CPUs and the GPU. Hence its performance is affected if full 16 PCIe lanes are not available for each GPU. In HPC environments this can be the case if S2050/70 servers are used, where two devices generally share one PCIe 2.0 16x slot. Also many multi-GPU mainboards do not provide full 16 lanes to each of the PCIe 2.0 16x slots. :l :ule [Differences between the two packages:] The GPU package accelerates only pair force, neighbor list, and PPPM calculations. :ulb,l The GPU package requires neighbor lists to be built on the CPU when using exclusion lists, hybrid pair styles, or a triclinic simulation box. :l :ule diff --git a/doc/src/Section_example.txt b/doc/src/Section_example.txt index 26dc3b969..f8b39be17 100644 --- a/doc/src/Section_example.txt +++ b/doc/src/Section_example.txt @@ -1,144 +1,145 @@ "Previous Section"_Section_howto.html - "LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc - "Next Section"_Section_perf.html :c :link(lws,http://lammps.sandia.gov) :link(ld,Manual.html) :link(lc,Section_commands.html#comm) :line 7. Example problems :h3 The LAMMPS distribution includes an examples sub-directory with many sample problems. Many are 2d models that run quickly are are straightforward to visualize, requiring at most a couple of minutes to run on a desktop machine. Each problem has an input script (in.*) and produces a log file (log.*) when it runs. Some use a data file (data.*) of initial coordinates as additional input. A few sample log file run on different machines and different numbers of processors are included in the directories to compare your answers to. E.g. a log file like log.date.crack.foo.P means the "crack" example was run on P processors of machine "foo" on that date (i.e. with that version of LAMMPS). Many of the input files have commented-out lines for creating dump files and image files. If you uncomment the "dump"_dump.html command in the input script, a text dump file will be produced, which can be animated by various "visualization programs"_http://lammps.sandia.gov/viz.html. If you uncomment the "dump image"_dump.html command in the input script, and assuming you have built LAMMPS with a JPG library, JPG snapshot images will be produced when the simulation runs. They can be quickly post-processed into a movie using commands described on the "dump image"_dump_image.html doc page. Animations of many of the examples can be viewed on the Movies section of the "LAMMPS web site"_lws. There are two kinds of sub-directories in the examples dir. Lowercase dirs contain one or a few simple, quick-to-run problems. Uppercase dirs contain up to several complex scripts that illustrate a particular kind of simulation method or model. Some of these run for longer times, e.g. to measure a particular quantity. Lists of both kinds of directories are given below. :line Lowercase directories :h4 accelerate: run with various acceleration options (OpenMP, GPU, Phi) +airebo: polyethylene with AIREBO potential balance: dynamic load balancing, 2d system body: body particles, 2d system cmap: CMAP 5-body contributions to CHARMM force field colloid: big colloid particles in a small particle solvent, 2d system comb: models using the COMB potential coreshell: core/shell model using CORESHELL package controller: use of fix controller as a thermostat crack: crack propagation in a 2d solid deposit: deposit atoms and molecules on a surface dipole: point dipolar particles, 2d system dreiding: methanol via Dreiding FF eim: NaCl using the EIM potential ellipse: ellipsoidal particles in spherical solvent, 2d system flow: Couette and Poiseuille flow in a 2d channel friction: frictional contact of spherical asperities between 2d surfaces gcmc: Grand Canonical Monte Carlo (GCMC) via the fix gcmc command granregion: use of fix wall/region/gran as boundary on granular particles hugoniostat: Hugoniostat shock dynamics indent: spherical indenter into a 2d solid kim: use of potentials in Knowledge Base for Interatomic Models (KIM) meam: MEAM test for SiC and shear (same as shear examples) melt: rapid melt of 3d LJ system micelle: self-assembly of small lipid-like molecules into 2d bilayers min: energy minimization of 2d LJ melt mscg: parameterize a multi-scale coarse-graining (MSCG) model msst: MSST shock dynamics nb3b: use of nonbonded 3-body harmonic pair style neb: nudged elastic band (NEB) calculation for barrier finding nemd: non-equilibrium MD of 2d sheared system obstacle: flow around two voids in a 2d channel peptide: dynamics of a small solvated peptide chain (5-mer) peri: Peridynamic model of cylinder impacted by indenter pour: pouring of granular particles into a 3d box, then chute flow prd: parallel replica dynamics of vacancy diffusion in bulk Si python: using embedded Python in a LAMMPS input script qeq: use of the QEQ package for charge equilibration reax: RDX and TATB models using the ReaxFF rigid: rigid bodies modeled as independent or coupled shear: sideways shear applied to 2d solid, with and without a void snap: NVE dynamics for BCC tantalum crystal using SNAP potential srd: stochastic rotation dynamics (SRD) particles as solvent streitz: use of Streitz/Mintmire potential with charge equilibration tad: temperature-accelerated dynamics of vacancy diffusion in bulk Si vashishta: use of the Vashishta potential voronoi: Voronoi tesselation via compute voronoi/atom command :tb(s=:) Here is how you can run and visualize one of the sample problems: cd indent cp ../../src/lmp_linux . # copy LAMMPS executable to this dir lmp_linux -in in.indent # run the problem :pre Running the simulation produces the files {dump.indent} and {log.lammps}. You can visualize the dump file of snapshots with a variety of 3rd-party tools highlighted on the "Visualization"_http://lammps.sandia.gov/viz.html page of the LAMMPS web site. If you uncomment the "dump image"_dump_image.html line(s) in the input script a series of JPG images will be produced by the run (assuming you built LAMMPS with JPG support; see "Section 2.2"_Section_start.html#start_2 for details). These can be viewed individually or turned into a movie or animated by tools like ImageMagick or QuickTime or various Windows-based tools. See the "dump image"_dump_image.html doc page for more details. E.g. this Imagemagick command would create a GIF file suitable for viewing in a browser. % convert -loop 1 *.jpg foo.gif :pre :line Uppercase directories :h4 ASPHERE: various aspherical particle models, using ellipsoids, rigid bodies, line/triangle particles, etc COUPLE: examples of how to use LAMMPS as a library DIFFUSE: compute diffusion coefficients via several methods ELASTIC: compute elastic constants at zero temperature ELASTIC_T: compute elastic constants at finite temperature KAPPA: compute thermal conductivity via several methods MC: using LAMMPS in a Monte Carlo mode to relax the energy of a system USER: examples for USER packages and USER-contributed commands VISCOSITY: compute viscosity via several methods :tb(s=:) Nearly all of these directories have README files which give more details on how to understand and use their contents. The USER directory has a large number of sub-directories which correspond by name to a USER package. They contain scripts that illustrate how to use the command(s) provided in that package. Many of the sub-directories have their own README files which give further instructions. See the "Section 4"_Section_packages.html doc page for more info on specific USER packages. diff --git a/doc/src/Section_packages.txt b/doc/src/Section_packages.txt index 6afcb2758..ea7b41b0a 100644 --- a/doc/src/Section_packages.txt +++ b/doc/src/Section_packages.txt @@ -1,2658 +1,2658 @@ "Previous Section"_Section_commands.html - "LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc - "Next Section"_Section_accelerate.html :c :link(lws,http://lammps.sandia.gov) :link(ld,Manual.html) :link(lc,Section_commands.html#comm) :line 4. Packages :h3 This section gives an overview of the optional packages that extend LAMMPS functionality with instructions on how to build LAMMPS with each of them. Packages are groups of files that enable a specific set of features. For example, force fields for molecular systems or granular systems are in packages. You can see the list of all packages and "make" commands to manage them by typing "make package" from within the src directory of the LAMMPS distribution. "Section 2.3"_Section_start.html#start_3 gives general info on how to install and un-install packages as part of the LAMMPS build process. There are two kinds of packages in LAMMPS, standard and user packages: "Table of standard packages"_#table_standard "Table of user packages"_#table_user :ul Standard packages are supported by the LAMMPS developers and are written in a syntax and style consistent with the rest of LAMMPS. This means the developers will answer questions about them, debug and fix them if necessary, and keep them compatible with future changes to LAMMPS. User packages have been contributed by users, and begin with the "user" prefix. If they are a single command (single file), they are typically in the user-misc package. User packages don't necessarily meet the requirements of the standard packages. If you have problems using a feature provided in a user package, you may need to contact the contributor directly to get help. Information on how to submit additions you make to LAMMPS as single files or as a standard or user package are given in "this section"_Section_modify.html#mod_15 of the manual. Following the next two tables is a sub-section for each package. It lists authors (if applicable) and summarizes the package contents. It has specific instructions on how to install the package, including (if necessary) downloading or building any extra library it requires. It also gives links to documentation, example scripts, and pictures/movies (if available) that illustrate use of the package. NOTE: To see the complete list of commands a package adds to LAMMPS, just look at the files in its src directory, e.g. "ls src/GRANULAR". Files with names that start with fix, compute, atom, pair, bond, angle, etc correspond to commands with the same style names. In these two tables, the "Example" column is a sub-directory in the examples directory of the distribution which has an input script that uses the package. E.g. "peptide" refers to the examples/peptide directory; USER/atc refers to the examples/USER/atc directory. The "Library" column indicates whether an extra library is needed to build and use the package: dash = no library sys = system library: you likely have it on your machine int = internal library: provided with LAMMPS, but you may need to build it ext = external library: you will need to download and install it on your machine :ul :line :line [Standard packages] :link(table_standard),p Package, Description, Doc page, Example, Library "ASPHERE"_#ASPHERE, aspherical particle models, "Section 6.6.14"_Section_howto.html#howto_14, ellipse, - "BODY"_#BODY, body-style particles, "body"_body.html, body, - "CLASS2"_#CLASS2, class 2 force fields, "pair_style lj/class2"_pair_class2.html, -, - "COLLOID"_#COLLOID, colloidal particles, "atom_style colloid"_atom_style.html, colloid, - "COMPRESS"_#COMPRESS, I/O compression, "dump */gz"_dump.html, -, sys "CORESHELL"_#CORESHELL, adiabatic core/shell model, "Section 6.6.25"_Section_howto.html#howto_25, coreshell, - "DIPOLE"_#DIPOLE, point dipole particles, "pair_style dipole/cut"_pair_dipole.html, dipole, - "GPU"_#GPU, GPU-enabled styles, "Section 5.3.1"_accelerate_gpu.html, WWW bench, int "GRANULAR"_#GRANULAR, granular systems, "Section 6.6.6"_Section_howto.html#howto_6, pour, - -"KIM"_#KIM, openKIM wrapper, "pair_style kim"_pair_kim.html, kim, ext +"KIM"_#KIM, OpenKIM wrapper, "pair_style kim"_pair_kim.html, kim, ext "KOKKOS"_#KOKKOS, Kokkos-enabled styles, "Section 5.3.3"_accelerate_kokkos.html, WWW bench, - "KSPACE"_#KSPACE, long-range Coulombic solvers, "kspace_style"_kspace_style.html, peptide, - "MANYBODY"_#MANYBODY, many-body potentials, "pair_style tersoff"_pair_tersoff.html, shear, - "MC"_#MC, Monte Carlo options, "fix gcmc"_fix_gcmc.html, -, - "MEAM"_#MEAM, modified EAM potential, "pair_style meam"_pair_meam.html, meam, int "MISC"_#MISC, miscellanous single-file commands, -, -, - "MOLECULE"_#MOLECULE, molecular system force fields, "Section 6.6.3"_Section_howto.html#howto_3, peptide, - "MPIIO"_#MPIIO, MPI parallel I/O dump and restart, "dump"_dump.html, -, - "MSCG"_#MSCG, multi-scale coarse-graining wrapper, "fix mscg"_fix_mscg.html, mscg, ext "OPT"_#OPT, optimized pair styles, "Section 5.3.5"_accelerate_opt.html, WWW bench, - "PERI"_#PERI, Peridynamics models, "pair_style peri"_pair_peri.html, peri, - "POEMS"_#POEMS, coupled rigid body motion, "fix poems"_fix_poems.html, rigid, int "PYTHON"_#PYTHON, embed Python code in an input script, "python"_python.html, python, sys "QEQ"_#QEQ, QEq charge equilibration, "fix qeq"_fix_qeq.html, qeq, - "REAX"_#REAX, ReaxFF potential (Fortran), "pair_style reax"_pair_reax.html, reax, int "REPLICA"_#REPLICA, multi-replica methods, "Section 6.6.5"_Section_howto.html#howto_5, tad, - "RIGID"_#RIGID, rigid bodies and constraints, "fix rigid"_fix_rigid.html, rigid, - "SHOCK"_#SHOCK, shock loading methods, "fix msst"_fix_msst.html, -, - "SNAP"_#SNAP, quantum-fitted potential, "pair snap"_pair_snap.html, snap, - "SRD"_#SRD, stochastic rotation dynamics, "fix srd"_fix_srd.html, srd, - "VORONOI"_#VORONOI, Voronoi tesselation, "compute voronoi/atom"_compute_voronoi_atom.html, -, ext :tb(ea=c,ca1=l) [USER packages] :link(table_user),p Package, Description, Doc page, Example, Library "USER-ATC"_#USER-ATC, atom-to-continuum coupling, "fix atc"_fix_atc.html, USER/atc, int "USER-AWPMD"_#USER-AWPMD, wave-packet MD, "pair_style awpmd/cut"_pair_awpmd.html, USER/awpmd, int "USER-CGDNA"_#USER-CGDNA, coarse-grained DNA force fields, src/USER-CGDNA/README, USER/cgdna, - "USER-CGSDK"_#USER-CGSDK, SDK coarse-graining model, "pair_style lj/sdk"_pair_sdk.html, USER/cgsdk, - "USER-COLVARS"_#USER-COLVARS, collective variables library, "fix colvars"_fix_colvars.html, USER/colvars, int "USER-DIFFRACTION"_#USER-DIFFRACTION, virtual x-ray and electron diffraction,"compute xrd"_compute_xrd.html, USER/diffraction, - "USER-DPD"_#USER-DPD, reactive dissipative particle dynamics, src/USER-DPD/README, USER/dpd, - "USER-DRUDE"_#USER-DRUDE, Drude oscillators, "tutorial"_tutorial_drude.html, USER/drude, - "USER-EFF"_#USER-EFF, electron force field,"pair_style eff/cut"_pair_eff.html, USER/eff, - "USER-FEP"_#USER-FEP, free energy perturbation,"compute fep"_compute_fep.html, USER/fep, - "USER-H5MD"_#USER-H5MD, dump output via HDF5,"dump h5md"_dump_h5md.html, -, ext "USER-INTEL"_#USER-INTEL, optimized Intel CPU and KNL styles,"Section 5.3.2"_accelerate_intel.html, WWW bench, - "USER-LB"_#USER-LB, Lattice Boltzmann fluid,"fix lb/fluid"_fix_lb_fluid.html, USER/lb, - "USER-MANIFOLD"_#USER-MANIFOLD, motion on 2d surfaces,"fix manifoldforce"_fix_manifoldforce.html, USER/manifold, - "USER-MEAMC"_#USER-MEAMC, modified EAM potential (C++), "pair_style meam/c"_pair_meam.html, meam, - "USER-MGPT"_#USER-MGPT, fast MGPT multi-ion potentials, "pair_style mgpt"_pair_mgpt.html, USER/mgpt, - "USER-MISC"_#USER-MISC, single-file contributions, USER-MISC/README, USER/misc, - "USER-MOLFILE"_#USER-MOLFILE, "VMD"_vmd_home molfile plug-ins,"dump molfile"_dump_molfile.html, -, ext "USER-NETCDF"_#USER-NETCDF, dump output via NetCDF,"dump netcdf"_dump_netcdf.html, -, ext "USER-OMP"_#USER-OMP, OpenMP-enabled styles,"Section 5.3.4"_accelerate_omp.html, WWW bench, - "USER-PHONON"_#USER-PHONON, phonon dynamical matrix,"fix phonon"_fix_phonon.html, USER/phonon, - "USER-QMMM"_#USER-QMMM, QM/MM coupling,"fix qmmm"_fix_qmmm.html, USER/qmmm, ext "USER-QTB"_#USER-QTB, quantum nuclear effects,"fix qtb"_fix_qtb.html "fix qbmsst"_fix_qbmsst.html, qtb, - "USER-QUIP"_#USER-QUIP, QUIP/libatoms interface,"pair_style quip"_pair_quip.html, USER/quip, ext "USER-REAXC"_#USER-REAXC, ReaxFF potential (C/C++) ,"pair_style reaxc"_pair_reaxc.html, reax, - "USER-SMD"_#USER-SMD, smoothed Mach dynamics,"SMD User Guide"_PDF/SMD_LAMMPS_userguide.pdf, USER/smd, ext "USER-SMTBQ"_#USER-SMTBQ, second moment tight binding QEq potential,"pair_style smtbq"_pair_smtbq.html, USER/smtbq, - "USER-SPH"_#USER-SPH, smoothed particle hydrodynamics,"SPH User Guide"_PDF/SPH_LAMMPS_userguide.pdf, USER/sph, - "USER-TALLY"_#USER-TALLY, pairwise tally computes,"compute XXX/tally"_compute_tally.html, USER/tally, - "USER-VTK"_#USER-VTK, dump output via VTK, "compute vtk"_dump_vtk.html, -, ext :tb(ea=c,ca1=l) :line :line ASPHERE package :link(ASPHERE),h4 [Contents:] Computes, time-integration fixes, and pair styles for aspherical particle models including ellipsoids, 2d lines, and 3d triangles. [Install or un-install:] make yes-asphere make machine :pre make no-asphere make machine :pre [Supporting info:] src/ASPHERE: filenames -> commands "Section 6.14"_Section_howto.html#howto_14 "pair_style gayberne"_pair_gayberne.html "pair_style resquared"_pair_resquared.html "doc/PDF/pair_gayberne_extra.pdf"_PDF/pair_gayberne_extra.pdf "doc/PDF/pair_resquared_extra.pdf"_PDF/pair_resquared_extra.pdf examples/ASPHERE examples/ellipse http://lammps.sandia.gov/movies.html#line http://lammps.sandia.gov/movies.html#tri :ul :line BODY package :link(BODY),h4 [Contents:] Body-style particles with internal structure. Computes, time-integration fixes, pair styles, as well as the body styles themselves. See the "body"_body.html doc page for an overview. [Install or un-install:] make yes-body make machine :pre make no-body make machine :pre [Supporting info:] src/BODY filenames -> commands "body"_body.html "atom_style body"_atom_style.html "fix nve/body"_fix_nve_body.html "pair_style body"_pair_body.html examples/body :ul :line CLASS2 package :link(CLASS2),h4 [Contents:] Bond, angle, dihedral, improper, and pair styles for the COMPASS CLASS2 molecular force field. [Install or un-install:] make yes-class2 make machine :pre make no-class2 make machine :pre [Supporting info:] src/CLASS2: filenames -> commands "bond_style class2"_bond_class2.html "angle_style class2"_angle_class2.html "dihedral_style class2"_dihedral_class2.html "improper_style class2"_improper_class2.html "pair_style lj/class2"_pair_class2.html :ul :line COLLOID package :link(COLLOID),h4 [Contents:] Coarse-grained finite-size colloidal particles. Pair stayle and fix wall styles for colloidal interactions. Includes the Fast Lubrication Dynamics (FLD) method for hydrodynamic interactions, which is a simplified approximation to Stokesian dynamics. [Authors:] This package includes Fast Lubrication Dynamics pair styles which were created by Amit Kumar and Michael Bybee from Jonathan Higdon's group at UIUC. [Install or un-install:] make yes-colloid make machine :pre make no-colloid make machine :pre [Supporting info:] src/COLLOID: filenames -> commands "fix wall/colloid"_fix_wall.html "pair_style colloid"_pair_colloid.html "pair_style yukawa/colloid"_pair_yukawa_colloid.html "pair_style brownian"_pair_brownian.html "pair_style lubricate"_pair_lubricate.html "pair_style lubricateU"_pair_lubricateU.html examples/colloid examples/srd :ul :line COMPRESS package :link(COMPRESS),h4 [Contents:] Compressed output of dump files via the zlib compression library, using dump styles with a "gz" in their style name. To use this package you must have the zlib compression library available on your system. [Author:] Axel Kohlmeyer (Temple U). [Install or un-install:] Note that building with this package assumes you have the zlib compression library available on your system. The LAMMPS build uses the settings in the lib/compress/Makefile.lammps file in the compile/link process. You should only need to edit this file if the LAMMPS build fails on your system. make yes-compress make machine :pre make no-compress make machine :pre [Supporting info:] src/COMPRESS: filenames -> commands src/COMPRESS/README lib/compress/README "dump atom/gz"_dump.html "dump cfg/gz"_dump.html "dump custom/gz"_dump.html "dump xyz/gz"_dump.html :ul :line CORESHELL package :link(CORESHELL),h4 [Contents:] Compute and pair styles that implement the adiabatic core/shell model for polarizability. The pair styles augment Born, Buckingham, and Lennard-Jones styles with core/shell capabilities. The "compute temp/cs"_compute_temp_cs.html command calculates the temperature of a system with core/shell particles. See "Section 6.26"_Section_howto.html#howto_26 for an overview of how to use this package. [Author:] Hendrik Heenen (Technical U of Munich). [Install or un-install:] make yes-coreshell make machine :pre make no-coreshell make machine :pre [Supporting info:] src/CORESHELL: filenames -> commands "Section 6.26"_Section_howto.html#howto_26 "Section 6.25"_Section_howto.html#howto_25 "compute temp/cs"_compute_temp_cs.html "pair_style born/coul/long/cs"_pair_cs.html "pair_style buck/coul/long/cs"_pair_cs.html "pair_style lj/cut/coul/long/cs"_pair_lj.html examples/coreshell :ul :line DIPOLE package :link(DIPOLE),h4 [Contents:] An atom style and several pair styles for point dipole models with short-range or long-range interactions. [Install or un-install:] make yes-dipole make machine :pre make no-dipole make machine :pre [Supporting info:] src/DIPOLE: filenames -> commands "atom_style dipole"_atom_style.html "pair_style lj/cut/dipole/cut"_pair_dipole.html "pair_style lj/cut/dipole/long"_pair_dipole.html "pair_style lj/long/dipole/long"_pair_dipole.html examples/dipole :ul :line GPU package :link(GPU),h4 [Contents:] Dozens of pair styles and a version of the PPPM long-range Coulombic solver optimized for NVIDIA GPUs. All such styles have a "gpu" as a suffix in their style name. "Section 5.3.1"_accelerate_gpu.html gives details of what hardware and Cuda software is required on your system, and details on how to build and use this package. Its styles can be invoked at run time via the "-sf gpu" or "-suffix gpu" "command-line switches"_Section_start.html#start_6. See also the "KOKKOS"_#KOKKOS package, which has GPU-enabled styles. [Authors:] Mike Brown (Intel) while at Sandia and ORNL and Trung Nguyen (Northwestern U) while at ORNL. [Install or un-install:] Before building LAMMPS with this package, you must first build the GPU library in lib/gpu from a set of provided C and Cuda files. You can do this manually if you prefer; follow the instructions in lib/gpu/README. You can also do it in one step from the lammps/src dir, using a command like these, which simply invoke the lib/gpu/Install.py script with the specified args: make lib-gpu # print help message make lib-gpu args="-m" # build GPU library with default Makefile.linux make lib-gpu args="-i xk7 -p single -o xk7.single" # create new Makefile.xk7.single, altered for single-precision make lib-gpu args="-i xk7 -p single -o xk7.single -m" # ditto, also build GPU library Note that this procedure starts with one of the existing Makefile.machine files in lib/gpu. It allows you to alter 4 important settings in that Makefile, via the -h, -a, -p, -e switches, and save the new Makefile, if desired: CUDA_HOME = where NVIDIA Cuda software is installed on your system CUDA_ARCH = what GPU hardware you have (see help message for details) CUDA_PRECISION = precision (double, mixed, single) EXTRAMAKE = which Makefile.lammps.* file to copy to Makefile.lammps :ul If the library build is successful, 2 files should be created: lib/gpu/libgpu.a and lib/gpu/Makefile.lammps. The latter has settings that enable LAMMPS to link with Cuda libraries. If the settings in Makefile.lammps for your machine are not correct, the LAMMPS build will fail. You can then install/un-install the package and build LAMMPS in the usual manner: make yes-gpu make machine :pre make no-gpu make machine :pre NOTE: If you re-build the GPU library in lib/gpu, you should always un-install the GPU package, then re-install it and re-build LAMMPS. This is because the compilation of files in the GPU package use the library settings from the lib/gpu/Makefile.machine used to build the GPU library. [Supporting info:] src/GPU: filenames -> commands src/GPU/README lib/gpu/README "Section 5.3"_Section_accelerate.html#acc_3 "Section 5.3.1"_accelerate_gpu.html "Section 2.6 -sf gpu"_Section_start.html#start_6 "Section 2.6 -pk gpu"_Section_start.html#start_6 "package gpu"_package.html Pair Styles section of "Section 3.5"_Section_commands.html#cmd_5 for pair styles followed by (g) "Benchmarks page"_http://lammps.sandia.gov/bench.html of web site :ul :line GRANULAR package :link(GRANULAR),h4 [Contents:] Pair styles and fixes for finite-size granular particles, which interact with each other and boundaries via frictional and dissipative potentials. [Install or un-install:] make yes-granular make machine :pre make no-granular make machine :pre [Supporting info:] src/GRANULAR: filenames -> commands "Section 6.6"_Section_howto.html#howto_6, "fix pour"_fix_pour.html "fix wall/gran"_fix_wall_gran.html "pair_style gran/hooke"_pair_gran.html "pair_style gran/hertz/history"_pair_gran.html examples/granregion examples/pour bench/in.chute http://lammps.sandia.gov/pictures.html#jamming http://lammps.sandia.gov/movies.html#hopper http://lammps.sandia.gov/movies.html#dem http://lammps.sandia.gov/movies.html#brazil http://lammps.sandia.gov/movies.html#granregion :ul :line KIM package :link(KIM),h4 [Contents:] A "pair_style kim"_pair_kim.html command which is a wrapper on the Knowledge Base for Interatomic Models (KIM) repository of interatomic potentials, enabling any of them to be used in LAMMPS simulations. To use this package you must have the KIM library available on your system. Information about the KIM project can be found at its website: https://openkim.org. The KIM project is led by Ellad Tadmor and Ryan Elliott (U Minnesota) and James Sethna (Cornell U). [Authors:] Ryan Elliott (U Minnesota) is the main developer for the KIM API which the "pair_style kim"_pair_kim.html command uses. He developed the pair style in collaboration with Valeriu Smirichinski (U Minnesota). [Install or un-install:] Before building LAMMPS with this package, you must first download and build the KIM library and include the KIM models that you want to use. You can do this manually if you prefer; follow the instructions in lib/kim/README. You can also do it in one step from the lammps/src dir, using a command like these, which simply invoke the lib/kim/Install.py script with the specified args. make lib-kim # print help message make lib-kim args="-b . none" # install KIM API lib with only example models make lib-kim args="-b . Glue_Ercolessi_Adams_Al__MO_324507536345_001" # ditto plus one model make lib-kim args="-b . OpenKIM" # install KIM API lib with all models make lib-kim args="-a EAM_Dynamo_Ackland_W__MO_141627196590_002" # add one model or model driver :pre Note that in LAMMPS lingo, a KIM model driver is a pair style (e.g. EAM or Tersoff). A KIM model is a pair style for a particular element or alloy and set of parameters, e.g. EAM for Cu with a specific EAM potential file. Also note that installing the KIM API library with all its models, may take around 30 min to build. Of course you only need to do that once. See the list of KIM model drivers here: https://openkim.org/kim-items/model-drivers/alphabetical See the list of all KIM models here: https://openkim.org/kim-items/models/by-model-drivers See the list of example KIM models included by default here: https://openkim.org/kim-api in the "What is in the KIM API source package?" section You can then install/un-install the package and build LAMMPS in the usual manner: make yes-kim make machine :pre make no-kim make machine :pre [Supporting info:] src/KIM: filenames -> commands src/KIM/README lib/kim/README "pair_style kim"_pair_kim.html examples/kim :ul :line KOKKOS package :link(KOKKOS),h4 [Contents:] Dozens of atom, pair, bond, angle, dihedral, improper, fix, compute styles adapted to compile using the Kokkos library which can convert them to OpenMP or Cuda code so that they run efficiently on multicore CPUs, KNLs, or GPUs. All the styles have a "kk" as a suffix in their style name. "Section 5.3.3"_accelerate_kokkos.html gives details of what hardware and software is required on your system, and how to build and use this package. Its styles can be invoked at run time via the "-sf kk" or "-suffix kk" "command-line switches"_Section_start.html#start_6. Also see the "GPU"_#GPU, "OPT"_#OPT, "USER-INTEL"_#USER-INTEL, and "USER-OMP"_#USER-OMP packages, which have styles optimized for CPUs, KNLs, and GPUs. You must have a C++11 compatible compiler to use this package. [Authors:] The KOKKOS package was created primarily by Christian Trott and Stan Moore (Sandia), with contributions from other folks as well. It uses the open-source "Kokkos library"_https://github.com/kokkos which was developed by Carter Edwards, Christian Trott, and others at Sandia, and which is included in the LAMMPS distribution in lib/kokkos. [Install or un-install:] For the KOKKOS package, you have 3 choices when building. You can build with either CPU or KNL or GPU support. Each choice requires additional settings in your Makefile.machine for the KOKKOS_DEVICES and KOKKOS_ARCH settings. See the src/MAKE/OPTIONS/Makefile.kokkos* files for examples. For multicore CPUs using OpenMP: KOKKOS_DEVICES = OpenMP KOKKOS_ARCH = HSW # HSW = Haswell, SNB = SandyBridge, BDW = Broadwell, etc For Intel KNLs using OpenMP: KOKKOS_DEVICES = OpenMP KOKKOS_ARCH = KNL For NVIDIA GPUs using Cuda: KOKKOS_DEVICES = Cuda KOKKOS_ARCH = Pascal60,Power8 # P100 hosted by an IBM Power8, etc KOKKOS_ARCH = Kepler37,Power8 # K80 hosted by an IBM Power8, etc For GPUs, you also need these 2 lines in your Makefile.machine before the CC line is defined, in this case for use with OpenMPI mpicxx. The 2 lines define a nvcc wrapper compiler, which will use nvcc for compiling Cuda files or use a C++ compiler for non-Kokkos, non-Cuda files. KOKKOS_ABSOLUTE_PATH = $(shell cd $(KOKKOS_PATH); pwd) export OMPI_CXX = $(KOKKOS_ABSOLUTE_PATH)/config/nvcc_wrapper CC = mpicxx Once you have an appropriate Makefile.machine, you can install/un-install the package and build LAMMPS in the usual manner. Note that you cannot build one executable to run on multiple hardware targets (CPU or KNL or GPU). You need to build LAMMPS once for each hardware target, to produce a separate executable. Also note that we do not recommend building with other acceleration packages installed (GPU, OPT, USER-INTEL, USER-OMP) when also building with KOKKOS. make yes-kokkos make machine :pre make no-kokkos make machine :pre [Supporting info:] src/KOKKOS: filenames -> commands src/KOKKOS/README lib/kokkos/README "Section 5.3"_Section_accelerate.html#acc_3 "Section 5.3.3"_accelerate_kokkos.html "Section 2.6 -k on ..."_Section_start.html#start_6 "Section 2.6 -sf kk"_Section_start.html#start_6 "Section 2.6 -pk kokkos"_Section_start.html#start_6 "package kokkos"_package.html Styles sections of "Section 3.5"_Section_commands.html#cmd_5 for styles followed by (k) "Benchmarks page"_http://lammps.sandia.gov/bench.html of web site :ul :line KSPACE package :link(KSPACE),h4 [Contents:] A variety of long-range Coulombic solvers, as well as pair styles which compute the corresponding short-range pairwise Coulombic interactions. These include Ewald, particle-particle particle-mesh (PPPM), and multilevel summation method (MSM) solvers. [Install or un-install:] Building with this package requires a 1d FFT library be present on your system for use by the PPPM solvers. This can be the KISS FFT library provided with LAMMPS, 3rd party libraries like FFTW, or a vendor-supplied FFT library. See step 6 of "Section 2.2.2"_Section_start.html#start_2_2 of the manual for details on how to select different FFT options in your machine Makefile. make yes-kspace make machine :pre make no-kspace make machine :pre [Supporting info:] src/KSPACE: filenames -> commands "kspace_style"_kspace_style.html "doc/PDF/kspace.pdf"_PDF/kspace.pdf "Section 6.7"_Section_howto.html#howto_7 "Section 6.8"_Section_howto.html#howto_8 "Section 6.9"_Section_howto.html#howto_9 "pair_style coul"_pair_coul.html Pair Styles section of "Section 3.5"_Section_commands.html#cmd_5 with "long" or "msm" in pair style name examples/peptide bench/in.rhodo :ul :line MANYBODY package :link(MANYBODY),h4 [Contents:] A variety of manybody and bond-order potentials. These include (AI)REBO, BOP, EAM, EIM, Stillinger-Weber, and Tersoff potentials. [Install or un-install:] make yes-manybody make machine :pre make no-manybody make machine :pre [Supporting info:] src/MANYBODY: filenames -> commands Pair Styles section of "Section 3.5"_Section_commands.html#cmd_5 examples/comb examples/eim examples/nb3d examples/shear examples/streitz examples/vashishta bench/in.eam :ul :line MC package :link(MC),h4 [Contents:] Several fixes and a pair style that have Monte Carlo (MC) or MC-like attributes. These include fixes for creating, breaking, and swapping bonds, for performing atomic swaps, and performing grand-canonical MC (GCMC) in conjuction with dynamics. [Install or un-install:] make yes-mc make machine :pre make no-mc make machine :pre [Supporting info:] src/MC: filenames -> commands "fix atom/swap"_fix_atom_swap.html "fix bond/break"_fix_bond_break.html "fix bond/create"_fix_bond_create.html "fix bond/swap"_fix_bond_swap.html "fix gcmc"_fix_gcmc.html "pair_style dsmc"_pair_dsmc.html http://lammps.sandia.gov/movies.html#gcmc :ul :line MEAM package :link(MEAM),h4 [Contents:] A pair style for the modified embedded atom (MEAM) potential. [Author:] Greg Wagner (Northwestern U) while at Sandia. [Install or un-install:] Before building LAMMPS with this package, you must first build the MEAM library in lib/meam. You can do this manually if you prefer; follow the instructions in lib/meam/README. You can also do it in one step from the lammps/src dir, using a command like these, which simply invoke the lib/meam/Install.py script with the specified args: make lib-meam # print help message make lib-meam args="-m gfortran" # build with GNU Fortran compiler make lib-meam args="-m ifort" # build with Intel ifort compiler :pre The build should produce two files: lib/meam/libmeam.a and lib/meam/Makefile.lammps. The latter is copied from an existing Makefile.lammps.* and has settings needed to link C++ (LAMMPS) with Fortran (MEAM library). Typically the two compilers used for LAMMPS and the MEAM library need to be consistent (e.g. both Intel or both GNU compilers). If necessary, you can edit/create a new lib/meam/Makefile.machine file for your system, which should define an EXTRAMAKE variable to specify a corresponding Makefile.lammps.machine file. You can then install/un-install the package and build LAMMPS in the usual manner: make yes-meam make machine :pre make no-meam make machine :pre NOTE: You should test building the MEAM library with both the Intel and GNU compilers to see if a simulation runs faster with one versus the other on your system. [Supporting info:] src/MEAM: filenames -> commands src/meam/README lib/meam/README "pair_style meam"_pair_meam.html examples/meam :ul :line MISC package :link(MISC),h4 [Contents:] A variety of compute, fix, pair, dump styles with specialized capabilities that don't align with other packages. Do a directory listing, "ls src/MISC", to see the list of commands. [Install or un-install:] make yes-misc make machine :pre make no-misc make machine :pre [Supporting info:] src/MISC: filenames -> commands "compute ti"_compute_ti.html "fix evaporate"_fix_evaporate.html "fix orient/fcc"_fix_orient.html "fix ttm"_fix_ttm.html "fix thermal/conductivity"_fix_thermal_conductivity.html "fix viscosity"_fix_viscosity.html examples/KAPPA examples/VISCOSITY http://lammps.sandia.gov/pictures.html#ttm http://lammps.sandia.gov/movies.html#evaporation :ul :line MOLECULE package :link(MOLECULE),h4 [Contents:] A large number of atom, pair, bond, angle, dihedral, improper styles that are used to model molecular systems with fixed covalent bonds. The pair styles include the Dreiding (hydrogen-bonding) and CHARMM force fields, and a TIP4P water model. [Install or un-install:] make yes-molecule make machine :pre make no-molecule make machine :pre [Supporting info:] src/MOLECULE: filenames -> commands "atom_style"_atom_style.html "bond_style"_bond_style.html "angle_style"_angle_style.html "dihedral_style"_dihedral_style.html "improper_style"_improper_style.html "pair_style hbond/dreiding/lj"_pair_hbond_dreiding.html "pair_style lj/charmm/coul/charmm"_pair_charmm.html "Section 6.3"_Section_howto.html#howto_3 examples/cmap examples/dreiding examples/micelle, examples/peptide bench/in.chain bench/in.rhodo :ul :line MPIIO package :link(MPIIO),h4 [Contents:] Support for parallel output/input of dump and restart files via the MPIIO library. It adds "dump styles"_dump.html with a "mpiio" in their style name. Restart files with an ".mpiio" suffix are also written and read in parallel. [Install or un-install:] Note that MPIIO is part of the standard message-passing interface (MPI) library, so you should not need any additional compiler or link settings, beyond what LAMMPS normally uses for MPI on your system. make yes-mpiio make machine :pre make no-mpiio make machine :pre [Supporting info:] src/MPIIO: filenames -> commands "dump"_dump.html "restart"_restart.html "write_restart"_write_restart.html "read_restart"_read_restart.html :ul :line MSCG package :link(mscg),h4 [Contents:] A "fix mscg"_fix_mscg.html command which can parameterize a Mulit-Scale Coarse-Graining (MSCG) model using the open-source "MS-CG library"_mscg_home. :link(mscg_home,https://github.com/uchicago-voth/MSCG-release) To use this package you must have the MS-CG library available on your system. [Authors:] The fix was written by Lauren Abbott (Sandia). The MS-CG library was developed by Jacob Wagner in Greg Voth's group at the University of Chicago. [Install or un-install:] Before building LAMMPS with this package, you must first download and build the MS-CG library. Building the MS-CG library and using it from LAMMPS requires a C++11 compatible compiler, and that LAPACK and GSL (GNU Scientific Library) libraries be installed on your machine. See the lib/mscg/README and MSCG/Install files for more details. Assuming these libraries are in place, you can do the download and build of MS-CG manually if you prefer; follow the instructions in lib/mscg/README. You can also do it in one step from the lammps/src dir, using a command like these, which simply invoke the lib/mscg/Install.py script with the specified args: make lib-mscg # print help message make lib-mscg args="-g -b -l" # download and build in default lib/mscg/MSCG-release-master make lib-mscg args="-h . MSCG -g -b -l" # download and build in lib/mscg/MSCG make lib-mscg args="-h ~ MSCG -g -b -l" # download and build in ~/mscg :pre Note that the final -l switch is to create 2 symbolic (soft) links, "includelink" and "liblink", in lib/mscg to point to the MS-CG src dir. When LAMMPS builds it will use these links. You should not need to edit the lib/mscg/Makefile.lammps file. You can then install/un-install the package and build LAMMPS in the usual manner: make yes-mscg make machine :pre make no-mscg make machine :pre [Supporting info:] src/MSCG: filenames -> commands src/MSCG/README lib/mscg/README examples/mscg :ul :line OPT package :link(OPT),h4 [Contents:] A handful of pair styles which are optimized for improved CPU performance on single or multiple cores. These include EAM, LJ, CHARMM, and Morse potentials. The styles have an "opt" suffix in their style name. "Section 5.3.5"_accelerate_opt.html gives details of how to build and use this package. Its styles can be invoked at run time via the "-sf opt" or "-suffix opt" "command-line switches"_Section_start.html#start_6. See also the "KOKKOS"_#KOKKOS, "USER-INTEL"_#USER-INTEL, and "USER-OMP"_#USER-OMP packages, which have styles optimized for CPU performance. [Authors:] James Fischer (High Performance Technologies), David Richie, and Vincent Natoli (Stone Ridge Technolgy). [Install or un-install:] make yes-opt make machine :pre make no-opt make machine :pre NOTE: The compile flag "-restrict" must be used to build LAMMPS with the OPT package. It should be added to the CCFLAGS line of your Makefile.machine. See Makefile.opt in src/MAKE/OPTIONS for an example. CCFLAGS: add -restrict :ul [Supporting info:] src/OPT: filenames -> commands "Section 5.3"_Section_accelerate.html#acc_3 "Section 5.3.5"_accelerate_opt.html "Section 2.6 -sf opt"_Section_start.html#start_6 Pair Styles section of "Section 3.5"_Section_commands.html#cmd_5 for pair styles followed by (t) "Benchmarks page"_http://lammps.sandia.gov/bench.html of web site :ul :line PERI package :link(PERI),h4 [Contents:] An atom style, several pair styles which implement different Peridynamics materials models, and several computes which calculate diagnostics. Peridynamics is a a particle-based meshless continuum model. [Authors:] The original package was created by Mike Parks (Sandia). Additional Peridynamics models were added by Rezwanur Rahman and John Foster (UTSA). [Install or un-install:] make yes-peri make machine :pre make no-peri make machine :pre [Supporting info:] src/PERI: filenames -> commands "doc/PDF/PDLammps_overview.pdf"_PDF/PDLammps_overview.pdf "doc/PDF/PDLammps_EPS.pdf"_PDF/PDLammps_EPS.pdf "doc/PDF/PDLammps_VES.pdf"_PDF/PDLammps_VES.pdf "atom_style peri"_atom_style.html "pair_style peri/*"_pair_peri.html "compute damage/atom"_compute_damage_atom.html "compute plasticity/atom"_compute_plasticity_atom.html examples/peri http://lammps.sandia.gov/movies.html#peri :ul :line POEMS package :link(POEMS),h4 [Contents:] A fix that wraps the Parallelizable Open source Efficient Multibody Software (POEMS) library, which is able to simulate the dynamics of articulated body systems. These are systems with multiple rigid bodies (collections of particles) whose motion is coupled by connections at hinge points. [Author:] Rudra Mukherjee (JPL) while at RPI. [Install or un-install:] Before building LAMMPS with this package, you must first build the POEMS library in lib/poems. You can do this manually if you prefer; follow the instructions in lib/poems/README. You can also do it in one step from the lammps/src dir, using a command like these, which simply invoke the lib/poems/Install.py script with the specified args: make lib-poems # print help message make lib-poems args="-m g++" # build with GNU g++ compiler make lib-poems args="-m icc" # build with Intel icc compiler :pre The build should produce two files: lib/poems/libpoems.a and lib/poems/Makefile.lammps. The latter is copied from an existing Makefile.lammps.* and has settings needed to build LAMMPS with the POEMS library (though typically the settings are just blank). If necessary, you can edit/create a new lib/poems/Makefile.machine file for your system, which should define an EXTRAMAKE variable to specify a corresponding Makefile.lammps.machine file. You can then install/un-install the package and build LAMMPS in the usual manner: make yes-poems make machine :pre make no-meam make machine :pre [Supporting info:] src/POEMS: filenames -> commands src/POEMS/README lib/poems/README "fix poems"_fix_poems.html examples/rigid :ul :line PYTHON package :link(PYTHON),h4 [Contents:] A "python"_python.html command which allow you to execute Python code from a LAMMPS input script. The code can be in a separate file or embedded in the input script itself. See "Section 11.2"_Section_python.html#py_2 for an overview of using Python from LAMMPS in this manner and the entire section for other ways to use LAMMPS and Python together. [Install or un-install:] make yes-python make machine :pre make no-python make machine :pre NOTE: Building with the PYTHON package assumes you have a Python shared library available on your system, which needs to be a Python 2 version, 2.6 or later. Python 3 is not yet supported. See the lib/python/README for more details. Note that the build uses the lib/python/Makefile.lammps file in the compile/link process. You should only need to create a new Makefile.lammps.* file (and copy it to Makefile.lammps) if the LAMMPS build fails. [Supporting info:] src/PYTHON: filenames -> commands "Section 11"_Section_python.html lib/python/README examples/python :ul :line QEQ package :link(QEQ),h4 [Contents:] Several fixes for performing charge equilibration (QEq) via different algorithms. These can be used with pair styles that perform QEq as part of their formulation. [Install or un-install:] make yes-qeq make machine :pre make no-qeq make machine :pre [Supporting info:] src/QEQ: filenames -> commands "fix qeq/*"_fix_qeq.html examples/qeq examples/streitz :ul :line REAX package :link(REAX),h4 [Contents:] A pair style which wraps a Fortran library which implements the ReaxFF potential, which is a universal reactive force field. See the "USER-REAXC package"_#USER-REAXC for an alternate implementation in C/C++. Also a "fix reax/bonds"_fix_reax_bonds.html command for monitoring molecules as bonds are created and destroyed. [Author:] Aidan Thompson (Sandia). [Install or un-install:] Before building LAMMPS with this package, you must first build the REAX library in lib/reax. You can do this manually if you prefer; follow the instructions in lib/reax/README. You can also do it in one step from the lammps/src dir, using a command like these, which simply invoke the lib/reax/Install.py script with the specified args: make lib-reax # print help message make lib-reax args="-m gfortran" # build with GNU Fortran compiler make lib-reax args="-m ifort" # build with Intel ifort compiler :pre The build should produce two files: lib/reax/libreax.a and lib/reax/Makefile.lammps. The latter is copied from an existing Makefile.lammps.* and has settings needed to link C++ (LAMMPS) with Fortran (REAX library). Typically the two compilers used for LAMMPS and the REAX library need to be consistent (e.g. both Intel or both GNU compilers). If necessary, you can edit/create a new lib/reax/Makefile.machine file for your system, which should define an EXTRAMAKE variable to specify a corresponding Makefile.lammps.machine file. You can then install/un-install the package and build LAMMPS in the usual manner: make yes-reax make machine :pre make no-reax make machine :pre [Supporting info:] src/REAX: filenames -> commands lib/reax/README "pair_style reax"_pair_reax.html "fix reax/bonds"_fix_reax_bonds.html examples/reax :ul :line REPLICA package :link(REPLICA),h4 [Contents:] A collection of multi-replica methods which can be used when running multiple LAMMPS simulations (replicas). See "Section 6.5"_Section_howto.html#howto_5 for an overview of how to run multi-replica simulations in LAMMPS. Methods in the package include nudged elastic band (NEB), parallel replica dynamics (PRD), temperature accelerated dynamics (TAD), parallel tempering, and a verlet/split algorithm for performing long-range Coulombics on one set of processors, and the remainder of the force field calcalation on another set. [Install or un-install:] make yes-replica make machine :pre make no-replica make machine :pre [Supporting info:] src/REPLICA: filenames -> commands "Section 6.5"_Section_howto.html#howto_5 "neb"_neb.html "prd"_prd.html "tad"_tad.html "temper"_temper.html, "run_style verlet/split"_run_style.html examples/neb examples/prd examples/tad :ul :line RIGID package :link(RIGID),h4 [Contents:] Fixes which enforce rigid constraints on collections of atoms or particles. This includes SHAKE and RATTLE, as well as varous rigid-body integrators for a few large bodies or many small bodies. Also several computes which calculate properties of rigid bodies. To install/build: make yes-rigid make machine :pre To un-install/re-build: make no-rigid make machine :pre [Supporting info:] src/RIGID: filenames -> commands "compute erotate/rigid"_compute_erotate_rigid.html fix shake"_fix_shake.html "fix rattle"_fix_shake.html "fix rigid/*"_fix_rigid.html examples/ASPHERE examples/rigid bench/in.rhodo http://lammps.sandia.gov/movies.html#box http://lammps.sandia.gov/movies.html#star :ul :line SHOCK package :link(SHOCK),h4 [Contents:] Fixes for running impact simulations where a shock-wave passes through a material. [Install or un-install:] make yes-shock make machine :pre make no-shock make machine :pre [Supporting info:] src/SHOCK: filenames -> commands "fix append/atoms"_fix_append_atoms.html "fix msst"_fix_msst.html "fix nphug"_fix_nphug.html "fix wall/piston"_fix_wall_piston.html examples/hugoniostat examples/msst :ul :line SNAP package :link(SNAP),h4 [Contents:] A pair style for the spectral neighbor analysis potential (SNAP). SNAP is methodology for deriving a highly accurate classical potential fit to a large archive of quantum mechanical (DFT) data. Also several computes which analyze attributes of the potential. [Author:] Aidan Thompson (Sandia). [Install or un-install:] make yes-snap make machine :pre make no-snap make machine :pre [Supporting info:] src/SNAP: filenames -> commands "pair snap"_pair_snap.html "compute sna/atom"_compute_sna_atom.html "compute snad/atom"_compute_sna_atom.html "compute snav/atom"_compute_sna_atom.html examples/snap :ul :line SRD package :link(SRD),h4 [Contents:] A pair of fixes which implement the Stochastic Rotation Dynamics (SRD) method for coarse-graining of a solvent, typically around large colloidal particles. To install/build: make yes-srd make machine :pre To un-install/re-build: make no-srd make machine :pre [Supporting info:] src/SRD: filenames -> commands "fix srd"_fix_srd.html "fix wall/srd"_fix_wall_srd.html examples/srd examples/ASPHERE http://lammps.sandia.gov/movies.html#tri http://lammps.sandia.gov/movies.html#line http://lammps.sandia.gov/movies.html#poly :ul :line VORONOI package :link(VORONOI),h4 [Contents:] A compute command which calculates the Voronoi tesselation of a collection of atoms by wrapping the "Voro++ library"_voro_home. This can be used to calculate the local volume or each atoms or its near neighbors. :link(voro_home,http://math.lbl.gov/voro++) To use this package you must have the Voro++ library available on your system. [Author:] Daniel Schwen (INL) while at LANL. The open-source Voro++ library was written by Chris Rycroft (Harvard U) while at UC Berkeley and LBNL. [Install or un-install:] Before building LAMMPS with this package, you must first download and build the Voro++ library. You can do this manually if you prefer; follow the instructions in lib/voronoi/README. You can also do it in one step from the lammps/src dir, using a command like these, which simply invoke the lib/voronoi/Install.py script with the specified args: make lib-voronoi # print help message make lib-voronoi args="-g -b -l" # download and build in default lib/voronoi/voro++-0.4.6 make lib-voronoi args="-h . voro++ -g -b -l" # download and build in lib/voronoi/voro++ make lib-voronoi args="-h ~ voro++ -g -b -l" # download and build in ~/voro++ :pre Note that the final -l switch is to create 2 symbolic (soft) links, "includelink" and "liblink", in lib/voronoi to point to the Voro++ src dir. When LAMMPS builds it will use these links. You should not need to edit the lib/voronoi/Makefile.lammps file. You can then install/un-install the package and build LAMMPS in the usual manner: make yes-voronoi make machine :pre make no-voronoi make machine :pre [Supporting info:] src/VORONOI: filenames -> commands src/VORONOI/README lib/voronoi/README "compute voronoi/atom"_compute_voronoi_atom.html examples/voronoi :ul :line :line USER-ATC package :link(USER-ATC),h4 [Contents:] ATC stands for atoms-to-continuum. This package implements a "fix atc"_fix_atc.html command to either couple molecular dynamics with continuum finite element equations or perform on-the-fly conversion of atomic information to continuum fields. [Authors:] Reese Jones, Jeremy Templeton, Jon Zimmerman (Sandia). [Install or un-install:] Before building LAMMPS with this package, you must first build the ATC library in lib/atc. You can do this manually if you prefer; follow the instructions in lib/atc/README. You can also do it in one step from the lammps/src dir, using a command like these, which simply invoke the lib/atc/Install.py script with the specified args: make lib-atc # print help message make lib-atc args="-m g++" # build with GNU g++ compiler make lib-atc args="-m icc" # build with Intel icc compiler :pre The build should produce two files: lib/atc/libatc.a and lib/atc/Makefile.lammps. The latter is copied from an existing Makefile.lammps.* and has settings needed to build LAMMPS with the ATC library. If necessary, you can edit/create a new lib/atc/Makefile.machine file for your system, which should define an EXTRAMAKE variable to specify a corresponding Makefile.lammps.machine file. Note that the Makefile.lammps file has settings for the BLAS and LAPACK linear algebra libraries. As explained in lib/atc/README these can either exist on your system, or you can use the files provided in lib/linalg. In the latter case you also need to build the library in lib/linalg with a command like these: make lib-linalg # print help message -make lib-atc args="-m gfortran" # build with GNU Fortran compiler +make lib-linalg args="-m gfortran" # build with GNU Fortran compiler You can then install/un-install the package and build LAMMPS in the usual manner: make yes-user-atc make machine :pre make no-user-atc make machine :pre [Supporting info:] src/USER-ATC: filenames -> commands src/USER-ATC/README "fix atc"_fix_atc.html examples/USER/atc http://lammps.sandia.gov/pictures.html#atc :ul :line USER-AWPMD package :link(USER-AWPMD),h4 [Contents:] AWPMD stands for Antisymmetrized Wave Packet Molecular Dynamics. This package implements an atom, pair, and fix style which allows electrons to be treated as explicit particles in a classical molecular dynamics model. [Author:] Ilya Valuev (JIHT, Russia). [Install or un-install:] Before building LAMMPS with this package, you must first build the AWPMD library in lib/awpmd. You can do this manually if you prefer; follow the instructions in lib/awpmd/README. You can also do it in one step from the lammps/src dir, using a command like these, which simply invoke the lib/awpmd/Install.py script with the specified args: make lib-awpmd # print help message make lib-awpmd args="-m g++" # build with GNU g++ compiler make lib-awpmd args="-m icc" # build with Intel icc compiler :pre The build should produce two files: lib/awpmd/libawpmd.a and lib/awpmd/Makefile.lammps. The latter is copied from an existing Makefile.lammps.* and has settings needed to build LAMMPS with the AWPMD library. If necessary, you can edit/create a new lib/awpmd/Makefile.machine file for your system, which should define an EXTRAMAKE variable to specify a corresponding Makefile.lammps.machine file. Note that the Makefile.lammps file has settings for the BLAS and LAPACK linear algebra libraries. As explained in lib/awpmd/README these can either exist on your system, or you can use the files provided in lib/linalg. In the latter case you also need to build the library in lib/linalg with a command like these: make lib-linalg # print help message make lib-atc args="-m gfortran" # build with GNU Fortran compiler You can then install/un-install the package and build LAMMPS in the usual manner: make yes-user-awpmd make machine :pre make no-user-awpmd make machine :pre [Supporting info:] src/USER-AWPMD: filenames -> commands src/USER-AWPMD/README "pair awpmd/cut"_pair_awpmd.html examples/USER/awpmd :ul :line USER-CGDNA package :link(USER-CGDNA),h4 [Contents:] Several pair styles, a bond style, and integration fixes for coarse-grained models of single- and double-stranded DNA based on the oxDNA model of Doye, Louis and Ouldridge at the University of Oxford. This includes Langevin-type rigid-body integrators with improved stability. [Author:] Oliver Henrich (University of Strathclyde, Glasgow). [Install or un-install:] make yes-user-cgdna make machine :pre make no-user-cgdna make machine :pre [Supporting info:] src/USER-CGDNA: filenames -> commands /src/USER-CGDNA/README "pair_style oxdna/*"_pair_oxdna.html "pair_style oxdna2/*"_pair_oxdna2.html "bond_style oxdna/*"_bond_oxdna.html "bond_style oxdna2/*"_bond_oxdna.html "fix nve/dotc/langevin"_fix_nve_dotc_langevin.html :ul :line USER-CGSDK package :link(USER-CGSDK),h4 [Contents:] Several pair styles and an angle style which implement the coarse-grained SDK model of Shinoda, DeVane, and Klein which enables simulation of ionic liquids, electrolytes, lipids and charged amino acids. [Author:] Axel Kohlmeyer (Temple U). [Install or un-install:] make yes-user-cgsdk make machine :pre make no-user-cgsdk make machine :pre [Supporting info:] src/USER-CGSDK: filenames -> commands src/USER-CGSDK/README "pair_style lj/sdk/*"_pair_sdk.html "angle_style sdk"_angle_sdk.html examples/USER/cgsdk http://lammps.sandia.gov/pictures.html#cg :ul :line USER-COLVARS package :link(USER-COLVARS),h4 [Contents:] COLVARS stands for collective variables, which can be used to implement various enhanced sampling methods, including Adaptive Biasing Force, Metadynamics, Steered MD, Umbrella Sampling and Restraints. A "fix colvars"_fix_colvars.html command is implemented which wraps a COLVARS library, which implements these methods. simulations. [Authors:] Axel Kohlmeyer (Temple U). The COLVARS library was written by Giacomo Fiorin (ICMS, Temple University, Philadelphia, PA, USA) and Jerome Henin (LISM, CNRS, Marseille, France). [Install or un-install:] Before building LAMMPS with this package, you must first build the COLVARS library in lib/colvars. You can do this manually if you prefer; follow the instructions in lib/colvars/README. You can also do it in one step from the lammps/src dir, using a command like these, which simply invoke the lib/colvars/Install.py script with the specified args: make lib-colvars # print help message make lib-colvars args="-m g++" # build with GNU g++ compiler :pre The build should produce two files: lib/colvars/libcolvars.a and lib/colvars/Makefile.lammps. The latter is copied from an existing Makefile.lammps.* and has settings needed to build LAMMPS with the COLVARS library (though typically the settings are just blank). If necessary, you can edit/create a new lib/colvars/Makefile.machine file for your system, which should define an EXTRAMAKE variable to specify a corresponding Makefile.lammps.machine file. You can then install/un-install the package and build LAMMPS in the usual manner: make yes-user-colvars make machine :pre make no-user-colvars make machine :pre [Supporting info:] src/USER-COLVARS: filenames -> commands "doc/PDF/colvars-refman-lammps.pdf"_PDF/colvars-refman-lammps.pdf src/USER-COLVARS/README lib/colvars/README "fix colvars"_fix_colvars.html examples/USER/colvars :ul :line USER-DIFFRACTION package :link(USER-DIFFRACTION),h4 [Contents:] Two computes and a fix for calculating x-ray and electron diffraction intensities based on kinematic diffraction theory. [Author:] Shawn Coleman while at the U Arkansas. [Install or un-install:] make yes-user-diffraction make machine :pre make no-user-diffraction make machine :pre [Supporting info:] src/USER-DIFFRACTION: filenames -> commands "compute saed"_compute_saed.html "compute xrd"_compute_xrd.html "fix saed/vtk"_fix_saed_vtk.html examples/USER/diffraction :ul :line USER-DPD package :link(USER-DPD),h4 [Contents:] DPD stands for dissipative particle dynamics. This package implements coarse-grained DPD-based models for energetic, reactive molecular crystalline materials. It includes many pair styles specific to these systems, including for reactive DPD, where each particle has internal state for multiple species and a coupled set of chemical reaction ODEs are integrated each timestep. Highly accurate time intergrators for isothermal, isoenergetic, isobaric and isenthalpic conditions are included. These enable long timesteps via the Shardlow splitting algorithm. [Authors:] Jim Larentzos (ARL), Tim Mattox (Engility Corp), and and John Brennan (ARL). [Install or un-install:] make yes-user-dpd make machine :pre make no-user-dpd make machine :pre [Supporting info:] src/USER-DPD: filenames -> commands /src/USER-DPD/README "compute dpd"_compute_dpd.html "compute dpd/atom"_compute_dpd_atom.html "fix eos/cv"_fix_eos_table.html "fix eos/table"_fix_eos_table.html "fix eos/table/rx"_fix_eos_table_rx.html "fix shardlow"_fix_shardlow.html "fix rx"_fix_rx.html "pair table/rx"_pair_table_rx.html "pair dpd/fdt"_pair_dpd_fdt.html "pair dpd/fdt/energy"_pair_dpd_fdt.html "pair exp6/rx"_pair_exp6_rx.html "pair multi/lucy"_pair_multi_lucy.html "pair multi/lucy/rx"_pair_multi_lucy_rx.html examples/USER/dpd :ul :line USER-DRUDE package :link(USER-DRUDE),h4 [Contents:] Fixes, pair styles, and a compute to simulate thermalized Drude oscillators as a model of polarization. See "Section 6.27"_Section_howto.html#howto_27 for an overview of how to use the package. There are auxiliary tools for using this package in tools/drude. [Authors:] Alain Dequidt (U Blaise Pascal Clermont-Ferrand), Julien Devemy (CNRS), and Agilio Padua (U Blaise Pascal). [Install or un-install:] make yes-user-drude make machine :pre make no-user-drude make machine :pre [Supporting info:] src/USER-DRUDE: filenames -> commands "Section 6.27"_Section_howto.html#howto_27 "Section 6.25"_Section_howto.html#howto_25 src/USER-DRUDE/README "fix drude"_fix_drude.html "fix drude/transform/*"_fix_drude_transform.html "compute temp/drude"_compute_temp_drude.html "pair thole"_pair_thole.html "pair lj/cut/thole/long"_pair_thole.html examples/USER/drude tools/drude :ul :line USER-EFF package :link(USER-EFF),h4 [Contents:] EFF stands for electron force field which allows a classical MD code to model electrons as particles of variable radius. This package contains atom, pair, fix and compute styles which implement the eFF as described in A. Jaramillo-Botero, J. Su, Q. An, and W.A. Goddard III, JCC, 2010. The eFF potential was first introduced by Su and Goddard, in 2007. There are auxiliary tools for using this package in tools/eff; see its README file. [Author:] Andres Jaramillo-Botero (CalTech). [Install or un-install:] make yes-user-eff make machine :pre make no-user-eff make machine :pre [Supporting info:] src/USER-EFF: filenames -> commands src/USER-EFF/README "atom_style electron"_atom_style.html "fix nve/eff"_fix_nve_eff.html "fix nvt/eff"_fix_nh_eff.html "fix npt/eff"_fix_nh_eff.html "fix langevin/eff"_fix_langevin_eff.html "compute temp/eff"_compute_temp_eff.html "pair eff/cut"_pair_eff.html "pair eff/inline"_pair_eff.html examples/USER/eff tools/eff/README tools/eff http://lammps.sandia.gov/movies.html#eff :ul :line USER-FEP package :link(USER-FEP),h4 [Contents:] FEP stands for free energy perturbation. This package provides methods for performing FEP simulations by using a "fix adapt/fep"_fix_adapt_fep.html command with soft-core pair potentials, which have a "soft" in their style name. There are auxiliary tools for using this package in tools/fep; see its README file. [Author:] Agilio Padua (Universite Blaise Pascal Clermont-Ferrand) [Install or un-install:] make yes-user-fep make machine :pre make no-user-fep make machine :pre [Supporting info:] src/USER-FEP: filenames -> commands src/USER-FEP/README "fix adapt/fep"_fix_adapt_fep.html "compute fep"_compute_fep.html "pair_style */soft"_pair_lj_soft.html examples/USER/fep tools/fep/README tools/fep :ul :line USER-H5MD package :link(USER-H5MD),h4 [Contents:] H5MD stands for HDF5 for MD. "HDF5"_HDF5 is a portable, binary, self-describing file format, used by many scientific simulations. H5MD is a format for molecular simulations, built on top of HDF5. This package implements a "dump h5md"_dump_h5md.html command to output LAMMPS snapshots in this format. :link(HDF5,http://www.hdfgroup.org/HDF5) To use this package you must have the HDF5 library available on your system. [Author:] Pierre de Buyl (KU Leuven) created both the package and the H5MD format. [Install or un-install:] Note that to follow these steps to compile and link to the CH5MD library, you need the standard HDF5 software package installed on your system, which should include the h5cc compiler and the HDF5 library. Before building LAMMPS with this package, you must first build the CH5MD library in lib/h5md. You can do this manually if you prefer; follow the instructions in lib/h5md/README. You can also do it in one step from the lammps/src dir, using a command like these, which simply invoke the lib/h5md/Install.py script with the specified args: make lib-h5md # print help message make lib-hm5d args="-m h5cc" # build with h5cc compiler :pre The build should produce two files: lib/h5md/libch5md.a and lib/h5md/Makefile.lammps. The latter is copied from an existing Makefile.lammps.* and has settings needed to build LAMMPS with the system HDF5 library. If necessary, you can edit/create a new lib/h5md/Makefile.machine file for your system, which should define an EXTRAMAKE variable to specify a corresponding Makefile.lammps.machine file. You can then install/un-install the package and build LAMMPS in the usual manner: make yes-user-h5md make machine :pre make no-user-h5md make machine :pre [Supporting info:] src/USER-H5MD: filenames -> commands src/USER-H5MD/README lib/h5md/README "dump h5md"_dump_h5md.html :ul :line USER-INTEL package :link(USER-INTEL),h4 [Contents:] Dozens of pair, fix, bond, angle, dihedral, improper, and kspace styles which are optimized for Intel CPUs and KNLs (Knights Landing). All of them have an "intel" in their style name. "Section 5.3.2"_accelerate_intel.html gives details of what hardware and compilers are required on your system, and how to build and use this package. Its styles can be invoked at run time via the "-sf intel" or "-suffix intel" "command-line switches"_Section_start.html#start_6. Also see the "KOKKOS"_#KOKKOS, "OPT"_#OPT, and "USER-OMP"_#USER-OMP packages, which have styles optimized for CPUs and KNLs. You need to have an Intel compiler, version 14 or higher to take full advantage of this package. [Author:] Mike Brown (Intel). [Install or un-install:] For the USER-INTEL package, you have 2 choices when building. You can build with either CPU or KNL support. Each choice requires additional settings in your Makefile.machine for CCFLAGS and LINKFLAGS and optimized malloc libraries. See the src/MAKE/OPTIONS/Makefile.intel_cpu and src/MAKE/OPTIONS/Makefile.knl files for examples. For CPUs: OPTFLAGS = -xHost -O2 -fp-model fast=2 -no-prec-div -qoverride-limits CCFLAGS = -g -qopenmp -DLAMMPS_MEMALIGN=64 -no-offload \ -fno-alias -ansi-alias -restrict $(OPTFLAGS) LINKFLAGS = -g -qopenmp $(OPTFLAGS) LIB = -ltbbmalloc -ltbbmalloc_proxy For KNLs: OPTFLAGS = -xMIC-AVX512 -O2 -fp-model fast=2 -no-prec-div -qoverride-limits CCFLAGS = -g -qopenmp -DLAMMPS_MEMALIGN=64 -no-offload \ -fno-alias -ansi-alias -restrict $(OPTFLAGS) LINKFLAGS = -g -qopenmp $(OPTFLAGS) LIB = -ltbbmalloc Once you have an appropriate Makefile.machine, you can install/un-install the package and build LAMMPS in the usual manner. Note that you cannot build one executable to run on multiple hardware targets (Intel CPUs or KNL). You need to build LAMMPS once for each hardware target, to produce a separate executable. You should also typically install the USER-OMP package, as it can be used in tandem with the USER-INTEL package to good effect, as explained in "Section 5.3.2"_accelerate_intel.html. make yes-user-intel yes-user-omp make machine :pre make no-user-intel no-user-omp make machine :pre [Supporting info:] src/USER-INTEL: filenames -> commands src/USER-INTEL/README "Section 5.3"_Section_accelerate.html#acc_3 "Section 5.3.2"_accelerate_gpu.html "Section 2.6 -sf intel"_Section_start.html#start_6 "Section 2.6 -pk intel"_Section_start.html#start_6 "package intel"_package.html Styles sections of "Section 3.5"_Section_commands.html#cmd_5 for styles followed by (i) src/USER-INTEL/TEST "Benchmarks page"_http://lammps.sandia.gov/bench.html of web site :ul :line USER-LB package :link(USER-LB),h4 [Contents:] Fixes which implement a background Lattice-Boltzmann (LB) fluid, which can be used to model MD particles influenced by hydrodynamic forces. [Authors:] Frances Mackay and Colin Denniston (University of Western Ontario). [Install or un-install:] make yes-user-lb make machine :pre make no-user-lb make machine :pre [Supporting info:] src/USER-LB: filenames -> commands src/USER-LB/README "fix lb/fluid"_fix_lb_fluid.html "fix lb/momentum"_fix_lb_momentum.html "fix lb/viscous"_fix_lb_viscous.html examples/USER/lb :ul :line USER-MGPT package :link(USER-MGPT),h4 [Contents:] A pair style which provides a fast implementation of the quantum-based MGPT multi-ion potentials. The MGPT or model GPT method derives from first-principles DFT-based generalized pseudopotential theory (GPT) through a series of systematic approximations valid for mid-period transition metals with nearly half-filled d bands. The MGPT method was originally developed by John Moriarty at LLNL. The pair style in this package calculates forces and energies using an optimized matrix-MGPT algorithm due to Tomas Oppelstrup at LLNL. [Authors:] Tomas Oppelstrup and John Moriarty (LLNL). [Install or un-install:] make yes-user-mgpt make machine :pre make no-user-mgpt make machine :pre [Supporting info:] src/USER-MGPT: filenames -> commands src/USER-MGPT/README "pair_style mgpt"_pair_mgpt.html examples/USER/mgpt :ul :line USER-MISC package :link(USER-MISC),h4 [Contents:] A potpourri of (mostly) unrelated features contributed to LAMMPS by users. Each feature is a single fix, compute, pair, bond, angle, dihedral, improper, or command style. [Authors:] The author for each style in the package is listed in the src/USER-MISC/README file. [Install or un-install:] make yes-user-misc make machine :pre make no-user-misc make machine :pre [Supporting info:] src/USER-MISC: filenames -> commands src/USER-MISC/README one doc page per individual command listed in src/USER-MISC/README examples/USER/misc :ul :line USER-MANIFOLD package :link(USER-MANIFOLD),h4 [Contents:] Several fixes and a "manifold" class which enable simulations of particles constrained to a manifold (a 2D surface within the 3D simulation box). This is done by applying the RATTLE constraint algorithm to formulate single-particle constraint functions g(xi,yi,zi) = 0 and their derivative (i.e. the normal of the manifold) n = grad(g). [Author:] Stefan Paquay (until 2017: Eindhoven University of Technology (TU/e), The Netherlands; since 2017: Brandeis University, Waltham, MA, USA) [Install or un-install:] make yes-user-manifold make machine :pre make no-user-manifold make machine :pre [Supporting info:] src/USER-MANIFOLD: filenames -> commands src/USER-MANIFOLD/README "doc/manifolds"_manifolds.html "fix manifoldforce"_fix_manifoldforce.html "fix nve/manifold/rattle"_fix_nve_manifold_rattle.html "fix nvt/manifold/rattle"_fix_nvt_manifold_rattle.html examples/USER/manifold http://lammps.sandia.gov/movies.html#manifold :ul :line USER-MEAMC package :link(USER-MEAMC),h4 [Contents:] A pair style for the modified embedded atom (MEAM) potential translated from the Fortran version in the "MEAM"_MEAM package to plain C++. In contrast to the MEAM package, no library needs to be compiled and the pair style can be instantiated multiple times. [Author:] Sebastian Huetter, (Otto-von-Guericke University Magdeburg) based on the Fortran version of Greg Wagner (Northwestern U) while at Sandia. [Install or un-install:] make yes-user-meamc make machine :pre make no-user-meamc make machine :pre [Supporting info:] src/USER-MEAMC: filenames -> commands src/USER-MEAMC/README "pair meam/c"_pair_meam.html examples/meam :ul :line USER-MOLFILE package :link(USER-MOLFILE),h4 [Contents:] A "dump molfile"_dump_molfile.html command which uses molfile plugins that are bundled with the "VMD"_vmd_home molecular visualization and analysis program, to enable LAMMPS to dump snapshots in formats compatible with various molecular simulation tools. :link(vmd_home,http://www.ks.uiuc.edu/Research/vmd) To use this package you must have the desired VMD plugins available on your system. Note that this package only provides the interface code, not the plugins themselves, which will be accessed when requesting a specific plugin via the "dump molfile"_dump_molfile.html command. Plugins can be obtained from a VMD installation which has to match the platform that you are using to compile LAMMPS for. By adding plugins to VMD, support for new file formats can be added to LAMMPS (or VMD or other programs that use them) without having to recompile the application itself. More information about the VMD molfile plugins can be found at "http://www.ks.uiuc.edu/Research/vmd/plugins/molfile"_http://www.ks.uiuc.edu/Research/vmd/plugins/molfile. [Author:] Axel Kohlmeyer (Temple U). [Install or un-install:] Note that the lib/molfile/Makefile.lammps file has a setting for a dynamic loading library libdl.a that should is typically present on all systems, which is required for LAMMPS to link with this package. If the setting is not valid for your system, you will need to edit the Makefile.lammps file. See lib/molfile/README and lib/molfile/Makefile.lammps for details. make yes-user-molfile make machine :pre make no-user-molfile make machine :pre [Supporting info:] src/USER-MOLFILE: filenames -> commands src/USER-MOLFILE/README lib/molfile/README "dump molfile"_dump_molfile.html :ul :line USER-NETCDF package :link(USER-NETCDF),h4 [Contents:] Dump styles for writing NetCDF formatted dump files. NetCDF is a portable, binary, self-describing file format developed on top of HDF5. The file contents follow the AMBER NetCDF trajectory conventions (http://ambermd.org/netcdf/nctraj.xhtml), but include extensions. To use this package you must have the NetCDF library available on your system. Note that NetCDF files can be directly visualized with the following tools: "Ovito"_ovito (Ovito supports the AMBER convention and the extensions mentioned above) "VMD"_vmd_home "AtomEye"_atomeye (the libAtoms version of AtomEye contains a NetCDF reader not present in the standard distribution) :ul :link(ovito,http://www.ovito.org) :link(atomeye,http://www.libatoms.org) [Author:] Lars Pastewka (Karlsruhe Institute of Technology). [Install or un-install:] Note that to follow these steps, you need the standard NetCDF software package installed on your system. The lib/netcdf/Makefile.lammps file has settings for NetCDF include and library files that LAMMPS needs to compile and linkk with this package. If the settings are not valid for your system, you will need to edit the Makefile.lammps file. See lib/netcdf/README for details. make yes-user-netcdf make machine :pre make no-user-netcdf make machine :pre [Supporting info:] src/USER-NETCDF: filenames -> commands src/USER-NETCDF/README lib/netcdf/README "dump netcdf"_dump_netcdf.html :ul :line USER-OMP package :link(USER-OMP),h4 [Contents:] Hundreds of pair, fix, compute, bond, angle, dihedral, improper, and kspace styles which are altered to enable threading on many-core CPUs via OpenMP directives. All of them have an "omp" in their style name. "Section 5.3.4"_accelerate_omp.html gives details of what hardware and compilers are required on your system, and how to build and use this package. Its styles can be invoked at run time via the "-sf omp" or "-suffix omp" "command-line switches"_Section_start.html#start_6. Also see the "KOKKOS"_#KOKKOS, "OPT"_#OPT, and "USER-INTEL"_#USER-INTEL packages, which have styles optimized for CPUs. [Author:] Axel Kohlmeyer (Temple U). NOTE: The compile flags "-restrict" and "-fopenmp" must be used to build LAMMPS with the USER-OMP package, as well as the link flag "-fopenmp". They should be added to the CCFLAGS and LINKFLAGS lines of your Makefile.machine. See src/MAKE/OPTIONS/Makefile.omp for an example. Once you have an appropriate Makefile.machine, you can install/un-install the package and build LAMMPS in the usual manner: [Install or un-install:] make yes-user-omp make machine :pre make no-user-omp make machine :pre CCFLAGS: add -fopenmp and -restrict LINKFLAGS: add -fopenmp :ul [Supporting info:] src/USER-OMP: filenames -> commands src/USER-OMP/README "Section 5.3"_Section_accelerate.html#acc_3 "Section 5.3.4"_accelerate_omp.html "Section 2.6 -sf omp"_Section_start.html#start_6 "Section 2.6 -pk omp"_Section_start.html#start_6 "package omp"_package.html Styles sections of "Section 3.5"_Section_commands.html#cmd_5 for styles followed by (o) "Benchmarks page"_http://lammps.sandia.gov/bench.html of web site :ul :line USER-PHONON package :link(USER-PHONON),h4 [Contents:] A "fix phonon"_fix_phonon.html command that calculates dynamical matrices, which can then be used to compute phonon dispersion relations, directly from molecular dynamics simulations. [Author:] Ling-Ti Kong (Shanghai Jiao Tong University). [Install or un-install:] make yes-user-phonon make machine :pre make no-user-phonon make machine :pre [Supporting info:] src/USER-PHONON: filenames -> commands src/USER-PHONON/README "fix phonon"_fix_phonon.html examples/USER/phonon :ul :line USER-QMMM package :link(USER-QMMM),h4 [Contents:] A "fix qmmm"_fix_qmmm.html command which allows LAMMPS to be used in a QM/MM simulation, currently only in combination with the "Quantum ESPRESSO"_espresso package. :link(espresso,http://www.quantum-espresso.org) To use this package you must have Quantum ESPRESSO available on your system. The current implementation only supports an ONIOM style mechanical coupling to the Quantum ESPRESSO plane wave DFT package. Electrostatic coupling is in preparation and the interface has been written in a manner that coupling to other QM codes should be possible without changes to LAMMPS itself. [Author:] Axel Kohlmeyer (Temple U). [Install or un-install:] Before building LAMMPS with this package, you must first build the QMMM library in lib/qmmm. You can do this manually if you prefer; follow the first two steps explained in lib/colvars/README. You can also do it in one step from the lammps/src dir, using a command like these, which simply invoke the lib/colvars/Install.py script with the specified args: make lib-qmmm # print help message make lib-qmmm args="-m gfortran" # build with GNU Fortran compiler :pre The build should produce two files: lib/qmmm/libqmmm.a and lib/qmmm/Makefile.lammps. The latter is copied from an existing Makefile.lammps.* and has settings needed to build LAMMPS with the QMMM library (though typically the settings are just blank). If necessary, you can edit/create a new lib/qmmm/Makefile.machine file for your system, which should define an EXTRAMAKE variable to specify a corresponding Makefile.lammps.machine file. You can then install/un-install the package and build LAMMPS in the usual manner: make yes-user-qmmm make machine :pre make no-user-qmmm make machine :pre NOTE: The LAMMPS executable these steps produce is not yet functional for a QM/MM simulation. You must also build Quantum ESPRESSO and create a new executable which links LAMMPS and Quanutm ESPRESSO together. These are steps 3 and 4 described in the lib/qmmm/README file. [Supporting info:] src/USER-QMMM: filenames -> commands src/USER-QMMM/README lib/qmmm/README "fix phonon"_fix_phonon.html lib/qmmm/example-ec/README lib/qmmm/example-mc/README :ul :line USER-QTB package :link(USER-QTB),h4 [Contents:] Two fixes which provide a self-consistent quantum treatment of vibrational modes in a classical molecular dynamics simulation. By coupling the MD simulation to a colored thermostat, it introduces zero point energy into the system, altering the energy power spectrum and the heat capacity to account for their quantum nature. This is useful when modeling systems at temperatures lower than their classical limits or when temperatures ramp across the classical limits in a simulation. [Author:] Yuan Shen (Stanford U). [Install or un-install:] make yes-user-qtb make machine :pre make no-user-qtb make machine :pre [Supporting info:] src/USER-QTB: filenames -> commands src/USER-QTB/README "fix qtb"_fix_qtb.html "fix qbmsst"_fix_qbmsst.html examples/USER/qtb :ul :line USER-QUIP package :link(USER-QUIP),h4 [Contents:] A "pair_style quip"_pair_quip.html command which wraps the "QUIP libAtoms library"_quip, which includes a variety of interatomic potentials, including Gaussian Approximation Potential (GAP) models developed by the Cambridge University group. :link(quip,https://github.com/libAtoms/QUIP) To use this package you must have the QUIP libAatoms library available on your system. [Author:] Albert Bartok (Cambridge University) [Install or un-install:] Note that to follow these steps to compile and link to the QUIP library, you must first download and build QUIP on your systems. It can be obtained from GitHub. See step 1 and step 1.1 in the lib/quip/README file for details on how to do this. Note that it requires setting two environment variables, QUIP_ROOT and QUIP_ARCH, which will be accessed by the lib/quip/Makefile.lammps file which is used when you compile and link LAMMPS with this package. You should only need to edit this file if the LAMMPS build can not use its settings to successfully build on your system. You can then install/un-install the package and build LAMMPS in the usual manner: make yes-user-quip make machine :pre make no-user-quip make machine :pre [Supporting info:] src/USER-QUIP: filenames -> commands src/USER-QUIP/README "pair_style quip"_pair_quip.html examples/USER/quip :ul :line USER-REAXC package :link(USER-REAXC),h4 [Contents:] A pair style which implements the ReaxFF potential in C/C++ (in contrast to the "REAX package"_#REAX and its Fortran library). ReaxFF is universal reactive force field. See the src/USER-REAXC/README file for more info on differences between the two packages. Also two fixes for monitoring molecules as bonds are created and destroyed. [Author:] Hasan Metin Aktulga (MSU) while at Purdue University. [Install or un-install:] make yes-user-reaxc make machine :pre make no-user-reaxc make machine :pre [Supporting info:] src/USER-REAXC: filenames -> commands src/USER-REAXC/README "pair_style reax/c"_pair_reaxc.html "fix reax/c/bonds"_fix_reax_bonds.html "fix reax/c/species"_fix_reaxc_species.html examples/reax :ul :line USER-SMD package :link(USER-SMD),h4 [Contents:] An atom style, fixes, computes, and several pair styles which implements smoothed Mach dynamics (SMD) for solids, which is a model related to smoothed particle hydrodynamics (SPH) for liquids (see the "USER-SPH package"_#USER-SPH). This package solves solids mechanics problems via a state of the art stabilized meshless method with hourglass control. It can specify hydrostatic interactions independently from material strength models, i.e. pressure and deviatoric stresses are separated. It provides many material models (Johnson-Cook, plasticity with hardening, Mie-Grueneisen, Polynomial EOS) and allows new material models to be added. It implements rigid boundary conditions (walls) which can be specified as surface geometries from *.STL files. [Author:] Georg Ganzenmuller (Fraunhofer-Institute for High-Speed Dynamics, Ernst Mach Institute, Germany). [Install or un-install:] Before building LAMMPS with this package, you must first download the Eigen library. Eigen is a template library, so you do not need to build it, just download it. You can do this manually if you prefer; follow the instructions in lib/smd/README. You can also do it in one step from the lammps/src dir, using a command like these, which simply invoke the lib/smd/Install.py script with the specified args: make lib-smd # print help message -make lib-smd args="-g -l" # download in default lib/smd/eigen-eigen-* -make lib-smd args="-h . eigen -g -l" # download in lib/smd/eigen +make lib-smd args="-g -l" # download and build in default lib/smd/eigen-eigen-* +make lib-smd args="-h . eigen -g -l" # download and build in lib/smd/eigen make lib-smd args="-h ~ eigen -g -l" # download and build in ~/eigen :pre Note that the final -l switch is to create a symbolic (soft) link named "includelink" in lib/smd to point to the Eigen dir. When LAMMPS builds it will use this link. You should not need to edit the lib/smd/Makefile.lammps file. You can then install/un-install the package and build LAMMPS in the usual manner: make yes-user-smd make machine :pre make no-user-smd make machine :pre [Supporting info:] src/USER-SMD: filenames -> commands src/USER-SMD/README doc/PDF/SMD_LAMMPS_userguide.pdf examples/USER/smd http://lammps.sandia.gov/movies.html#smd :ul :line USER-SMTBQ package :link(USER-SMTBQ),h4 [Contents:] A pair style which implements a Second Moment Tight Binding model with QEq charge equilibration (SMTBQ) potential for the description of ionocovalent bonds in oxides. [Authors:] Nicolas Salles, Emile Maras, Olivier Politano, and Robert Tetot (LAAS-CNRS, France). [Install or un-install:] make yes-user-smtbq make machine :pre make no-user-smtbq make machine :pre [Supporting info:] src/USER-SMTBQ: filenames -> commands src/USER-SMTBQ/README "pair_style smtbq"_pair_smtbq.html examples/USER/smtbq :ul :line USER-SPH package :link(USER-SPH),h4 [Contents:] An atom style, fixes, computes, and several pair styles which implements smoothed particle hydrodynamics (SPH) for liquids. See the related "USER-SMD package"_#USER-SMD package for smooth Mach dynamics (SMD) for solids. This package contains ideal gas, Lennard-Jones equation of states, Tait, and full support for complete (i.e. internal-energy dependent) equations of state. It allows for plain or Monaghans XSPH integration of the equations of motion. It has options for density continuity or density summation to propagate the density field. It has "set"_set.html command options to set the internal energy and density of particles from the input script and allows the same quantities to be output with thermodynamic output or to dump files via the "compute property/atom"_compute_property_atom.html command. [Author:] Georg Ganzenmuller (Fraunhofer-Institute for High-Speed Dynamics, Ernst Mach Institute, Germany). [Install or un-install:] make yes-user-sph make machine :pre make no-user-sph make machine :pre [Supporting info:] src/USER-SPH: filenames -> commands src/USER-SPH/README doc/PDF/SPH_LAMMPS_userguide.pdf examples/USER/sph http://lammps.sandia.gov/movies.html#sph :ul :line USER-TALLY package :link(USER-TALLY),h4 [Contents:] Several compute styles that can be called when pairwise interactions are calculated to tally information (forces, heat flux, energy, stress, etc) about individual interactions. [Author:] Axel Kohlmeyer (Temple U). [Install or un-install:] make yes-user-tally make machine :pre make no-user-tally make machine :pre [Supporting info:] src/USER-TALLY: filenames -> commands src/USER-TALLY/README "compute */tally"_compute_tally.html examples/USER/tally :ul :line USER-VTK package :link(USER-VTK),h4 [Contents:] A "dump vtk"_dump_vtk.html command which outputs snapshot info in the "VTK format"_vtk, enabling visualization by "Paraview"_paraview or other visuzlization packages. :link(vtk,http://www.vtk.org) :link(paraview,http://www.paraview.org) To use this package you must have VTK library available on your system. [Authors:] Richard Berger (JKU) and Daniel Queteschiner (DCS Computing). [Install or un-install:] The lib/vtk/Makefile.lammps file has settings for accessing VTK files and its library, which are required for LAMMPS to build and link with this package. If the settings are not valid for your system, check if one of the other lib/vtk/Makefile.lammps.* files is compatible and copy it to Makefile.lammps. If none of the provided files work, you will need to edit the Makefile.lammps file. You can then install/un-install the package and build LAMMPS in the usual manner: make yes-user-vtk make machine :pre make no-user-vtk make machine :pre [Supporting info:] src/USER-VTK: filenames -> commands src/USER-VTK/README lib/vtk/README "dump vtk"_dump_vtk.html :ul diff --git a/doc/src/accelerate_gpu.txt b/doc/src/accelerate_gpu.txt index 68e9fa477..2723b6e97 100644 --- a/doc/src/accelerate_gpu.txt +++ b/doc/src/accelerate_gpu.txt @@ -1,254 +1,249 @@ "Previous Section"_Section_packages.html - "LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c :link(lws,http://lammps.sandia.gov) :link(ld,Manual.html) :link(lc,Section_commands.html#comm) :line "Return to Section accelerate overview"_Section_accelerate.html 5.3.1 GPU package :h5 The GPU package was developed by Mike Brown at ORNL and his collaborators, particularly Trung Nguyen (ORNL). It provides GPU versions of many pair styles, including the 3-body Stillinger-Weber pair style, and for "kspace_style pppm"_kspace_style.html for long-range Coulombics. It has the following general features: It is designed to exploit common GPU hardware configurations where one or more GPUs are coupled to many cores of one or more multi-core CPUs, e.g. within a node of a parallel machine. :ulb,l Atom-based data (e.g. coordinates, forces) moves back-and-forth between the CPU(s) and GPU every timestep. :l Neighbor lists can be built on the CPU or on the GPU :l The charge assignment and force interpolation portions of PPPM can be run on the GPU. The FFT portion, which requires MPI communication between processors, runs on the CPU. :l Asynchronous force computations can be performed simultaneously on the CPU(s) and GPU. :l It allows for GPU computations to be performed in single or double precision, or in mixed-mode precision, where pairwise forces are computed in single precision, but accumulated into double-precision force vectors. :l LAMMPS-specific code is in the GPU package. It makes calls to a generic GPU library in the lib/gpu directory. This library provides NVIDIA support as well as more general OpenCL support, so that the same functionality can eventually be supported on a variety of GPU hardware. :l :ule Here is a quick overview of how to enable and use the GPU package: build the library in lib/gpu for your GPU hardware with the desired precision settings install the GPU package and build LAMMPS as usual use the mpirun command to set the number of MPI tasks/node which determines the number of MPI tasks/GPU specify the # of GPUs per node use GPU styles in your input script :ul The latter two steps can be done using the "-pk gpu" and "-sf gpu" "command-line switches"_Section_start.html#start_6 respectively. Or the effect of the "-pk" or "-sf" switches can be duplicated by adding the "package gpu"_package.html or "suffix gpu"_suffix.html commands respectively to your input script. [Required hardware/software:] To use this package, you currently need to have an NVIDIA GPU and install the NVIDIA Cuda software on your system: Check if you have an NVIDIA GPU: cat /proc/driver/nvidia/gpus/0/information Go to http://www.nvidia.com/object/cuda_get.html Install a driver and toolkit appropriate for your system (SDK is not necessary) Run lammps/lib/gpu/nvc_get_devices (after building the GPU library, see below) to list supported devices and properties :ul [Building LAMMPS with the GPU package:] This requires two steps (a,b): build the GPU library, then build LAMMPS with the GPU package. -You can do both these steps in one line, using the src/Make.py script, -described in "Section 4"_Section_packages.html of the manual. -Type "Make.py -h" for help. If run from the src directory, this -command will create src/lmp_gpu using src/MAKE/Makefile.mpi as the -starting Makefile.machine: - -Make.py -p gpu -gpu mode=single arch=31 -o gpu -a lib-gpu file mpi :pre +You can do both these steps in one line as described in +"Section 4"_Section_packages.html of the manual. Or you can follow these two (a,b) steps: (a) Build the GPU library The GPU library is in lammps/lib/gpu. Select a Makefile.machine (in lib/gpu) appropriate for your system. You should pay special attention to 3 settings in this makefile. CUDA_HOME = needs to be where NVIDIA Cuda software is installed on your system CUDA_ARCH = needs to be appropriate to your GPUs CUDA_PREC = precision (double, mixed, single) you desire :ul See lib/gpu/Makefile.linux.double for examples of the ARCH settings for different GPU choices, e.g. Fermi vs Kepler. It also lists the possible precision settings: CUDA_PREC = -D_SINGLE_SINGLE # single precision for all calculations CUDA_PREC = -D_DOUBLE_DOUBLE # double precision for all calculations CUDA_PREC = -D_SINGLE_DOUBLE # accumulation of forces, etc, in double :pre The last setting is the mixed mode referred to above. Note that your GPU must support double precision to use either the 2nd or 3rd of these settings. To build the library, type: make -f Makefile.machine :pre If successful, it will produce the files libgpu.a and Makefile.lammps. The latter file has 3 settings that need to be appropriate for the paths and settings for the CUDA system software on your machine. Makefile.lammps is a copy of the file specified by the EXTRAMAKE setting in Makefile.machine. You can change EXTRAMAKE or create your own Makefile.lammps.machine if needed. Note that to change the precision of the GPU library, you need to re-build the entire library. Do a "clean" first, e.g. "make -f Makefile.linux clean", followed by the make command above. (b) Build LAMMPS with the GPU package cd lammps/src make yes-gpu make machine :pre No additional compile/link flags are needed in Makefile.machine. Note that if you change the GPU library precision (discussed above) and rebuild the GPU library, then you also need to re-install the GPU package and re-build LAMMPS, so that all affected files are re-compiled and linked to the new GPU library. [Run with the GPU package from the command line:] The mpirun or mpiexec command sets the total number of MPI tasks used by LAMMPS (one or multiple per compute node) and the number of MPI tasks used per node. E.g. the mpirun command in MPICH does this via its -np and -ppn switches. Ditto for OpenMPI via -np and -npernode. When using the GPU package, you cannot assign more than one GPU to a single MPI task. However multiple MPI tasks can share the same GPU, and in many cases it will be more efficient to run this way. Likewise it may be more efficient to use less MPI tasks/node than the available # of CPU cores. Assignment of multiple MPI tasks to a GPU will happen automatically if you create more MPI tasks/node than there are GPUs/mode. E.g. with 8 MPI tasks/node and 2 GPUs, each GPU will be shared by 4 MPI tasks. Use the "-sf gpu" "command-line switch"_Section_start.html#start_6, which will automatically append "gpu" to styles that support it. Use the "-pk gpu Ng" "command-line switch"_Section_start.html#start_6 to set Ng = # of GPUs/node to use. lmp_machine -sf gpu -pk gpu 1 -in in.script # 1 MPI task uses 1 GPU mpirun -np 12 lmp_machine -sf gpu -pk gpu 2 -in in.script # 12 MPI tasks share 2 GPUs on a single 16-core (or whatever) node mpirun -np 48 -ppn 12 lmp_machine -sf gpu -pk gpu 2 -in in.script # ditto on 4 16-core nodes :pre Note that if the "-sf gpu" switch is used, it also issues a default "package gpu 1"_package.html command, which sets the number of GPUs/node to 1. Using the "-pk" switch explicitly allows for setting of the number of GPUs/node to use and additional options. Its syntax is the same as same as the "package gpu" command. See the "package"_package.html command doc page for details, including the default values used for all its options if it is not specified. Note that the default for the "package gpu"_package.html command is to set the Newton flag to "off" pairwise interactions. It does not affect the setting for bonded interactions (LAMMPS default is "on"). The "off" setting for pairwise interaction is currently required for GPU package pair styles. [Or run with the GPU package by editing an input script:] The discussion above for the mpirun/mpiexec command, MPI tasks/node, and use of multiple MPI tasks/GPU is the same. Use the "suffix gpu"_suffix.html command, or you can explicitly add an "gpu" suffix to individual styles in your input script, e.g. pair_style lj/cut/gpu 2.5 :pre You must also use the "package gpu"_package.html command to enable the GPU package, unless the "-sf gpu" or "-pk gpu" "command-line switches"_Section_start.html#start_6 were used. It specifies the number of GPUs/node to use, as well as other options. [Speed-ups to expect:] The performance of a GPU versus a multi-core CPU is a function of your hardware, which pair style is used, the number of atoms/GPU, and the precision used on the GPU (double, single, mixed). See the "Benchmark page"_http://lammps.sandia.gov/bench.html of the LAMMPS web site for performance of the GPU package on various hardware, including the Titan HPC platform at ORNL. You should also experiment with how many MPI tasks per GPU to use to give the best performance for your problem and machine. This is also a function of the problem size and the pair style being using. Likewise, you should experiment with the precision setting for the GPU library to see if single or mixed precision will give accurate results, since they will typically be faster. [Guidelines for best performance:] Using multiple MPI tasks per GPU will often give the best performance, as allowed my most multi-core CPU/GPU configurations. :ulb,l If the number of particles per MPI task is small (e.g. 100s of particles), it can be more efficient to run with fewer MPI tasks per GPU, even if you do not use all the cores on the compute node. :l The "package gpu"_package.html command has several options for tuning performance. Neighbor lists can be built on the GPU or CPU. Force calculations can be dynamically balanced across the CPU cores and GPUs. GPU-specific settings can be made which can be optimized for different hardware. See the "packakge"_package.html command doc page for details. :l As described by the "package gpu"_package.html command, GPU accelerated pair styles can perform computations asynchronously with CPU computations. The "Pair" time reported by LAMMPS will be the maximum of the time required to complete the CPU pair style computations and the time required to complete the GPU pair style computations. Any time spent for GPU-enabled pair styles for computations that run simultaneously with "bond"_bond_style.html, "angle"_angle_style.html, "dihedral"_dihedral_style.html, "improper"_improper_style.html, and "long-range"_kspace_style.html calculations will not be included in the "Pair" time. :l When the {mode} setting for the package gpu command is force/neigh, the time for neighbor list calculations on the GPU will be added into the "Pair" time, not the "Neigh" time. An additional breakdown of the times required for various tasks on the GPU (data copy, neighbor calculations, force computations, etc) are output only with the LAMMPS screen output (not in the log file) at the end of each run. These timings represent total time spent on the GPU for each routine, regardless of asynchronous CPU calculations. :l The output section "GPU Time Info (average)" reports "Max Mem / Proc". This is the maximum memory used at one time on the GPU for data storage by a single MPI process. :l :ule [Restrictions:] None. diff --git a/doc/src/accelerate_intel.txt b/doc/src/accelerate_intel.txt index 74ae9d9a4..9eb295e0d 100644 --- a/doc/src/accelerate_intel.txt +++ b/doc/src/accelerate_intel.txt @@ -1,517 +1,514 @@ "Previous Section"_Section_packages.html - "LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c :link(lws,http://lammps.sandia.gov) :link(ld,Manual.html) :link(lc,Section_commands.html#comm) :line "Return to Section accelerate overview"_Section_accelerate.html 5.3.2 USER-INTEL package :h5 The USER-INTEL package is maintained by Mike Brown at Intel Corporation. It provides two methods for accelerating simulations, depending on the hardware you have. The first is acceleration on Intel CPUs by running in single, mixed, or double precision with vectorization. The second is acceleration on Intel Xeon Phi coprocessors via offloading neighbor list and non-bonded force calculations to the Phi. The same C++ code is used in both cases. When offloading to a coprocessor from a CPU, the same routine is run twice, once on the CPU and once with an offload flag. This allows LAMMPS to run on the CPU cores and coprocessor cores simultaneously. [Currently Available USER-INTEL Styles:] Angle Styles: charmm, harmonic :ulb,l Bond Styles: fene, harmonic :l Dihedral Styles: charmm, harmonic, opls :l Fixes: nve, npt, nvt, nvt/sllod :l Improper Styles: cvff, harmonic :l Pair Styles: buck/coul/cut, buck/coul/long, buck, eam, gayberne, charmm/coul/long, lj/cut, lj/cut/coul/long, lj/long/coul/long, sw, tersoff :l K-Space Styles: pppm, pppm/disp :l :ule [Speed-ups to expect:] The speedups will depend on your simulation, the hardware, which styles are used, the number of atoms, and the floating-point precision mode. Performance improvements are shown compared to LAMMPS {without using other acceleration packages} as these are under active development (and subject to performance changes). The measurements were performed using the input files available in the src/USER-INTEL/TEST directory with the provided run script. These are scalable in size; the results given are with 512K particles (524K for Liquid Crystal). Most of the simulations are standard LAMMPS benchmarks (indicated by the filename extension in parenthesis) with modifications to the run length and to add a warmup run (for use with offload benchmarks). :c,image(JPG/user_intel.png) Results are speedups obtained on Intel Xeon E5-2697v4 processors (code-named Broadwell) and Intel Xeon Phi 7250 processors (code-named Knights Landing) with "June 2017" LAMMPS built with Intel Parallel Studio 2017 update 2. Results are with 1 MPI task per physical core. See {src/USER-INTEL/TEST/README} for the raw simulation rates and instructions to reproduce. :line [Accuracy and order of operations:] In most molecular dynamics software, parallelization parameters (# of MPI, OpenMP, and vectorization) can change the results due to changing the order of operations with finite-precision calculations. The USER-INTEL package is deterministic. This means that the results should be reproducible from run to run with the {same} parallel configurations and when using determinstic libraries or library settings (MPI, OpenMP, FFT). However, there are differences in the USER-INTEL package that can change the order of operations compared to LAMMPS without acceleration: Neighbor lists can be created in a different order :ulb,l Bins used for sorting atoms can be oriented differently :l The default stencil order for PPPM is 7. By default, LAMMPS will calculate other PPPM parameters to fit the desired acuracy with this order :l The {newton} setting applies to all atoms, not just atoms shared between MPI tasks :l Vectorization can change the order for adding pairwise forces :l :ule The precision mode (described below) used with the USER-INTEL package can change the {accuracy} of the calculations. For the default {mixed} precision option, calculations between pairs or triplets of atoms are performed in single precision, intended to be within the inherent error of MD simulations. All accumulation is performed in double precision to prevent the error from growing with the number of atoms in the simulation. {Single} precision mode should not be used without appropriate validation. :line [Quick Start for Experienced Users:] LAMMPS should be built with the USER-INTEL package installed. Simulations should be run with 1 MPI task per physical {core}, not {hardware thread}. Edit src/MAKE/OPTIONS/Makefile.intel_cpu_intelmpi as necessary. :ulb,l Set the environment variable KMP_BLOCKTIME=0 :l "-pk intel 0 omp $t -sf intel" added to LAMMPS command-line :l $t should be 2 for Intel Xeon CPUs and 2 or 4 for Intel Xeon Phi :l For some of the simple 2-body potentials without long-range electrostatics, performance and scalability can be better with the "newton off" setting added to the input script :l For simulations on higher node counts, add "processors * * * grid numa" to the beginning of the input script for better scalability :l If using {kspace_style pppm} in the input script, add "kspace_modify diff ad" for better performance :l :ule For Intel Xeon Phi CPUs: Runs should be performed using MCDRAM. :ulb,l :ule For simulations using {kspace_style pppm} on Intel CPUs supporting AVX-512: Add "kspace_modify diff ad" to the input script :ulb,l The command-line option should be changed to "-pk intel 0 omp $r lrt yes -sf intel" where $r is the number of threads minus 1. :l Do not use thread affinity (set KMP_AFFINITY=none) :l The "newton off" setting may provide better scalability :l :ule For Intel Xeon Phi coprocessors (Offload): Edit src/MAKE/OPTIONS/Makefile.intel_coprocessor as necessary :ulb,l "-pk intel N omp 1" added to command-line where N is the number of coprocessors per node. :l :ule :line [Required hardware/software:] In order to use offload to coprocessors, an Intel Xeon Phi coprocessor and an Intel compiler are required. For this, the recommended version of the Intel compiler is 14.0.1.106 or versions 15.0.2.044 and higher. Although any compiler can be used with the USER-INTEL package, currently, vectorization directives are disabled by default when not using Intel compilers due to lack of standard support and observations of decreased performance. The OpenMP standard now supports directives for vectorization and we plan to transition the code to this standard once it is available in most compilers. We expect this to allow improved performance and support with other compilers. For Intel Xeon Phi x200 series processors (code-named Knights Landing), there are multiple configuration options for the hardware. For best performance, we recommend that the MCDRAM is configured in "Flat" mode and with the cluster mode set to "Quadrant" or "SNC4". "Cache" mode can also be used, although the performance might be slightly lower. [Notes about Simultaneous Multithreading:] Modern CPUs often support Simultaneous Multithreading (SMT). On Intel processors, this is called Hyper-Threading (HT) technology. SMT is hardware support for running multiple threads efficiently on a single core. {Hardware threads} or {logical cores} are often used to refer to the number of threads that are supported in hardware. For example, the Intel Xeon E5-2697v4 processor is described as having 36 cores and 72 threads. This means that 36 MPI processes or OpenMP threads can run simultaneously on separate cores, but that up to 72 MPI processes or OpenMP threads can be running on the CPU without costly operating system context switches. Molecular dynamics simulations will often run faster when making use of SMT. If a thread becomes stalled, for example because it is waiting on data that has not yet arrived from memory, another thread can start running so that the CPU pipeline is still being used efficiently. Although benefits can be seen by launching a MPI task for every hardware thread, for multinode simulations, we recommend that OpenMP threads are used for SMT instead, either with the USER-INTEL package, "USER-OMP package"_accelerate_omp.html, or "KOKKOS package"_accelerate_kokkos.html. In the example above, up to 36X speedups can be observed by using all 36 physical cores with LAMMPS. By using all 72 hardware threads, an additional 10-30% performance gain can be achieved. The BIOS on many platforms allows SMT to be disabled, however, we do not recommend this on modern processors as there is little to no benefit for any software package in most cases. The operating system will report every hardware thread as a separate core allowing one to determine the number of hardware threads available. On Linux systems, this information can normally be obtained with: cat /proc/cpuinfo :pre [Building LAMMPS with the USER-INTEL package:] NOTE: See the src/USER-INTEL/README file for additional flags that might be needed for best performance on Intel server processors code-named "Skylake". The USER-INTEL package must be installed into the source directory: make yes-user-intel :pre Several example Makefiles for building with the Intel compiler are included with LAMMPS in the src/MAKE/OPTIONS/ directory: Makefile.intel_cpu_intelmpi # Intel Compiler, Intel MPI, No Offload Makefile.knl # Intel Compiler, Intel MPI, No Offload Makefile.intel_cpu_mpich # Intel Compiler, MPICH, No Offload Makefile.intel_cpu_openpmi # Intel Compiler, OpenMPI, No Offload Makefile.intel_coprocessor # Intel Compiler, Intel MPI, Offload :pre Makefile.knl is identical to Makefile.intel_cpu_intelmpi except that it explicitly specifies that vectorization should be for Intel Xeon Phi x200 processors making it easier to cross-compile. For users with recent installations of Intel Parallel Studio, the process can be as simple as: make yes-user-intel source /opt/intel/parallel_studio_xe_2016.3.067/psxevars.sh # or psxevars.csh for C-shell make intel_cpu_intelmpi :pre -Alternatively, the build can be accomplished with the src/Make.py -script, described in "Section 4"_Section_packages.html of the -manual. Type "Make.py -h" for help. For an example: - -Make.py -v -p intel omp -intel cpu -a file intel_cpu_intelmpi :pre +Alternatively this can be done as a single command with +suitable make command invocations. This is discussed in "Section +4"_Section_packages.html of the manual. Note that if you build with support for a Phi coprocessor, the same binary can be used on nodes with or without coprocessors installed. However, if you do not have coprocessors on your system, building without offload support will produce a smaller binary. The general requirements for Makefiles with the USER-INTEL package are as follows. "-DLAMMPS_MEMALIGN=64" is required for CCFLAGS. When using Intel compilers, "-restrict" is required and "-qopenmp" is highly recommended for CCFLAGS and LINKFLAGS. LIB should include "-ltbbmalloc". For builds supporting offload, "-DLMP_INTEL_OFFLOAD" is required for CCFLAGS and "-qoffload" is required for LINKFLAGS. Other recommended CCFLAG options for best performance are "-O2 -fno-alias -ansi-alias -qoverride-limits fp-model fast=2 --no-prec-div". The Make.py command will add all of these -automatically. +-no-prec-div". NOTE: The vectorization and math capabilities can differ depending on the CPU. For Intel compilers, the "-x" flag specifies the type of processor for which to optimize. "-xHost" specifies that the compiler should build for the processor used for compiling. For Intel Xeon Phi x200 series processors, this option is "-xMIC-AVX512". For fourth generation Intel Xeon (v4/Broadwell) processors, "-xCORE-AVX2" should be used. For older Intel Xeon processors, "-xAVX" will perform best in general for the different simulations in LAMMPS. The default in most of the example Makefiles is to use "-xHost", however this should not be used when cross-compiling. [Running LAMMPS with the USER-INTEL package:] Running LAMMPS with the USER-INTEL package is similar to normal use with the exceptions that one should 1) specify that LAMMPS should use the USER-INTEL package, 2) specify the number of OpenMP threads, and 3) optionally specify the specific LAMMPS styles that should use the USER-INTEL package. 1) and 2) can be performed from the command-line or by editing the input script. 3) requires editing the input script. Advanced performance tuning options are also described below to get the best performance. When running on a single node (including runs using offload to a coprocessor), best performance is normally obtained by using 1 MPI task per physical core and additional OpenMP threads with SMT. For Intel Xeon processors, 2 OpenMP threads should be used for SMT. For Intel Xeon Phi CPUs, 2 or 4 OpenMP threads should be used (best choice depends on the simulation). In cases where the user specifies that LRT mode is used (described below), 1 or 3 OpenMP threads should be used. For multi-node runs, using 1 MPI task per physical core will often perform best, however, depending on the machine and scale, users might get better performance by decreasing the number of MPI tasks and using more OpenMP threads. For performance, the product of the number of MPI tasks and OpenMP threads should not exceed the number of available hardware threads in almost all cases. NOTE: Setting core affinity is often used to pin MPI tasks and OpenMP threads to a core or group of cores so that memory access can be uniform. Unless disabled at build time, affinity for MPI tasks and OpenMP threads on the host (CPU) will be set by default on the host {when using offload to a coprocessor}. In this case, it is unnecessary to use other methods to control affinity (e.g. taskset, numactl, I_MPI_PIN_DOMAIN, etc.). This can be disabled with the {no_affinity} option to the "package intel"_package.html command or by disabling the option at build time (by adding -DINTEL_OFFLOAD_NOAFFINITY to the CCFLAGS line of your Makefile). Disabling this option is not recommended, especially when running on a machine with Intel Hyper-Threading technology disabled. [Run with the USER-INTEL package from the command line:] To enable USER-INTEL optimizations for all available styles used in the input script, the "-sf intel" "command-line switch"_Section_start.html#start_6 can be used without any requirement for editing the input script. This switch will automatically append "intel" to styles that support it. It also invokes a default command: "package intel 1"_package.html. This package command is used to set options for the USER-INTEL package. The default package command will specify that USER-INTEL calculations are performed in mixed precision, that the number of OpenMP threads is specified by the OMP_NUM_THREADS environment variable, and that if coprocessors are present and the binary was built with offload support, that 1 coprocessor per node will be used with automatic balancing of work between the CPU and the coprocessor. You can specify different options for the USER-INTEL package by using the "-pk intel Nphi" "command-line switch"_Section_start.html#start_6 with keyword/value pairs as specified in the documentation. Here, Nphi = # of Xeon Phi coprocessors/node (ignored without offload support). Common options to the USER-INTEL package include {omp} to override any OMP_NUM_THREADS setting and specify the number of OpenMP threads, {mode} to set the floating-point precision mode, and {lrt} to enable Long-Range Thread mode as described below. See the "package intel"_package.html command for details, including the default values used for all its options if not specified, and how to set the number of OpenMP threads via the OMP_NUM_THREADS environment variable if desired. Examples (see documentation for your MPI/Machine for differences in launching MPI applications): mpirun -np 72 -ppn 36 lmp_machine -sf intel -in in.script # 2 nodes, 36 MPI tasks/node, $OMP_NUM_THREADS OpenMP Threads mpirun -np 72 -ppn 36 lmp_machine -sf intel -in in.script -pk intel 0 omp 2 mode double # Don't use any coprocessors that might be available, use 2 OpenMP threads for each task, use double precision :pre [Or run with the USER-INTEL package by editing an input script:] As an alternative to adding command-line arguments, the input script can be edited to enable the USER-INTEL package. This requires adding the "package intel"_package.html command to the top of the input script. For the second example above, this would be: package intel 0 omp 2 mode double :pre To enable the USER-INTEL package only for individual styles, you can add an "intel" suffix to the individual style, e.g.: pair_style lj/cut/intel 2.5 :pre Alternatively, the "suffix intel"_suffix.html command can be added to the input script to enable USER-INTEL styles for the commands that follow in the input script. [Tuning for Performance:] NOTE: The USER-INTEL package will perform better with modifications to the input script when "PPPM"_kspace_style.html is used: "kspace_modify diff ad"_kspace_modify.html should be added to the input script. Long-Range Thread (LRT) mode is an option to the "package intel"_package.html command that can improve performance when using "PPPM"_kspace_style.html for long-range electrostatics on processors with SMT. It generates an extra pthread for each MPI task. The thread is dedicated to performing some of the PPPM calculations and MPI communications. On Intel Xeon Phi x200 series CPUs, this will likely always improve performance, even on a single node. On Intel Xeon processors, using this mode might result in better performance when using multiple nodes, depending on the machine. To use this mode, specify that the number of OpenMP threads is one less than would normally be used for the run and add the "lrt yes" option to the "-pk" command-line suffix or "package intel" command. For example, if a run would normally perform best with "-pk intel 0 omp 4", instead use "-pk intel 0 omp 3 lrt yes". When using LRT, you should set the environment variable "KMP_AFFINITY=none". LRT mode is not supported when using offload. NOTE: Changing the "newton"_newton.html setting to off can improve performance and/or scalability for simple 2-body potentials such as lj/cut or when using LRT mode on processors supporting AVX-512. Not all styles are supported in the USER-INTEL package. You can mix the USER-INTEL package with styles from the "OPT"_accelerate_opt.html package or the "USER-OMP package"_accelerate_omp.html. Of course, this requires that these packages were installed at build time. This can performed automatically by using "-sf hybrid intel opt" or "-sf hybrid intel omp" command-line options. Alternatively, the "opt" and "omp" suffixes can be appended manually in the input script. For the latter, the "package omp"_package.html command must be in the input script or the "-pk omp Nt" "command-line switch"_Section_start.html#start_6 must be used where Nt is the number of OpenMP threads. The number of OpenMP threads should not be set differently for the different packages. Note that the "suffix hybrid intel omp"_suffix.html command can also be used within the input script to automatically append the "omp" suffix to styles when USER-INTEL styles are not available. NOTE: For simulations on higher node counts, add "processors * * * grid numa"_processors.html" to the beginning of the input script for better scalability. When running on many nodes, performance might be better when using fewer OpenMP threads and more MPI tasks. This will depend on the simulation and the machine. Using the "verlet/split"_run_style.html run style might also give better performance for simulations with "PPPM"_kspace_style.html electrostatics. Note that this is an alternative to LRT mode and the two cannot be used together. Currently, when using Intel MPI with Intel Xeon Phi x200 series CPUs, better performance might be obtained by setting the environment variable "I_MPI_SHM_LMT=shm" for Linux kernels that do not yet have full support for AVX-512. Runs on Intel Xeon Phi x200 series processors will always perform better using MCDRAM. Please consult your system documentation for the best approach to specify that MPI runs are performed in MCDRAM. [Tuning for Offload Performance:] The default settings for offload should give good performance. When using LAMMPS with offload to Intel coprocessors, best performance will typically be achieved with concurrent calculations performed on both the CPU and the coprocessor. This is achieved by offloading only a fraction of the neighbor and pair computations to the coprocessor or using "hybrid"_pair_hybrid.html pair styles where only one style uses the "intel" suffix. For simulations with long-range electrostatics or bond, angle, dihedral, improper calculations, computation and data transfer to the coprocessor will run concurrently with computations and MPI communications for these calculations on the host CPU. This is illustrated in the figure below for the rhodopsin protein benchmark running on E5-2697v2 processors with a Intel Xeon Phi 7120p coprocessor. In this plot, the vertical access is time and routines running at the same time are running concurrently on both the host and the coprocessor. :c,image(JPG/offload_knc.png) The fraction of the offloaded work is controlled by the {balance} keyword in the "package intel"_package.html command. A balance of 0 runs all calculations on the CPU. A balance of 1 runs all supported calculations on the coprocessor. A balance of 0.5 runs half of the calculations on the coprocessor. Setting the balance to -1 (the default) will enable dynamic load balancing that continously adjusts the fraction of offloaded work throughout the simulation. Because data transfer cannot be timed, this option typically produces results within 5 to 10 percent of the optimal fixed balance. If running short benchmark runs with dynamic load balancing, adding a short warm-up run (10-20 steps) will allow the load-balancer to find a near-optimal setting that will carry over to additional runs. The default for the "package intel"_package.html command is to have all the MPI tasks on a given compute node use a single Xeon Phi coprocessor. In general, running with a large number of MPI tasks on each node will perform best with offload. Each MPI task will automatically get affinity to a subset of the hardware threads available on the coprocessor. For example, if your card has 61 cores, with 60 cores available for offload and 4 hardware threads per core (240 total threads), running with 24 MPI tasks per node will cause each MPI task to use a subset of 10 threads on the coprocessor. Fine tuning of the number of threads to use per MPI task or the number of threads to use per core can be accomplished with keyword settings of the "package intel"_package.html command. The USER-INTEL package has two modes for deciding which atoms will be handled by the coprocessor. This choice is controlled with the {ghost} keyword of the "package intel"_package.html command. When set to 0, ghost atoms (atoms at the borders between MPI tasks) are not offloaded to the card. This allows for overlap of MPI communication of forces with computation on the coprocessor when the "newton"_newton.html setting is "on". The default is dependent on the style being used, however, better performance may be achieved by setting this option explicitly. When using offload with CPU Hyper-Threading disabled, it may help performance to use fewer MPI tasks and OpenMP threads than available cores. This is due to the fact that additional threads are generated internally to handle the asynchronous offload tasks. If pair computations are being offloaded to an Intel Xeon Phi coprocessor, a diagnostic line is printed to the screen (not to the log file), during the setup phase of a run, indicating that offload mode is being used and indicating the number of coprocessor threads per MPI task. Additionally, an offload timing summary is printed at the end of each run. When offloading, the frequency for "atom sorting"_atom_modify.html is changed to 1 so that the per-atom data is effectively sorted at every rebuild of the neighbor lists. All the available coprocessor threads on each Phi will be divided among MPI tasks, unless the {tptask} option of the "-pk intel" "command-line switch"_Section_start.html#start_6 is used to limit the coprocessor threads per MPI task. [Restrictions:] When offloading to a coprocessor, "hybrid"_pair_hybrid.html styles that require skip lists for neighbor builds cannot be offloaded. Using "hybrid/overlay"_pair_hybrid.html is allowed. Only one intel accelerated style may be used with hybrid styles. "Special_bonds"_special_bonds.html exclusion lists are not currently supported with offload, however, the same effect can often be accomplished by setting cutoffs for excluded atom types to 0. None of the pair styles in the USER-INTEL package currently support the "inner", "middle", "outer" options for rRESPA integration via the "run_style respa"_run_style.html command; only the "pair" option is supported. [References:] Brown, W.M., Carrillo, J.-M.Y., Mishra, B., Gavhane, N., Thakker, F.M., De Kraker, A.R., Yamada, M., Ang, J.A., Plimpton, S.J., "Optimizing Classical Molecular Dynamics in LAMMPS," in Intel Xeon Phi Processor High Performance Programming: Knights Landing Edition, J. Jeffers, J. Reinders, A. Sodani, Eds. Morgan Kaufmann. :ulb,l Brown, W. M., Semin, A., Hebenstreit, M., Khvostov, S., Raman, K., Plimpton, S.J. "Increasing Molecular Dynamics Simulation Rates with an 8-Fold Increase in Electrical Power Efficiency."_http://dl.acm.org/citation.cfm?id=3014915 2016 High Performance Computing, Networking, Storage and Analysis, SC16: International Conference (pp. 82-95). :l Brown, W.M., Carrillo, J.-M.Y., Gavhane, N., Thakkar, F.M., Plimpton, S.J. Optimizing Legacy Molecular Dynamics Software with Directive-Based Offload. Computer Physics Communications. 2015. 195: p. 95-101. :l :ule diff --git a/doc/src/accelerate_kokkos.txt b/doc/src/accelerate_kokkos.txt index 6ccd69584..712a05300 100644 --- a/doc/src/accelerate_kokkos.txt +++ b/doc/src/accelerate_kokkos.txt @@ -1,496 +1,493 @@ "Previous Section"_Section_packages.html - "LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c :link(lws,http://lammps.sandia.gov) :link(ld,Manual.html) :link(lc,Section_commands.html#comm) :line "Return to Section accelerate overview"_Section_accelerate.html 5.3.3 KOKKOS package :h5 The KOKKOS package was developed primarily by Christian Trott (Sandia) with contributions of various styles by others, including Sikandar Mashayak (UIUC), Stan Moore (Sandia), and Ray Shan (Sandia). The underlying Kokkos library was written primarily by Carter Edwards, Christian Trott, and Dan Sunderland (all Sandia). The KOKKOS package contains versions of pair, fix, and atom styles that use data structures and macros provided by the Kokkos library, which is included with LAMMPS in lib/kokkos. The Kokkos library is part of "Trilinos"_http://trilinos.sandia.gov/packages/kokkos and can also be downloaded from "Github"_https://github.com/kokkos/kokkos. Kokkos is a templated C++ library that provides two key abstractions for an application like LAMMPS. First, it allows a single implementation of an application kernel (e.g. a pair style) to run efficiently on different kinds of hardware, such as a GPU, Intel Phi, or many-core CPU. The Kokkos library also provides data abstractions to adjust (at compile time) the memory layout of basic data structures like 2d and 3d arrays and allow the transparent utilization of special hardware load and store operations. Such data structures are used in LAMMPS to store atom coordinates or forces or neighbor lists. The layout is chosen to optimize performance on different platforms. Again this functionality is hidden from the developer, and does not affect how the kernel is coded. These abstractions are set at build time, when LAMMPS is compiled with the KOKKOS package installed. All Kokkos operations occur within the context of an individual MPI task running on a single node of the machine. The total number of MPI tasks used by LAMMPS (one or multiple per compute node) is set in the usual manner via the mpirun or mpiexec commands, and is independent of Kokkos. Kokkos currently provides support for 3 modes of execution (per MPI task). These are OpenMP (for many-core CPUs), Cuda (for NVIDIA GPUs), and OpenMP (for Intel Phi). Note that the KOKKOS package supports running on the Phi in native mode, not offload mode like the USER-INTEL package supports. You choose the mode at build time to produce an executable compatible with specific hardware. Here is a quick overview of how to use the KOKKOS package for CPU acceleration, assuming one or more 16-core nodes. More details follow. use a C++11 compatible compiler make yes-kokkos make mpi KOKKOS_DEVICES=OpenMP # build with the KOKKOS package -make kokkos_omp # or Makefile.kokkos_omp already has variable set -Make.py -v -p kokkos -kokkos omp -o mpi -a file mpi # or one-line build via Make.py :pre +make kokkos_omp # or Makefile.kokkos_omp already has variable set :pre mpirun -np 16 lmp_mpi -k on -sf kk -in in.lj # 1 node, 16 MPI tasks/node, no threads mpirun -np 2 -ppn 1 lmp_mpi -k on t 16 -sf kk -in in.lj # 2 nodes, 1 MPI task/node, 16 threads/task mpirun -np 2 lmp_mpi -k on t 8 -sf kk -in in.lj # 1 node, 2 MPI tasks/node, 8 threads/task mpirun -np 32 -ppn 4 lmp_mpi -k on t 4 -sf kk -in in.lj # 8 nodes, 4 MPI tasks/node, 4 threads/task :pre specify variables and settings in your Makefile.machine that enable OpenMP, GPU, or Phi support include the KOKKOS package and build LAMMPS enable the KOKKOS package and its hardware options via the "-k on" command-line switch use KOKKOS styles in your input script :ul Here is a quick overview of how to use the KOKKOS package for GPUs, assuming one or more nodes, each with 16 cores and a GPU. More details follow. discuss use of NVCC, which Makefiles to examine use a C++11 compatible compiler KOKKOS_DEVICES = Cuda, OpenMP KOKKOS_ARCH = Kepler35 make yes-kokkos -make machine -Make.py -p kokkos -kokkos cuda arch=31 -o kokkos_cuda -a file kokkos_cuda :pre +make machine :pre mpirun -np 1 lmp_cuda -k on t 6 -sf kk -in in.lj # one MPI task, 6 threads on CPU mpirun -np 4 -ppn 1 lmp_cuda -k on t 6 -sf kk -in in.lj # ditto on 4 nodes :pre mpirun -np 2 lmp_cuda -k on t 8 g 2 -sf kk -in in.lj # two MPI tasks, 8 threads per CPU mpirun -np 32 -ppn 2 lmp_cuda -k on t 8 g 2 -sf kk -in in.lj # ditto on 16 nodes :pre Here is a quick overview of how to use the KOKKOS package for the Intel Phi: use a C++11 compatible compiler KOKKOS_DEVICES = OpenMP KOKKOS_ARCH = KNC make yes-kokkos -make machine -Make.py -p kokkos -kokkos phi -o kokkos_phi -a file mpi :pre +make machine :pre host=MIC, Intel Phi with 61 cores (240 threads/phi via 4x hardware threading): mpirun -np 1 lmp_g++ -k on t 240 -sf kk -in in.lj # 1 MPI task on 1 Phi, 1*240 = 240 mpirun -np 30 lmp_g++ -k on t 8 -sf kk -in in.lj # 30 MPI tasks on 1 Phi, 30*8 = 240 mpirun -np 12 lmp_g++ -k on t 20 -sf kk -in in.lj # 12 MPI tasks on 1 Phi, 12*20 = 240 mpirun -np 96 -ppn 12 lmp_g++ -k on t 20 -sf kk -in in.lj # ditto on 8 Phis :pre [Required hardware/software:] Kokkos support within LAMMPS must be built with a C++11 compatible compiler. If using gcc, version 4.7.2 or later is required. To build with Kokkos support for CPUs, your compiler must support the OpenMP interface. You should have one or more multi-core CPUs so that multiple threads can be launched by each MPI task running on a CPU. To build with Kokkos support for NVIDIA GPUs, NVIDIA Cuda software version 7.5 or later must be installed on your system. See the discussion for the "GPU"_accelerate_gpu.html package for details of how to check and do this. NOTE: For good performance of the KOKKOS package on GPUs, you must have Kepler generation GPUs (or later). The Kokkos library exploits texture cache options not supported by Telsa generation GPUs (or older). To build with Kokkos support for Intel Xeon Phi coprocessors, your sysmte must be configured to use them in "native" mode, not "offload" mode like the USER-INTEL package supports. [Building LAMMPS with the KOKKOS package:] You must choose at build time whether to build for CPUs (OpenMP), GPUs, or Phi. -You can do any of these in one line, using the src/Make.py script, -described in "Section 4"_Section_packages.html of the manual. -Type "Make.py -h" for help. If run from the src directory, these +You can do any of these in one line, using the suitable make command +line flags as described in "Section 4"_Section_packages.html of the +manual. If run from the src directory, these commands will create src/lmp_kokkos_omp, lmp_kokkos_cuda, and lmp_kokkos_phi. Note that the OMP and PHI options use src/MAKE/Makefile.mpi as the starting Makefile.machine. The CUDA option uses src/MAKE/OPTIONS/Makefile.kokkos_cuda. The latter two steps can be done using the "-k on", "-pk kokkos" and "-sf kk" "command-line switches"_Section_start.html#start_6 respectively. Or the effect of the "-pk" or "-sf" switches can be duplicated by adding the "package kokkos"_package.html or "suffix kk"_suffix.html commands respectively to your input script. Or you can follow these steps: CPU-only (run all-MPI or with OpenMP threading): cd lammps/src make yes-kokkos make kokkos_omp :pre CPU-only (only MPI, no threading): cd lammps/src make yes-kokkos make kokkos_mpi :pre Intel Xeon Phi (Intel Compiler, Intel MPI): cd lammps/src make yes-kokkos make kokkos_phi :pre CPUs and GPUs (with MPICH): cd lammps/src make yes-kokkos make kokkos_cuda_mpich :pre These examples set the KOKKOS-specific OMP, MIC, CUDA variables on the make command line which requires a GNU-compatible make command. Try "gmake" if your system's standard make complains. NOTE: If you build using make line variables and re-build LAMMPS twice with different KOKKOS options and the *same* target, e.g. g++ in the first two examples above, then you *must* perform a "make clean-all" or "make clean-machine" before each build. This is to force all the KOKKOS-dependent files to be re-compiled with the new options. NOTE: Currently, there are no precision options with the KOKKOS package. All compilation and computation is performed in double precision. There are other allowed options when building with the KOKKOS package. As above, they can be set either as variables on the make command line or in Makefile.machine. This is the full list of options, including those discussed above, Each takes a value shown below. The default value is listed, which is set in the lib/kokkos/Makefile.kokkos file. #Default settings specific options #Options: force_uvm,use_ldg,rdc KOKKOS_DEVICES, values = {OpenMP}, {Serial}, {Pthreads}, {Cuda}, default = {OpenMP} KOKKOS_ARCH, values = {KNC}, {SNB}, {HSW}, {Kepler}, {Kepler30}, {Kepler32}, {Kepler35}, {Kepler37}, {Maxwell}, {Maxwell50}, {Maxwell52}, {Maxwell53}, {ARMv8}, {BGQ}, {Power7}, {Power8}, default = {none} KOKKOS_DEBUG, values = {yes}, {no}, default = {no} KOKKOS_USE_TPLS, values = {hwloc}, {librt}, default = {none} KOKKOS_CUDA_OPTIONS, values = {force_uvm}, {use_ldg}, {rdc} :ul KOKKOS_DEVICE sets the parallelization method used for Kokkos code (within LAMMPS). KOKKOS_DEVICES=OpenMP means that OpenMP will be used. KOKKOS_DEVICES=Pthreads means that pthreads will be used. KOKKOS_DEVICES=Cuda means an NVIDIA GPU running CUDA will be used. If KOKKOS_DEVICES=Cuda, then the lo-level Makefile in the src/MAKE directory must use "nvcc" as its compiler, via its CC setting. For best performance its CCFLAGS setting should use -O3 and have a KOKKOS_ARCH setting that matches the compute capability of your NVIDIA hardware and software installation, e.g. KOKKOS_ARCH=Kepler30. Note the minimal required compute capability is 2.0, but this will give significantly reduced performance compared to Kepler generation GPUs with compute capability 3.x. For the LINK setting, "nvcc" should not be used; instead use g++ or another compiler suitable for linking C++ applications. Often you will want to use your MPI compiler wrapper for this setting (i.e. mpicxx). Finally, the lo-level Makefile must also have a "Compilation rule" for creating *.o files from *.cu files. See src/Makefile.cuda for an example of a lo-level Makefile with all of these settings. KOKKOS_USE_TPLS=hwloc binds threads to hardware cores, so they do not migrate during a simulation. KOKKOS_USE_TPLS=hwloc should always be used if running with KOKKOS_DEVICES=Pthreads for pthreads. It is not necessary for KOKKOS_DEVICES=OpenMP for OpenMP, because OpenMP provides alternative methods via environment variables for binding threads to hardware cores. More info on binding threads to cores is given in "Section 5.3"_Section_accelerate.html#acc_3. KOKKOS_ARCH=KNC enables compiler switches needed when compiling for an Intel Phi processor. KOKKOS_USE_TPLS=librt enables use of a more accurate timer mechanism on most Unix platforms. This library is not available on all platforms. KOKKOS_DEBUG is only useful when developing a Kokkos-enabled style within LAMMPS. KOKKOS_DEBUG=yes enables printing of run-time debugging information that can be useful. It also enables runtime bounds checking on Kokkos data structures. KOKKOS_CUDA_OPTIONS are additional options for CUDA. For more information on Kokkos see the Kokkos programmers' guide here: /lib/kokkos/doc/Kokkos_PG.pdf. [Run with the KOKKOS package from the command line:] The mpirun or mpiexec command sets the total number of MPI tasks used by LAMMPS (one or multiple per compute node) and the number of MPI tasks used per node. E.g. the mpirun command in MPICH does this via its -np and -ppn switches. Ditto for OpenMPI via -np and -npernode. When using KOKKOS built with host=OMP, you need to choose how many OpenMP threads per MPI task will be used (via the "-k" command-line switch discussed below). Note that the product of MPI tasks * OpenMP threads/task should not exceed the physical number of cores (on a node), otherwise performance will suffer. When using the KOKKOS package built with device=CUDA, you must use exactly one MPI task per physical GPU. When using the KOKKOS package built with host=MIC for Intel Xeon Phi coprocessor support you need to insure there are one or more MPI tasks per coprocessor, and choose the number of coprocessor threads to use per MPI task (via the "-k" command-line switch discussed below). The product of MPI tasks * coprocessor threads/task should not exceed the maximum number of threads the coprocessor is designed to run, otherwise performance will suffer. This value is 240 for current generation Xeon Phi(TM) chips, which is 60 physical cores * 4 threads/core. Note that with the KOKKOS package you do not need to specify how many Phi coprocessors there are per node; each coprocessors is simply treated as running some number of MPI tasks. You must use the "-k on" "command-line switch"_Section_start.html#start_6 to enable the KOKKOS package. It takes additional arguments for hardware settings appropriate to your system. Those arguments are "documented here"_Section_start.html#start_6. The two most commonly used options are: -k on t Nt g Ng :pre The "t Nt" option applies to host=OMP (even if device=CUDA) and host=MIC. For host=OMP, it specifies how many OpenMP threads per MPI task to use with a node. For host=MIC, it specifies how many Xeon Phi threads per MPI task to use within a node. The default is Nt = 1. Note that for host=OMP this is effectively MPI-only mode which may be fine. But for host=MIC you will typically end up using far less than all the 240 available threads, which could give very poor performance. The "g Ng" option applies to device=CUDA. It specifies how many GPUs per compute node to use. The default is 1, so this only needs to be specified is you have 2 or more GPUs per compute node. The "-k on" switch also issues a "package kokkos" command (with no additional arguments) which sets various KOKKOS options to default values, as discussed on the "package"_package.html command doc page. Use the "-sf kk" "command-line switch"_Section_start.html#start_6, which will automatically append "kk" to styles that support it. Use the "-pk kokkos" "command-line switch"_Section_start.html#start_6 if you wish to change any of the default "package kokkos"_package.html optionns set by the "-k on" "command-line switch"_Section_start.html#start_6. Note that the default for the "package kokkos"_package.html command is to use "full" neighbor lists and set the Newton flag to "off" for both pairwise and bonded interactions. This typically gives fastest performance. If the "newton"_newton.html command is used in the input script, it can override the Newton flag defaults. However, when running in MPI-only mode with 1 thread per MPI task, it will typically be faster to use "half" neighbor lists and set the Newton flag to "on", just as is the case for non-accelerated pair styles. You can do this with the "-pk" "command-line switch"_Section_start.html#start_6. [Or run with the KOKKOS package by editing an input script:] The discussion above for the mpirun/mpiexec command and setting appropriate thread and GPU values for host=OMP or host=MIC or device=CUDA are the same. You must still use the "-k on" "command-line switch"_Section_start.html#start_6 to enable the KOKKOS package, and specify its additional arguments for hardware options appropriate to your system, as documented above. Use the "suffix kk"_suffix.html command, or you can explicitly add a "kk" suffix to individual styles in your input script, e.g. pair_style lj/cut/kk 2.5 :pre You only need to use the "package kokkos"_package.html command if you wish to change any of its option defaults, as set by the "-k on" "command-line switch"_Section_start.html#start_6. [Speed-ups to expect:] The performance of KOKKOS running in different modes is a function of your hardware, which KOKKOS-enable styles are used, and the problem size. Generally speaking, the following rules of thumb apply: When running on CPUs only, with a single thread per MPI task, performance of a KOKKOS style is somewhere between the standard (un-accelerated) styles (MPI-only mode), and those provided by the USER-OMP package. However the difference between all 3 is small (less than 20%). :ulb,l When running on CPUs only, with multiple threads per MPI task, performance of a KOKKOS style is a bit slower than the USER-OMP package. :l When running large number of atoms per GPU, KOKKOS is typically faster than the GPU package. :l When running on Intel Xeon Phi, KOKKOS is not as fast as the USER-INTEL package, which is optimized for that hardware. :l :ule See the "Benchmark page"_http://lammps.sandia.gov/bench.html of the LAMMPS web site for performance of the KOKKOS package on different hardware. [Guidelines for best performance:] Here are guidline for using the KOKKOS package on the different hardware configurations listed above. Many of the guidelines use the "package kokkos"_package.html command See its doc page for details and default settings. Experimenting with its options can provide a speed-up for specific calculations. [Running on a multi-core CPU:] If N is the number of physical cores/node, then the number of MPI tasks/node * number of threads/task should not exceed N, and should typically equal N. Note that the default threads/task is 1, as set by the "t" keyword of the "-k" "command-line switch"_Section_start.html#start_6. If you do not change this, no additional parallelism (beyond MPI) will be invoked on the host CPU(s). You can compare the performance running in different modes: run with 1 MPI task/node and N threads/task run with N MPI tasks/node and 1 thread/task run with settings in between these extremes :ul Examples of mpirun commands in these modes are shown above. When using KOKKOS to perform multi-threading, it is important for performance to bind both MPI tasks to physical cores, and threads to physical cores, so they do not migrate during a simulation. If you are not certain MPI tasks are being bound (check the defaults for your MPI installation), binding can be forced with these flags: OpenMPI 1.8: mpirun -np 2 -bind-to socket -map-by socket ./lmp_openmpi ... Mvapich2 2.0: mpiexec -np 2 -bind-to socket -map-by socket ./lmp_mvapich ... :pre For binding threads with the KOKKOS OMP option, use thread affinity environment variables to force binding. With OpenMP 3.1 (gcc 4.7 or later, intel 12 or later) setting the environment variable OMP_PROC_BIND=true should be sufficient. For binding threads with the KOKKOS pthreads option, compile LAMMPS the KOKKOS HWLOC=yes option (see "this section"_Section_packages.html#KOKKOS of the manual for details). [Running on GPUs:] Insure the -arch setting in the machine makefile you are using, e.g. src/MAKE/Makefile.cuda, is correct for your GPU hardware/software. (see "this section"_Section_packages.html#KOKKOS of the manual for details). The -np setting of the mpirun command should set the number of MPI tasks/node to be equal to the # of physical GPUs on the node. Use the "-k" "command-line switch"_Section_commands.html#start_6 to specify the number of GPUs per node, and the number of threads per MPI task. As above for multi-core CPUs (and no GPU), if N is the number of physical cores/node, then the number of MPI tasks/node * number of threads/task should not exceed N. With one GPU (and one MPI task) it may be faster to use less than all the available cores, by setting threads/task to a smaller value. This is because using all the cores on a dual-socket node will incur extra cost to copy memory from the 2nd socket to the GPU. Examples of mpirun commands that follow these rules are shown above. NOTE: When using a GPU, you will achieve the best performance if your input script does not use any fix or compute styles which are not yet Kokkos-enabled. This allows data to stay on the GPU for multiple timesteps, without being copied back to the host CPU. Invoking a non-Kokkos fix or compute, or performing I/O for "thermo"_thermo_style.html or "dump"_dump.html output will cause data to be copied back to the CPU. You cannot yet assign multiple MPI tasks to the same GPU with the KOKKOS package. We plan to support this in the future, similar to the GPU package in LAMMPS. You cannot yet use both the host (multi-threaded) and device (GPU) together to compute pairwise interactions with the KOKKOS package. We hope to support this in the future, similar to the GPU package in LAMMPS. [Running on an Intel Phi:] Kokkos only uses Intel Phi processors in their "native" mode, i.e. not hosted by a CPU. As illustrated above, build LAMMPS with OMP=yes (the default) and MIC=yes. The latter insures code is correctly compiled for the Intel Phi. The OMP setting means OpenMP will be used for parallelization on the Phi, which is currently the best option within Kokkos. In the future, other options may be added. Current-generation Intel Phi chips have either 61 or 57 cores. One core should be excluded for running the OS, leaving 60 or 56 cores. Each core is hyperthreaded, so there are effectively N = 240 (4*60) or N = 224 (4*56) cores to run on. The -np setting of the mpirun command sets the number of MPI tasks/node. The "-k on t Nt" command-line switch sets the number of threads/task as Nt. The product of these 2 values should be N, i.e. 240 or 224. Also, the number of threads/task should be a multiple of 4 so that logical threads from more than one MPI task do not run on the same physical core. Examples of mpirun commands that follow these rules are shown above. [Restrictions:] As noted above, if using GPUs, the number of MPI tasks per compute node should equal to the number of GPUs per compute node. In the future Kokkos will support assigning multiple MPI tasks to a single GPU. Currently Kokkos does not support AMD GPUs due to limits in the available backend programming models. Specifically, Kokkos requires extensive C++ support from the Kernel language. This is expected to change in the future. diff --git a/doc/src/accelerate_omp.txt b/doc/src/accelerate_omp.txt index 81b7a5adc..fa7bef1a5 100644 --- a/doc/src/accelerate_omp.txt +++ b/doc/src/accelerate_omp.txt @@ -1,187 +1,183 @@ "Previous Section"_Section_packages.html - "LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c :link(lws,http://lammps.sandia.gov) :link(ld,Manual.html) :link(lc,Section_commands.html#comm) :line "Return to Section 5 overview"_Section_accelerate.html 5.3.4 USER-OMP package :h5 The USER-OMP package was developed by Axel Kohlmeyer at Temple University. It provides multi-threaded versions of most pair styles, nearly all bonded styles (bond, angle, dihedral, improper), several Kspace styles, and a few fix styles. The package currently uses the OpenMP interface for multi-threading. Here is a quick overview of how to use the USER-OMP package, assuming one or more 16-core nodes. More details follow. use -fopenmp with CCFLAGS and LINKFLAGS in Makefile.machine make yes-user-omp make mpi # build with USER-OMP package, if settings added to Makefile.mpi -make omp # or Makefile.omp already has settings -Make.py -v -p omp -o mpi -a file mpi # or one-line build via Make.py :pre +make omp # or Makefile.omp already has settings :pre lmp_mpi -sf omp -pk omp 16 < in.script # 1 MPI task, 16 threads mpirun -np 4 lmp_mpi -sf omp -pk omp 4 -in in.script # 4 MPI tasks, 4 threads/task mpirun -np 32 -ppn 4 lmp_mpi -sf omp -pk omp 4 -in in.script # 8 nodes, 4 MPI tasks/node, 4 threads/task :pre [Required hardware/software:] Your compiler must support the OpenMP interface. You should have one or more multi-core CPUs so that multiple threads can be launched by each MPI task running on a CPU. [Building LAMMPS with the USER-OMP package:] The lines above illustrate how to include/build with the USER-OMP package in two steps, using the "make" command. Or how to do it with -one command via the src/Make.py script, described in "Section -4"_Section_packages.html of the manual. Type "Make.py -h" for -help. +one command as described in "Section 4"_Section_packages.html of the manual. Note that the CCFLAGS and LINKFLAGS settings in Makefile.machine must include "-fopenmp". Likewise, if you use an Intel compiler, the -CCFLAGS setting must include "-restrict". The Make.py command will -add these automatically. +CCFLAGS setting must include "-restrict". [Run with the USER-OMP package from the command line:] The mpirun or mpiexec command sets the total number of MPI tasks used by LAMMPS (one or multiple per compute node) and the number of MPI tasks used per node. E.g. the mpirun command in MPICH does this via its -np and -ppn switches. Ditto for OpenMPI via -np and -npernode. You need to choose how many OpenMP threads per MPI task will be used by the USER-OMP package. Note that the product of MPI tasks * threads/task should not exceed the physical number of cores (on a node), otherwise performance will suffer. As in the lines above, use the "-sf omp" "command-line switch"_Section_start.html#start_6, which will automatically append "omp" to styles that support it. The "-sf omp" switch also issues a default "package omp 0"_package.html command, which will set the number of threads per MPI task via the OMP_NUM_THREADS environment variable. You can also use the "-pk omp Nt" "command-line switch"_Section_start.html#start_6, to explicitly set Nt = # of OpenMP threads per MPI task to use, as well as additional options. Its syntax is the same as the "package omp"_package.html command whose doc page gives details, including the default values used if it is not specified. It also gives more details on how to set the number of threads via the OMP_NUM_THREADS environment variable. [Or run with the USER-OMP package by editing an input script:] The discussion above for the mpirun/mpiexec command, MPI tasks/node, and threads/MPI task is the same. Use the "suffix omp"_suffix.html command, or you can explicitly add an "omp" suffix to individual styles in your input script, e.g. pair_style lj/cut/omp 2.5 :pre You must also use the "package omp"_package.html command to enable the USER-OMP package. When you do this you also specify how many threads per MPI task to use. The command doc page explains other options and how to set the number of threads via the OMP_NUM_THREADS environment variable. [Speed-ups to expect:] Depending on which styles are accelerated, you should look for a reduction in the "Pair time", "Bond time", "KSpace time", and "Loop time" values printed at the end of a run. You may see a small performance advantage (5 to 20%) when running a USER-OMP style (in serial or parallel) with a single thread per MPI task, versus running standard LAMMPS with its standard un-accelerated styles (in serial or all-MPI parallelization with 1 task/core). This is because many of the USER-OMP styles contain similar optimizations to those used in the OPT package, described in "Section 5.3.5"_accelerate_opt.html. With multiple threads/task, the optimal choice of number of MPI tasks/node and OpenMP threads/task can vary a lot and should always be tested via benchmark runs for a specific simulation running on a specific machine, paying attention to guidelines discussed in the next sub-section. A description of the multi-threading strategy used in the USER-OMP package and some performance examples are "presented here"_http://sites.google.com/site/akohlmey/software/lammps-icms/lammps-icms-tms2011-talk.pdf?attredirects=0&d=1 [Guidelines for best performance:] For many problems on current generation CPUs, running the USER-OMP package with a single thread/task is faster than running with multiple threads/task. This is because the MPI parallelization in LAMMPS is often more efficient than multi-threading as implemented in the USER-OMP package. The parallel efficiency (in a threaded sense) also varies for different USER-OMP styles. Using multiple threads/task can be more effective under the following circumstances: Individual compute nodes have a significant number of CPU cores but the CPU itself has limited memory bandwidth, e.g. for Intel Xeon 53xx (Clovertown) and 54xx (Harpertown) quad-core processors. Running one MPI task per CPU core will result in significant performance degradation, so that running with 4 or even only 2 MPI tasks per node is faster. Running in hybrid MPI+OpenMP mode will reduce the inter-node communication bandwidth contention in the same way, but offers an additional speedup by utilizing the otherwise idle CPU cores. :ulb,l The interconnect used for MPI communication does not provide sufficient bandwidth for a large number of MPI tasks per node. For example, this applies to running over gigabit ethernet or on Cray XT4 or XT5 series supercomputers. As in the aforementioned case, this effect worsens when using an increasing number of nodes. :l The system has a spatially inhomogeneous particle density which does not map well to the "domain decomposition scheme"_processors.html or "load-balancing"_balance.html options that LAMMPS provides. This is because multi-threading achives parallelism over the number of particles, not via their distribution in space. :l A machine is being used in "capability mode", i.e. near the point where MPI parallelism is maxed out. For example, this can happen when using the "PPPM solver"_kspace_style.html for long-range electrostatics on large numbers of nodes. The scaling of the KSpace calculation (see the "kspace_style"_kspace_style.html command) becomes the performance-limiting factor. Using multi-threading allows less MPI tasks to be invoked and can speed-up the long-range solver, while increasing overall performance by parallelizing the pairwise and bonded calculations via OpenMP. Likewise additional speedup can be sometimes be achived by increasing the length of the Coulombic cutoff and thus reducing the work done by the long-range solver. Using the "run_style verlet/split"_run_style.html command, which is compatible with the USER-OMP package, is an alternative way to reduce the number of MPI tasks assigned to the KSpace calculation. :l :ule Additional performance tips are as follows: The best parallel efficiency from {omp} styles is typically achieved when there is at least one MPI task per physical CPU chip, i.e. socket or die. :ulb,l It is usually most efficient to restrict threading to a single socket, i.e. use one or more MPI task per socket. :l NOTE: By default, several current MPI implementations use a processor affinity setting that restricts each MPI task to a single CPU core. Using multi-threading in this mode will force all threads to share the one core and thus is likely to be counterproductive. Instead, binding MPI tasks to a (multi-core) socket, should solve this issue. :l :ule [Restrictions:] None. diff --git a/doc/src/accelerate_opt.txt b/doc/src/accelerate_opt.txt index 5a2a5eac0..845264b52 100644 --- a/doc/src/accelerate_opt.txt +++ b/doc/src/accelerate_opt.txt @@ -1,71 +1,67 @@ "Previous Section"_Section_packages.html - "LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c :link(lws,http://lammps.sandia.gov) :link(ld,Manual.html) :link(lc,Section_commands.html#comm) :line "Return to Section accelerate overview"_Section_accelerate.html 5.3.5 OPT package :h5 The OPT package was developed by James Fischer (High Performance Technologies), David Richie, and Vincent Natoli (Stone Ridge Technologies). It contains a handful of pair styles whose compute() methods were rewritten in C++ templated form to reduce the overhead due to if tests and other conditional code. Here is a quick overview of how to use the OPT package. More details follow. make yes-opt -make mpi # build with the OPT package -Make.py -v -p opt -o mpi -a file mpi # or one-line build via Make.py :pre +make mpi # build with the OPT package :pre lmp_mpi -sf opt -in in.script # run in serial mpirun -np 4 lmp_mpi -sf opt -in in.script # run in parallel :pre [Required hardware/software:] None. [Building LAMMPS with the OPT package:] The lines above illustrate how to build LAMMPS with the OPT package in two steps, using the "make" command. Or how to do it with one command -via the src/Make.py script, described in "Section -4"_Section_packages.html of the manual. Type "Make.py -h" for -help. +as described in "Section 4"_Section_packages.html of the manual. Note that if you use an Intel compiler to build with the OPT package, the CCFLAGS setting in your Makefile.machine must include "-restrict". -The Make.py command will add this automatically. [Run with the OPT package from the command line:] As in the lines above, use the "-sf opt" "command-line switch"_Section_start.html#start_6, which will automatically append "opt" to styles that support it. [Or run with the OPT package by editing an input script:] Use the "suffix opt"_suffix.html command, or you can explicitly add an "opt" suffix to individual styles in your input script, e.g. pair_style lj/cut/opt 2.5 :pre [Speed-ups to expect:] You should see a reduction in the "Pair time" value printed at the end of a run. On most machines for reasonable problem sizes, it will be a 5 to 20% savings. [Guidelines for best performance:] Just try out an OPT pair style to see how it performs. [Restrictions:] None. diff --git a/doc/src/compute_voronoi_atom.txt b/doc/src/compute_voronoi_atom.txt index d084fcee6..a280b2b15 100644 --- a/doc/src/compute_voronoi_atom.txt +++ b/doc/src/compute_voronoi_atom.txt @@ -1,228 +1,228 @@ "LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c :link(lws,http://lammps.sandia.gov) :link(ld,Manual.html) :link(lc,Section_commands.html#comm) :line compute voronoi/atom command :h3 [Syntax:] compute ID group-ID voronoi/atom keyword arg ... :pre ID, group-ID are documented in "compute"_compute.html command :ulb,l voronoi/atom = style name of this compute command :l zero or more keyword/value pairs may be appended :l keyword = {only_group} or {surface} or {radius} or {edge_histo} or {edge_threshold} or {face_threshold} or {neighbors} or {peratom} :l {only_group} = no arg {occupation} = no arg {surface} arg = sgroup-ID sgroup-ID = compute the dividing surface between group-ID and sgroup-ID this keyword adds a third column to the compute output {radius} arg = v_r v_r = radius atom style variable for a poly-disperse Voronoi tessellation {edge_histo} arg = maxedge maxedge = maximum number of Voronoi cell edges to be accounted in the histogram {edge_threshold} arg = minlength minlength = minimum length for an edge to be counted {face_threshold} arg = minarea minarea = minimum area for a face to be counted {neighbors} value = {yes} or {no} = store list of all neighbors or no {peratom} value = {yes} or {no} = per-atom quantities accessible or no :pre :ule [Examples:] compute 1 all voronoi/atom compute 2 precipitate voronoi/atom surface matrix compute 3b precipitate voronoi/atom radius v_r compute 4 solute voronoi/atom only_group compute 5 defects voronoi/atom occupation compute 6 all voronoi/atom neighbors yes :pre [Description:] Define a computation that calculates the Voronoi tessellation of the atoms in the simulation box. The tessellation is calculated using all atoms in the simulation, but non-zero values are only stored for atoms in the group. By default two per-atom quantities are calculated by this compute. The first is the volume of the Voronoi cell around each atom. Any point in an atom's Voronoi cell is closer to that atom than any other. The second is the number of faces of the Voronoi cell. This is equal to the number of nearest neighbors of the central atom, plus any exterior faces (see note below). If the {peratom} keyword is set to "no", the per-atom quantities are still calculated, but they are not accessible. :line If the {only_group} keyword is specified the tessellation is performed only with respect to the atoms contained in the compute group. This is equivalent to deleting all atoms not contained in the group prior to evaluating the tessellation. If the {surface} keyword is specified a third quantity per atom is computed: the Voronoi cell surface of the given atom. {surface} takes a group ID as an argument. If a group other than {all} is specified, only the Voronoi cell facets facing a neighbor atom from the specified group are counted towards the surface area. In the example above, a precipitate embedded in a matrix, only atoms at the surface of the precipitate will have non-zero surface area, and only the outward facing facets of the Voronoi cells are counted (the hull of the precipitate). The total surface area of the precipitate can be obtained by running a "reduce sum" compute on c_2\[3\] If the {radius} keyword is specified with an atom style variable as the argument, a poly-disperse Voronoi tessellation is performed. Examples for radius variables are variable r1 atom (type==1)*0.1+(type==2)*0.4 compute radius all property/atom radius variable r2 atom c_radius :pre Here v_r1 specifies a per-type radius of 0.1 units for type 1 atoms and 0.4 units for type 2 atoms, and v_r2 accesses the radius property present in atom_style sphere for granular models. The {edge_histo} keyword activates the compilation of a histogram of number of edges on the faces of the Voronoi cells in the compute group. The argument {maxedge} of the this keyword is the largest number of edges on a single Voronoi cell face expected to occur in the sample. This keyword adds the generation of a global vector with {maxedge}+1 entries. The last entry in the vector contains the number of faces with with more than {maxedge} edges. Since the polygon with the smallest amount of edges is a triangle, entries 1 and 2 of the vector will always be zero. The {edge_threshold} and {face_threshold} keywords allow the suppression of edges below a given minimum length and faces below a given minimum area. Ultra short edges and ultra small faces can occur as artifacts of the Voronoi tessellation. These keywords will affect the neighbor count and edge histogram outputs. If the {occupation} keyword is specified the tessellation is only performed for the first invocation of the compute and then stored. For all following invocations of the compute the number of atoms in each Voronoi cell in the stored tessellation is counted. In this mode the compute returns a per-atom array with 2 columns. The first column is the number of atoms currently in the Voronoi volume defined by this atom at the time of the first invocation of the compute (note that the atom may have moved significantly). The second column contains the total number of atoms sharing the Voronoi cell of the stored tessellation at the location of the current atom. Numbers in column one can be any positive integer including zero, while column two values will always be greater than zero. Column one data can be used to locate vacancies (the coordinates are given by the atom coordinates at the time step when the compute was first invoked), while column two data can be used to identify interstitial atoms. If the {neighbors} value is set to yes, then this compute creates a local array with 3 columns. There is one row for each face of each Voronoi cell. The 3 columns are the atom ID of the atom that owns the cell, the atom ID of the atom in the neighboring cell (or zero if the face is external), and the area of the face. The array can be accessed by any command that uses local values from a compute as input. See "this section"_Section_howto.html#howto_15 for an overview of LAMMPS output options. More specifically, the array can be accessed by a "dump local"_dump.html command to write a file containing all the Voronoi neighbors in a system: compute 6 all voronoi/atom neighbors yes dump d2 all local 1 dump.neighbors index c_6\[1\] c_6\[2\] c_6\[3\] :pre If the {face_threshold} keyword is used, then only faces with areas greater than the threshold are stored. :line The Voronoi calculation is performed by the freely available "Voro++ package"_voronoi, written by Chris Rycroft at UC Berkeley and LBL, which must be installed on your system when building LAMMPS for use with this compute. See instructions on obtaining and installing the Voro++ software in the src/VORONOI/README file. :link(voronoi,http://math.lbl.gov/voro++/) NOTE: The calculation of Voronoi volumes is performed by each processor for the atoms it owns, and includes the effect of ghost atoms stored by the processor. This assumes that the Voronoi cells of owned atoms are not affected by atoms beyond the ghost atom cut-off distance. This is usually a good assumption for liquid and solid systems, but may lead to underestimation of Voronoi volumes in low density systems. By default, the set of ghost atoms stored by each processor is determined by the cutoff used for "pair_style"_pair_style.html interactions. The cutoff can be set explicitly via the "comm_modify cutoff"_comm_modify.html command. The Voronoi cells for atoms adjacent to empty regions will extend into those regions up to the communication cutoff in x, y, or z. In that situation, an exterior face is created at the cutoff distance normal to the x, y, or z direction. For triclinic systems, the exterior face is parallel to the corresponding reciprocal lattice vector. NOTE: The Voro++ package performs its calculation in 3d. This will still work for a 2d LAMMPS simulation, provided all the atoms have the same z coordinate. The Voronoi cell of each atom will be a columnar polyhedron with constant cross-sectional area along the z direction and two exterior faces at the top and bottom of the simulation box. If the atoms do not all have the same z coordinate, then the columnar cells will be accordingly distorted. The cross-sectional area of each Voronoi cell can be obtained by dividing its volume by the z extent of the simulation box. Note that you define the z extent of the simulation box for 2d simulations when using the "create_box"_create_box.html or "read_data"_read_data.html commands. [Output info:] By default, this compute calculates a per-atom array with 2 columns. In regular dynamic tessellation mode the first column is the Voronoi volume, the second is the neighbor count, as described above (read above for the output data in case the {occupation} keyword is specified). These values can be accessed by any command that uses per-atom values from a compute as input. See "Section 6.15"_Section_howto.html#howto_15 for an overview of LAMMPS output options. If the {peratom} keyword is set to "no", the per-atom array is still created, but it is not accessible. If the {edge_histo} keyword is used, then this compute generates a global vector of length {maxedge}+1, containing a histogram of the number of edges per face. If the {neighbors} value is set to yes, then this compute calculates a local array with 3 columns. There is one row for each face of each Voronoi cell. NOTE: Some LAMMPS commands such as the "compute reduce"_compute_reduce.html command can accept either a per-atom or local quantity. If this compute produces both quantities, the command may access the per-atom quantity, even if you want to access the local quantity. This effect can be eliminated by using the {peratom} keyword to turn off the production of the per-atom quantities. For the default value {yes} both quantities are produced. For the value {no}, only the local array is produced. The Voronoi cell volume will be in distance "units"_units.html cubed. The Voronoi face area will be in distance "units"_units.html squared. [Restrictions:] This compute is part of the VORONOI package. It is only enabled if LAMMPS was built with that package. See the "Making LAMMPS"_Section_start.html#start_3 section for more info. -It also requiers you have a copy of the Voro++ library built and +It also requires you have a copy of the Voro++ library built and installed on your system. See instructions on obtaining and installing the Voro++ software in the src/VORONOI/README file. [Related commands:] "dump custom"_dump.html, "dump local"_dump.html [Default:] {neighbors} no, {peratom} yes diff --git a/doc/src/fix_msst.txt b/doc/src/fix_msst.txt index 025c73389..310692669 100644 --- a/doc/src/fix_msst.txt +++ b/doc/src/fix_msst.txt @@ -1,193 +1,193 @@ "LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c :link(lws,http://lammps.sandia.gov) :link(ld,Manual.html) :link(lc,Section_commands.html#comm) :line fix msst command :h3 [Syntax:] fix ID group-ID msst dir shockvel keyword value ... :pre ID, group-ID are documented in "fix"_fix.html command :ulb,l msst = style name of this fix :l dir = {x} or {y} or {z} :l shockvel = shock velocity (strictly positive, distance/time units) :l zero or more keyword value pairs may be appended :l keyword = {q} or {mu} or {p0} or {v0} or {e0} or {tscale} or {beta} or {dftb} :l {q} value = cell mass-like parameter (mass^2/distance^4 units) {mu} value = artificial viscosity (mass/length/time units) {p0} value = initial pressure in the shock equations (pressure units) {v0} value = initial simulation cell volume in the shock equations (distance^3 units) {e0} value = initial total energy (energy units) {tscale} value = reduction in initial temperature (unitless fraction between 0.0 and 1.0) {dftb} value = {yes} or {no} for whether using MSST in conjunction with DFTB+ {beta} value = scale factor for improved energy conservation :pre :ule [Examples:] fix 1 all msst y 100.0 q 1.0e5 mu 1.0e5 fix 2 all msst z 50.0 q 1.0e4 mu 1.0e4 v0 4.3419e+03 p0 3.7797e+03 e0 -9.72360e+02 tscale 0.01 fix 1 all msst y 100.0 q 1.0e5 mu 1.0e5 dftb yes beta 0.5 :pre [Description:] This command performs the Multi-Scale Shock Technique (MSST) integration to update positions and velocities each timestep to mimic a compressive shock wave passing over the system. See "(Reed)"_#Reed for a detailed description of this method. The MSST varies the cell volume and temperature in such a way as to restrain the system to the shock Hugoniot and the Rayleigh line. These restraints correspond to the macroscopic conservation laws dictated by a shock front. {shockvel} determines the steady shock velocity that will be simulated. To perform a simulation, choose a value of {q} that provides volume compression on the timescale of 100 fs to 1 ps. If the volume is not compressing, either the shock speed is chosen to be below the material sound speed or {p0} has been chosen inaccurately. Volume compression at the start can be sped up by using a non-zero value of {tscale}. Use the smallest value of {tscale} that results in compression. Under some special high-symmetry conditions, the pressure (volume) and/or temperature of the system may oscillate for many cycles even with an appropriate choice of mass-like parameter {q}. Such oscillations have physical significance in some cases. The optional {mu} keyword adds an artificial viscosity that helps break the system symmetry to equilibrate to the shock Hugoniot and Rayleigh line more rapidly in such cases. The keyword {tscale} is a factor between 0 and 1 that determines what fraction of thermal kinetic energy is converted to compressive strain kinetic energy at the start of the simulation. Setting this parameter to a non-zero value may assist in compression at the start of simulations where it is slow to occur. If keywords {e0}, {p0},or {v0} are not supplied, these quantities will be calculated on the first step, after the energy specified by {tscale} is removed. The value of {e0} is not used in the dynamical equations, but is used in calculating the deviation from the Hugoniot. The keyword {beta} is a scaling term that can be added to the MSST ionic equations of motion to account for drift in the conserved quantity during long timescale simulations, similar to a Berendson -thermostat. See "(Reed)"_#Reed and "(Goldman)"_#Goldman for more +thermostat. See "(Reed)"_#Reed and "(Goldman)"_#Goldman2 for more details. The value of {beta} must be between 0.0 and 1.0 inclusive. A value of 0.0 means no contribution, a value of 1.0 means a full contribution. Values of shockvel less than a critical value determined by the material response will not have compressive solutions. This will be reflected in lack of significant change of the volume in the MSST. For all pressure styles, the simulation box stays orthogonal in shape. Parrinello-Rahman boundary conditions (tilted box) are supported by LAMMPS, but are not implemented for MSST. This fix computes a temperature and pressure and potential energy each timestep. To do this, the fix creates its own computes of style "temp" "pressure", and "pe", as if these commands had been issued: compute fix-ID_MSST_temp all temp compute fix-ID_MSST_press all pressure fix-ID_MSST_temp :pre compute fix-ID_MSST_pe all pe :pre See the "compute temp"_compute_temp.html and "compute pressure"_compute_pressure.html commands for details. Note that the IDs of the new computes are the fix-ID + "_MSST_temp" or "_MSST_press" or "_MSST_pe". The group for the new computes is "all". :line The {dftb} keyword is to allow this fix to be used when LAMMPS is being driven by DFTB+, a density-functional tight-binding code. If the keyword {dftb} is used with a value of {yes}, then the MSST equations are altered to account for the electron entropy contribution to the Hugonio relations and total energy. See "(Reed2)"_#Reed2 and -"(Goldman)"_#Goldman for details on this contribution. In this case, +"(Goldman)"_#Goldman2 for details on this contribution. In this case, you must define a "fix external"_fix_external.html command in your input script, which is used to callback to DFTB+ during the LAMMPS timestepping. DFTB+ will communicate its info to LAMMPS via that fix. :line [Restart, fix_modify, output, run start/stop, minimize info:] This fix writes the state of all internal variables to "binary restart files"_restart.html. See the "read_restart"_read_restart.html command for info on how to re-specify a fix in an input script that reads a restart file, so that the operation of the fix continues in an uninterrupted fashion. The progress of the MSST can be monitored by printing the global scalar and global vector quantities computed by the fix. The scalar is the cumulative energy change due to the fix. This is also the energy added to the potential energy by the "fix_modify"_fix_modify.html {energy} command. With this command, the thermo keyword {etotal} prints the conserved quantity of the MSST dynamic equations. This can be used to test if the MD timestep is sufficiently small for accurate integration of the dynamic equations. See also "thermo_style"_thermo_style.html command. The global vector contains four values in this order: \[{dhugoniot}, {drayleigh}, {lagrangian_speed}, {lagrangian_position}\] {dhugoniot} is the departure from the Hugoniot (temperature units). {drayleigh} is the departure from the Rayleigh line (pressure units). {lagrangian_speed} is the laboratory-frame Lagrangian speed (particle velocity) of the computational cell (velocity units). {lagrangian_position} is the computational cell position in the reference frame moving at the shock speed. This is usually a good estimate of distance of the computational cell behind the shock front. :ol To print these quantities to the log file with descriptive column headers, the following LAMMPS commands are suggested: fix msst all msst z fix_modify msst energy yes variable dhug equal f_msst\[1\] variable dray equal f_msst\[2\] variable lgr_vel equal f_msst\[3\] variable lgr_pos equal f_msst\[4\] thermo_style custom step temp ke pe lz pzz etotal v_dhug v_dray v_lgr_vel v_lgr_pos f_msst :pre These fixes compute a global scalar and a global vector of 4 quantities, which can be accessed by various "output commands"_Section_howto.html#howto_15. The scalar values calculated by this fix are "extensive"; the vector values are "intensive". [Restrictions:] This fix style is part of the SHOCK package. It is only enabled if LAMMPS was built with that package. See the "Making LAMMPS"_Section_start.html#start_3 section for more info. All cell dimensions must be periodic. This fix can not be used with a triclinic cell. The MSST fix has been tested only for the group-ID all. [Related commands:] "fix nphug"_fix_nphug.html, "fix deform"_fix_deform.html [Default:] The keyword defaults are q = 10, mu = 0, tscale = 0.01, dftb = no, beta = 0.0. Note that p0, v0, and e0 are calculated on the first timestep. :line :link(Reed) [(Reed)] Reed, Fried, and Joannopoulos, Phys. Rev. Lett., 90, 235503 (2003). :link(Reed2) [(Reed2)] Reed, J. Phys. Chem. C, 116, 2205 (2012). -:link(Goldman) +:link(Goldman2) [(Goldman)] Goldman, Srinivasan, Hamel, Fried, Gaus, and Elstner, J. Phys. Chem. C, 117, 7885 (2013). diff --git a/doc/src/fix_qbmsst.txt b/doc/src/fix_qbmsst.txt index 468206a57..2c116fb0f 100644 --- a/doc/src/fix_qbmsst.txt +++ b/doc/src/fix_qbmsst.txt @@ -1,219 +1,219 @@ "LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c :link(lws,http://lammps.sandia.gov) :link(ld,Manual.html) :link(lc,Section_commands.html#comm) :line fix qbmsst command :h3 [Syntax:] fix ID group-ID qbmsst dir shockvel keyword value ... :pre ID, group-ID are documented in "fix"_fix.html command :ulb,l qbmsst = style name of this fix :l dir = {x} or {y} or {z} :l shockvel = shock velocity (strictly positive, velocity units) :l zero or more keyword/value pairs may be appended :l keyword = {q} or {mu} or {p0} or {v0} or {e0} or {tscale} or {damp} or {seed}or {f_max} or {N_f} or {eta} or {beta} or {T_init} :l {q} value = cell mass-like parameter (mass^2/distance^4 units) {mu} value = artificial viscosity (mass/distance/time units) {p0} value = initial pressure in the shock equations (pressure units) {v0} value = initial simulation cell volume in the shock equations (distance^3 units) {e0} value = initial total energy (energy units) {tscale} value = reduction in initial temperature (unitless fraction between 0.0 and 1.0) {damp} value = damping parameter (time units) inverse of friction γ {seed} value = random number seed (positive integer) {f_max} value = upper cutoff frequency of the vibration spectrum (1/time units) {N_f} value = number of frequency bins (positive integer) {eta} value = coupling constant between the shock system and the quantum thermal bath (positive unitless) {beta} value = the quantum temperature is updated every beta time steps (positive integer) {T_init} value = quantum temperature for the initial state (temperature units) :pre :ule [Examples:] fix 1 all qbmsst z 0.122 q 25 mu 0.9 tscale 0.01 damp 200 seed 35082 f_max 0.3 N_f 100 eta 1 beta 400 T_init 110 (liquid methane modeled with the REAX force field, real units) fix 2 all qbmsst z 72 q 40 tscale 0.05 damp 1 seed 47508 f_max 120.0 N_f 100 eta 1.0 beta 500 T_init 300 (quartz modeled with the BKS force field, metal units) :pre Two example input scripts are given, including shocked alpha quartz and shocked liquid methane. The input script first equilibrate an initial state with the quantum thermal bath at the target temperature and then apply the qbmsst to simulate shock compression with quantum nuclear correction. The following two figures plot related quantities for shocked alpha quartz. :c,image(JPG/qbmsst_init.jpg) Figure 1. Classical temperature Tcl = ∑ mivi2/3NkB vs. time for coupling the alpha quartz initial state with the quantum thermal bath at target quantum temperature Tqm = 300 K. The NpH ensemble is used for time integration while QTB provides the colored random force. Tcl converges at the timescale of {damp} which is set to be 1 ps. :c,image(JPG/qbmsst_shock.jpg) Figure 2. Quantum temperature and pressure vs. time for simulating shocked alpha quartz with the QBMSST. The shock propagates along the z direction. Restart of the QBMSST command is demonstrated in the example input script. Thermodynamic quantities stay continuous before and after the restart. [Description:] This command performs the Quantum-Bath coupled Multi-Scale Shock Technique (QBMSST) integration. See "(Qi)"_#Qi for a detailed description of this method. The QBMSST provides description of the thermodynamics and kinetics of shock processes while incorporating quantum nuclear effects. The {shockvel} setting determines the steady shock velocity that will be simulated along direction {dir}. Quantum nuclear effects "(fix qtb)"_fix_qtb.html can be crucial especially when the temperature of the initial state is below the classical limit or there is a great change in the zero point energies between the initial and final states. Theoretical post processing quantum corrections of shock compressed water and methane have been -reported as much as 30% of the temperatures "(Goldman)"_#Goldman. A +reported as much as 30% of the temperatures "(Goldman)"_#Goldman1. A self-consistent method that couples the shock to a quantum thermal bath described by a colored noise Langevin thermostat has been developed by Qi et al "(Qi)"_#Qi and applied to shocked methane. The onset of chemistry is reported to be at a pressure on the shock Hugoniot that is 40% lower than observed with classical molecular dynamics. It is highly recommended that the system be already in an equilibrium state with a quantum thermal bath at temperature of {T_init}. The fix command "fix qtb"_fix_qtb.html at constant temperature {T_init} could be used before applying this command to introduce self-consistent quantum nuclear effects into the initial state. The parameters {q}, {mu}, {e0}, {p0}, {v0} and {tscale} are described in the command "fix msst"_fix_msst.html. The values of {e0}, {p0}, or {v0} will be calculated on the first step if not specified. The parameter of {damp}, {f_max}, and {N_f} are described in the command "fix qtb"_fix_qtb.html. The fix qbmsst command couples the shock system to a quantum thermal bath with a rate that is proportional to the change of the total energy of the shock system, etot - etot0. Here etot consists of both the system energy and a thermal term, see "(Qi)"_#Qi, and etot0 = {e0} is the initial total energy. The {eta} (η) parameter is a unitless coupling constant between the shock system and the quantum thermal bath. A small {eta} value cannot adjust the quantum temperature fast enough during the temperature ramping period of shock compression while large {eta} leads to big temperature oscillation. A value of {eta} between 0.3 and 1 is usually appropriate for simulating most systems under shock compression. We observe that different values of {eta} lead to almost the same final thermodynamic state behind the shock, as expected. The quantum temperature is updated every {beta} (β) steps with an integration time interval {beta} times longer than the simulation time step. In that case, etot is taken as its average over the past {beta} steps. The temperature of the quantum thermal bath Tqm changes dynamically according to the following equation where Δt is the MD time step and γ is the friction constant which is equal to the inverse of the {damp} parameter.
dTqm/dt = γηβl = 1[etot(t-lΔt)-etot0]/3βNkB
The parameter {T_init} is the initial temperature of the quantum thermal bath and the system before shock loading. For all pressure styles, the simulation box stays orthorhombic in shape. Parrinello-Rahman boundary conditions (tilted box) are supported by LAMMPS, but are not implemented for QBMSST. :line [Restart, fix_modify, output, run start/stop, minimize info:] Because the state of the random number generator is not written to "binary restart files"_restart.html, this fix cannot be restarted "exactly" in an uninterrupted fashion. However, in a statistical sense, a restarted simulation should produce similar behaviors of the system as if it is not interrupted. To achieve such a restart, one should write explicitly the same value for {q}, {mu}, {damp}, {f_max}, {N_f}, {eta}, and {beta} and set {tscale} = 0 if the system is compressed during the first run. The progress of the QBMSST can be monitored by printing the global scalar and global vector quantities computed by the fix. The global vector contains five values in this order: \[{dhugoniot}, {drayleigh}, {lagrangian_speed}, {lagrangian_position}, {quantum_temperature}\] {dhugoniot} is the departure from the Hugoniot (temperature units). {drayleigh} is the departure from the Rayleigh line (pressure units). {lagrangian_speed} is the laboratory-frame Lagrangian speed (particle velocity) of the computational cell (velocity units). {lagrangian_position} is the computational cell position in the reference frame moving at the shock speed. This is the distance of the computational cell behind the shock front. {quantum_temperature} is the temperature of the quantum thermal bath Tqm. :ol To print these quantities to the log file with descriptive column headers, the following LAMMPS commands are suggested. Here the "fix_modify"_fix_modify.html energy command is also enabled to allow the thermo keyword {etotal} to print the quantity etot. See also the "thermo_style"_thermo_style.html command. fix fix_id all msst z fix_modify fix_id energy yes variable dhug equal f_fix_id\[1\] variable dray equal f_fix_id\[2\] variable lgr_vel equal f_fix_id\[3\] variable lgr_pos equal f_fix_id\[4\] variable T_qm equal f_fix_id\[5\] thermo_style custom step temp ke pe lz pzz etotal v_dhug v_dray v_lgr_vel v_lgr_pos v_T_qm f_fix_id :pre The global scalar under the entry f_fix_id is the quantity of thermo energy as an extra part of etot. This global scalar and the vector of 5 quantities can be accessed by various "output commands"_Section_howto.html#howto_15. It is worth noting that the temp keyword under the "thermo_style"_thermo_style.html command print the instantaneous classical temperature Tcl as described in the command "fix qtb"_fix_qtb.html. :line [Restrictions:] This fix style is part of the USER-QTB package. It is only enabled if LAMMPS was built with that package. See the "Making LAMMPS"_Section_start.html#start_3 section for more info. All cell dimensions must be periodic. This fix can not be used with a triclinic cell. The QBMSST fix has been tested only for the group-ID all. :line [Related commands:] "fix qtb"_fix_qtb.html, "fix msst"_fix_msst.html :line [Default:] The keyword defaults are q = 10, mu = 0, tscale = 0.01, damp = 1, seed = 880302, f_max = 200.0, N_f = 100, eta = 1.0, beta = 100, and T_init=300.0. e0, p0, and v0 are calculated on the first step. :line -:link(Goldman) +:link(Goldman1) [(Goldman)] Goldman, Reed and Fried, J. Chem. Phys. 131, 204103 (2009) :link(Qi) [(Qi)] Qi and Reed, J. Phys. Chem. A 116, 10451 (2012). diff --git a/doc/src/neigh_modify.txt b/doc/src/neigh_modify.txt index 5c149d892..c4544cb29 100644 --- a/doc/src/neigh_modify.txt +++ b/doc/src/neigh_modify.txt @@ -1,217 +1,218 @@ "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 neigh_modify command :h3 [Syntax:] neigh_modify keyword values ... :pre one or more keyword/value pairs may be listed :ulb,l keyword = {delay} or {every} or {check} or {once} or {cluster} or {include} or {exclude} or {page} or {one} or {binsize} {delay} value = N N = delay building until this many steps since last build {every} value = M M = build neighbor list every this many steps {check} value = {yes} or {no} {yes} = only build if some atom has moved half the skin distance or more {no} = always build on 1st step that {every} and {delay} are satisfied {once} {yes} = only build neighbor list once at start of run and never rebuild {no} = rebuild neighbor list according to other settings {cluster} {yes} = check bond,angle,etc neighbor list for nearby clusters {no} = do not check bond,angle,etc neighbor list for nearby clusters {include} value = group-ID group-ID = only build pair neighbor lists for atoms in this group {exclude} values: type M N M,N = exclude if one atom in pair is type M, other is type N group group1-ID group2-ID group1-ID,group2-ID = exclude if one atom is in 1st group, other in 2nd molecule/intra group-ID group-ID = exclude if both atoms are in the same molecule and in group molecule/inter group-ID group-ID = exclude if both atoms are in different molecules and in group none delete all exclude settings {page} value = N N = number of pairs stored in a single neighbor page {one} value = N N = max number of neighbors of one atom {binsize} value = size size = bin size for neighbor list construction (distance units) :pre :ule [Examples:] neigh_modify every 2 delay 10 check yes page 100000 neigh_modify exclude type 2 3 neigh_modify exclude group frozen frozen check no neigh_modify exclude group residue1 chain3 neigh_modify exclude molecule/intra rigid :pre [Description:] This command sets parameters that affect the building and use of pairwise neighbor lists. Depending on what pair interactions and other commands are defined, a simulation may require one or more neighbor lists. The {every}, {delay}, {check}, and {once} options affect how often lists are built as a simulation runs. The {delay} setting means never build new lists until at least N steps after the previous build. The {every} setting means build lists every M steps (after the delay has passed). If the {check} setting is {no}, the lists are built on the first step that satisfies the {delay} and {every} settings. If the {check} setting is {yes}, then the {every} and {delay} settings determine when a build may possibly be performed, but an actual build only occurs if some atom has moved more than half the skin distance (specified in the "neighbor"_neighbor.html command) since the last build. If the {once} setting is yes, then the neighbor list is only built once at the beginning of each run, and never rebuilt, except on steps when a restart file is written, or steps when a fix forces a rebuild to occur (e.g. fixes that create or delete atoms, such as "fix deposit"_fix_deposit.html or "fix evaporate"_fix_evaporate.html). This setting should only be made if you are certain atoms will not move far enough that the neighbor list should be rebuilt, e.g. running a simulation of a cold crystal. Note that it is not that expensive to check if neighbor lists should be rebuilt. When the rRESPA integrator is used (see the "run_style"_run_style.html command), the {every} and {delay} parameters refer to the longest (outermost) timestep. The {cluster} option does a sanity test every time neighbor lists are built for bond, angle, dihedral, and improper interactions, to check that each set of 2, 3, or 4 atoms is a cluster of nearby atoms. It does this by computing the distance between pairs of atoms in the interaction and insuring they are not further apart than half the periodic box length. If they are, an error is generated, since the interaction would be computed between far-away atoms instead of their nearby periodic images. The only way this should happen is if the pairwise cutoff is so short that atoms that are part of the same interaction are not communicated as ghost atoms. This is an unusual model (e.g. no pair interactions at all) and the problem can be fixed by use of the "comm_modify cutoff"_comm_modify.html command. Note that to save time, the default {cluster} setting is {no}, so that this check is not performed. The {include} option limits the building of pairwise neighbor lists to atoms in the specified group. This can be useful for models where a large portion of the simulation is particles that do not interact with other particles or with each other via pairwise interactions. The group specified with this option must also be specified via the -"atom_modify first"_atom_modify.html command. +"atom_modify first"_atom_modify.html command. Note that specifying +"all" as the group-ID effectively turns off the {include} option. The {exclude} option turns off pairwise interactions between certain pairs of atoms, by not including them in the neighbor list. These are sample scenarios where this is useful: In crack simulations, pairwise interactions can be shut off between 2 slabs of atoms to effectively create a crack. :ulb,l When a large collection of atoms is treated as frozen, interactions between those atoms can be turned off to save needless computation. E.g. Using the "fix setforce"_fix_setforce.html command to freeze a wall or portion of a bio-molecule. :l When one or more rigid bodies are specified, interactions within each body can be turned off to save needless computation. See the "fix rigid"_fix_rigid.html command for more details. :l :ule The {exclude type} option turns off the pairwise interaction if one atom is of type M and the other of type N. M can equal N. The {exclude group} option turns off the interaction if one atom is in the first group and the other is the second. Group1-ID can equal group2-ID. The {exclude molecule/intra} option turns off the interaction if both atoms are in the specified group and in the same molecule, as determined by their molecule ID. The {exclude molecule/inter} turns off the interaction between pairs of atoms that have different molecule IDs and are both in the specified group. Each of the exclude options can be specified multiple times. The {exclude type} option is the most efficient option to use; it requires only a single check, no matter how many times it has been specified. The other exclude options are more expensive if specified multiple times; they require one check for each time they have been specified. Note that the exclude options only affect pairwise interactions; see the "delete_bonds"_delete_bonds.html command for information on turning off bond interactions. NOTE: Excluding pairwise interactions will not work correctly when also using a long-range solver via the "kspace_style"_kspace_style.html command. LAMMPS will give a warning to this effect. This is because the short-range pairwise interaction needs to subtract off a term from the total energy for pairs whose short-range interaction is excluded, to compensate for how the long-range solver treats the interaction. This is done correctly for pairwise interactions that are excluded (or weighted) via the "special_bonds"_special_bonds.html command. But it is not done for interactions that are excluded via these neigh_modify exclude options. The {page} and {one} options affect how memory is allocated for the neighbor lists. For most simulations the default settings for these options are fine, but if a very large problem is being run or a very long cutoff is being used, these parameters can be tuned. The indices of neighboring atoms are stored in "pages", which are allocated one after another as they fill up. The size of each page is set by the {page} value. A new page is allocated when the next atom's neighbors could potentially overflow the list. This threshold is set by the {one} value which tells LAMMPS the maximum number of neighbor's one atom can have. NOTE: LAMMPS can crash without an error message if the number of neighbors for a single particle is larger than the {page} setting, which means it is much, much larger than the {one} setting. This is because LAMMPS doesn't error check these limits for every pairwise interaction (too costly), but only after all the particle's neighbors have been found. This problem usually means something is very wrong with the way you've setup your problem (particle spacing, cutoff length, neighbor skin distance, etc). If you really expect that many neighbors per particle, then boost the {one} and {page} settings accordingly. The {binsize} option allows you to specify what size of bins will be used in neighbor list construction to sort and find neighboring atoms. By default, for "neighbor style bin"_neighbor.html, LAMMPS uses bins that are 1/2 the size of the maximum pair cutoff. For "neighbor style multi"_neighbor.html, the bins are 1/2 the size of the minimum pair cutoff. Typically these are good values values for minimizing the time for neighbor list construction. This setting overrides the default. If you make it too big, there is little overhead due to looping over bins, but more atoms are checked. If you make it too small, the optimal number of atoms is checked, but bin overhead goes up. If you set the binsize to 0.0, LAMMPS will use the default binsize of 1/2 the cutoff. [Restrictions:] If the "delay" setting is non-zero, then it must be a multiple of the "every" setting. The molecule/intra and molecule/inter exclude options can only be used with atom styles that define molecule IDs. The value of the {page} setting must be at least 10x larger than the {one} setting. This insures neighbor pages are not mostly empty space. [Related commands:] "neighbor"_neighbor.html, "delete_bonds"_delete_bonds.html [Default:] The option defaults are delay = 10, every = 1, check = yes, once = no, -cluster = no, include = all, exclude = none, page = 100000, one = -2000, and binsize = 0.0. +cluster = no, include = all (same as no include option defined), +exclude = none, page = 100000, one = 2000, and binsize = 0.0. diff --git a/doc/src/pair_kim.txt b/doc/src/pair_kim.txt index 5a623e5ec..c5d910e27 100644 --- a/doc/src/pair_kim.txt +++ b/doc/src/pair_kim.txt @@ -1,118 +1,139 @@ "LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c :link(lws,http://lammps.sandia.gov) :link(ld,Manual.html) :link(lc,Section_commands.html#comm) :line pair_style kim command :h3 [Syntax:] pair_style kim virialmode model printflag :pre virialmode = KIMvirial or LAMMPSvirial model = name of KIM model (potential) printflag = 1/0 do or do not print KIM descriptor file, optional :ul [Examples:] pair_style kim KIMvirial model_Ar_P_Morse pair_coeff * * Ar Ar :pre pair_style kim KIMvirial model_Ar_P_Morse 1 pair_coeff * * Ar Ar :pre [Description:] This pair style is a wrapper on the "Knowledge Base for Interatomic -Models (KIM)"_https://openkim.org repository of interatomic potentials, -so that they can be used by LAMMPS scripts. +Models (OpenKIM)"_https://openkim.org repository of interatomic +potentials, so that they can be used by LAMMPS scripts. -In KIM lingo, a potential is a "model" and a model contains both the -analytic formulas that define the potential as well as the parameters -needed to run it for one or more materials, including coefficients and -cutoffs. +Note that in LAMMPS lingo, a KIM model driver is a pair style +(e.g. EAM or Tersoff). A KIM model is a pair style for a particular +element or alloy and set of parameters, e.g. EAM for Cu with a +specific EAM potential file. + +See the current list of "KIM model +drivers"_https://openkim.org/kim-items/model-drivers/alphabetical. + +See the current list of all "KIM +models"_https://openkim.org/kim-items/models/by-model-drivers + +See the list of "example KIM models"_https://openkim.org/kim-api which +are included in the KIM library by default, in the "What is in the KIM +API source package?" section. + +To use this pair style, you must first download and install the KIM +API library from the "OpenKIM website"_https://openkim.org. The "KIM +section of Section packages"_Section_packages.html#KIM has +instructions on how to do this with a simple make command, when +building LAMMPS. + +See the examples/kim dir for an input script that uses a KIM model +(potential) for Lennard-Jones. + +:line The argument {virialmode} determines how the global virial is calculated. If {KIMvirial} is specified, the KIM model performs the global virial calculation (if it knows how). If {LAMMPSvirial} is specified, LAMMPS computes the global virial using its fdotr mechanism. The argument {model} is the name of the KIM model for a specific potential as KIM defines it. In principle, LAMMPS can invoke any KIM model. You should get an error or warning message from either LAMMPS or KIM if there is an incompatibility. The argument {printflag} is optional. If it is set to a non-zero value then a KIM descriptor file is printed when KIM is invoked. This can be useful for debugging. The default is to not print this file. Only a single pair_coeff command is used with the {kim} style which specifies the mapping of LAMMPS atom types to KIM elements. This is done by specifying N additional arguments after the * * in the pair_coeff command, where N is the number of LAMMPS atom types: N element names = mapping of KIM elements to atom types :ul As an example, imagine the KIM model supports Si and C atoms. If your LAMMPS simulation has 4 atom types and you want the 1st 3 to be Si, and the 4th to be C, you would use the following pair_coeff command: pair_coeff * * Si Si Si C :pre The 1st 2 arguments must be * * so as to span all LAMMPS atom types. The first three Si arguments map LAMMPS atom types 1,2,3 to Si as defined within KIM. The final C argument maps LAMMPS atom type 4 to C as defined within KIM. If a mapping value is specified as NULL, the mapping is not performed. This can only be used when a {kim} potential is used as part of the {hybrid} pair style. The NULL values are placeholders for atom types that will be used with other potentials. :line In addition to the usual LAMMPS error messages, the KIM library itself may generate errors, which should be printed to the screen. In this case it is also useful to check the kim.log file for additional error information. This file kim.log should be generated in the same directory where LAMMPS is running. To download, build, and install the KIM library on your system, see the lib/kim/README file. Once you have done this and built LAMMPS with the KIM package installed you can run the example input scripts in examples/kim. :line [Mixing, shift, table, tail correction, restart, rRESPA info]: This pair style does not support the "pair_modify"_pair_modify.html mix, shift, table, and tail options. This pair style does not write its information to "binary restart files"_restart.html, since KIM stores the potential parameters. Thus, you need to re-specify the pair_style and pair_coeff commands in an input script that reads a restart file. This pair style can only be used via the {pair} keyword of the "run_style respa"_run_style.html command. It does not support the {inner}, {middle}, {outer} keywords. :line [Restrictions:] This pair style is part of the KIM package. It is only enabled if LAMMPS was built with that package. See the "Making LAMMPS"_Section_start.html#start_3 section for more info. This current version of pair_style kim is compatible with the kim-api package version 1.6.0 and higher. [Related commands:] "pair_coeff"_pair_coeff.html [Default:] none diff --git a/examples/README b/examples/README index 0b037f5c3..dc622ef7c 100644 --- a/examples/README +++ b/examples/README @@ -1,170 +1,170 @@ LAMMPS example problems There are 3 flavors of sub-directories in this file, each with sample problems you can run with LAMMPS. lower-case directories = simple test problems for LAMMPS and its packages upper-case directories = more complex problems USER directory with its own sub-directories = tests for USER packages Each is discussed below. ------------------------------------------ Lower-case directories Each of these sub-directories contains a sample problem you can run with LAMMPS. Most are 2d models so that they run quickly, requiring a few seconds to a few minutes to run on a desktop machine. Each problem has an input script (in.*) and produces a log file (log.*) and (optionally) a dump file (dump.*) or image files (image.*) or movie (movie.mpg) when it runs. Some use a data file (data.*) of initial coordinates as additional input. Some require that you install one or more optional LAMMPS packages. A few sample log file outputs on different machines and different numbers of processors are included in the directories to compare your answers to. E.g. a log file like log.crack.date.foo.P means it ran on P processors of machine "foo" with the dated version of LAMMPS. Note that these problems should get statistically similar answers when run on different machines or different numbers of processors, but not identical answers to those in the log of dump files included here. See the Errors section of the LAMMPS documentation for more discussion. Most of the example input scripts have commented-out lines that produce dump snapshots of the running simulation in any of 3 formats. If you uncomment the dump command in the input script, a text dump file will be produced, which can be animated by various visualization programs (see http://lammps.sandia.gov/viz.html) such as Ovito, VMD, or AtomEye. If you uncomment the dump image command in the input script, and assuming you have built LAMMPS with a JPG library, JPG snapshot images will be produced when the simulation runs. They can be quickly post-processed into a movie using commands described on the dump image doc page. If you uncomment the dump movie command in the input script, and assuming you have built LAMMPS with the FFMPEG library, an MPG movie will be produced when the simulation runs. The movie file can be played using various viewers, such as mplayer or QuickTime. Animations of many of these examples can be viewed on the Movies section of the LAMMPS WWW Site. These are the sample problems and their output in the various sub-directories: accelerate: use of all the various accelerator packages -airebo: example for using AIREBO and AIREBO-M +airebo: polyethylene with AIREBO potential balance: dynamic load balancing, 2d system body: body particles, 2d system cmap: CMAP 5-body contributions to CHARMM force field colloid: big colloid particles in a small particle solvent, 2d system comb: models using the COMB potential coreshell: adiabatic core/shell model controller: use of fix controller as a thermostat crack: crack propagation in a 2d solid deposit: deposition of atoms and molecules onto a 3d substrate dipole: point dipolar particles, 2d system dreiding: methanol via Dreiding FF eim: NaCl using the EIM potential ellipse: ellipsoidal particles in spherical solvent, 2d system flow: Couette and Poiseuille flow in a 2d channel friction: frictional contact of spherical asperities between 2d surfaces gcmc: Grand Canonical Monte Carlo (GCMC) via the fix gcmc command granregion: use of fix wall/region/gran as boundary on granular particles hugoniostat: Hugoniostat shock dynamics indent: spherical indenter into a 2d solid kim: use of potentials in Knowledge Base for Interatomic Models (KIM) meam: MEAM test for SiC and shear (same as shear examples) melt: rapid melt of 3d LJ system micelle: self-assembly of small lipid-like molecules into 2d bilayers min: energy minimization of 2d LJ melt mscg: parameterize a multi-scale coarse-graining (MSCG) model msst: MSST shock dynamics nb3b: use of nonbonded 3-body harmonic pair style neb: nudged elastic band (NEB) calculation for barrier finding nemd: non-equilibrium MD of 2d sheared system obstacle: flow around two voids in a 2d channel peptide: dynamics of a small solvated peptide chain (5-mer) peri: Peridynamic model of cylinder impacted by indenter pour: pouring of granular particles into a 3d box, then chute flow prd: parallel replica dynamics of vacancy diffusion in bulk Si python: use of PYTHON package to invoke Python code from input script qeq: use of QEQ package for charge equilibration reax: RDX and TATB models using the ReaxFF rigid: rigid bodies modeled as independent or coupled shear: sideways shear applied to 2d solid, with and without a void snap: use of SNAP potential for Ta srd: stochastic rotation dynamics (SRD) particles as solvent snap: NVE dynamics for BCC tantalum crystal using SNAP potential streitz: Streitz-Mintmire potential for Al2O3 tad: temperature-accelerated dynamics of vacancy diffusion in bulk Si vashishta: models using the Vashishta potential voronoi: Voronoi tesselation via compute voronoi/atom command Here is how you might run and visualize one of the sample problems: cd indent cp ../../src/lmp_mpi . # copy LAMMPS executable to this dir lmp_mpi -in in.indent # run the problem Running the simulation produces the files {dump.indent} and {log.lammps}. You can visualize the dump file as follows: ../../tools/xmovie/xmovie -scale dump.indent If you uncomment the dump image line(s) in the input script a series of JPG images will be produced by the run. These can be viewed individually or turned into a movie or animated by tools like ImageMagick or QuickTime or various Windows-based tools. See the dump image doc page for more details. E.g. this Imagemagick command would create a GIF file suitable for viewing in a browser. % convert -loop 1 *.jpg foo.gif ------------------------------------------ Upper-case directories The ASPHERE directory has examples of how to model aspherical particles with or without solvent, in 3 styles LAMMPS provides. Namely point ellipsoids, rigid bodies, and generalized aspherical bodies built from line/triangle surface facets in 2d/3d. See the ASPHERE/README file to get started. The COUPLE directory has examples of how to use LAMMPS as a library, either by itself or in tandem with another code or library. See the COUPLE/README file to get started. The ELASTIC directory has an example script for computing elastic constants at zero temperature, using an Si example. See the ELASTIC/in.elastic file for more info. The ELASTIC_T directory has an example script for computing elastic constants at finite temperature, using an Si example. See the ELASTIC_T/in.elastic file for more info. The HEAT directory has example scripts for heat exchange algorithms (e.g. used for establishing a thermal gradient), using two different methods. See the HEAT/README file for more info. The KAPPA directory has example scripts for computing the thermal conductivity (kappa) of a LJ liquid using 5 different methods. See the KAPPA/README file for more info. The MC directory has an example script for using LAMMPS as an energy-evaluation engine in a iterative Monte Carlo energy-relaxation loop. The USER directory contains subdirectories of user-provided example scripts for ser packages. See the README files in those directories for more info. See the doc/Section_start.html file for more info about installing and building user packages. The VISCOSITY directory has example scripts for computing the viscosity of a LJ liquid using 4 different methods. See the VISCOSITY/README file for more info. diff --git a/examples/USER/quip/in.gap b/examples/USER/quip/in.gap index 37667e39b..dd049a473 100644 --- a/examples/USER/quip/in.gap +++ b/examples/USER/quip/in.gap @@ -1,22 +1,22 @@ # Test of GAP potential for Si system units metal boundary p p p atom_style atomic read_data data_gap pair_style quip pair_coeff * * gap_example.xml "Potential xml_label=GAP_2015_2_20_0_10_54_35_765" 14 neighbor 0.3 bin neigh_modify delay 10 fix 1 all nve thermo 10 timestep 0.001 -dump 1 all custom 10 dump.gap id fx fy fz +#dump 1 all custom 10 dump.gap id fx fy fz run 40 diff --git a/examples/USER/quip/in.molecular b/examples/USER/quip/in.molecular index 24d21d676..4253399d7 100644 --- a/examples/USER/quip/in.molecular +++ b/examples/USER/quip/in.molecular @@ -1,48 +1,47 @@ units metal atom_style full boundary p p p -processors 1 1 1 timestep 0.0001 # 0.1 fs read_data methane-box-8.data # DISCLAIMER: This potential mixes parameters from methane and silane # potentials and is NOT intended to be a realistic representation of either # system. It is meant to demonstrate the use of hybrid QUIP/LAMMPS potentials, # including the use of separate 'special_bonds' settings. pair_style hybrid/overlay lj/cut 8.0 quip # exclusion setting for quip; cannot be exactly 1.0 1.0 1.0, # since that would not flag 1-2, 1-3, and 1-4 pairs in lj/cut special_bonds lj/coul 0.999999999 0.999999999 0.999999999 # Intermolecular: OPLS (JACS 118 (45), p. 11225 (1996)) # Coulomb interactions ommitted for simplicity pair_coeff 1 1 lj/cut 0.0028619844 3.5 # CT pair_coeff 2 2 lj/cut 0.0013009018 2.5 # HC pair_coeff 1 2 lj/cut 0.0019295487 2.95 pair_modify shift no # change exclusion settings for lj/cut only: exclude bonded pairs pair_modify pair lj/cut special lj/coul 0.0 0.0 0.0 # Intramolecular # Tell QUIP to pretend this is silane (which is covered by the parameter file) -pair_coeff * * quip ip.parms.SW.xml "IP SW" 14 1 +pair_coeff * * quip sw_example.xml "IP SW" 14 1 bond_style none angle_style none fix 1 all nve # Include diagnostics that allow us to compare to a pure QUIP run compute equip all pair quip compute evdw all pair lj/cut compute vir all pressure NULL virial thermo_style custom step epair ke etotal temp press c_vir c_evdw c_equip thermo 1 # dump 1 all custom 1 dump.molecular id type x y z fx fy fz # dump_modify 1 sort id run 10 diff --git a/examples/USER/quip/in.sw b/examples/USER/quip/in.sw index c1367ac80..aaa4217b2 100644 --- a/examples/USER/quip/in.sw +++ b/examples/USER/quip/in.sw @@ -1,22 +1,23 @@ # Test of SW potential for Si system units metal boundary p p p atom_style atomic read_data data_sw pair_style quip pair_coeff * * sw_example.xml "IP SW" 14 +velocity all create 10.0 355311 neighbor 0.3 bin neigh_modify delay 10 fix 1 all nve thermo 10 timestep 0.001 -dump 1 all custom 10 dump.sw id fx fy fz +#dump 1 all custom 10 dump.sw id fx fy fz -run 1 +run 100 diff --git a/examples/USER/quip/log.24Jul17.gap.g++.1 b/examples/USER/quip/log.24Jul17.gap.g++.1 new file mode 100644 index 000000000..348f2ae0c --- /dev/null +++ b/examples/USER/quip/log.24Jul17.gap.g++.1 @@ -0,0 +1,76 @@ +LAMMPS (24 Jul 2017) + using 1 OpenMP thread(s) per MPI task +# Test of GAP potential for Si system + +units metal +boundary p p p + +atom_style atomic + +read_data data_gap + orthogonal box = (0 0 0) to (10.9685 10.9685 10.9685) + 1 by 1 by 1 MPI processor grid + reading atoms ... + 64 atoms + +pair_style quip +pair_coeff * * gap_example.xml "Potential xml_label=GAP_2015_2_20_0_10_54_35_765" 14 + +neighbor 0.3 bin +neigh_modify delay 10 + +fix 1 all nve +thermo 10 +timestep 0.001 + +#dump 1 all custom 10 dump.gap id fx fy fz + +run 40 +Neighbor list info ... + update every 1 steps, delay 10 steps, check yes + max neighbors/atom: 2000, page size: 100000 + master list distance cutoff = 4.3 + ghost atom cutoff = 4.3 + binsize = 2.15, bins = 6 6 6 + 1 neighbor lists, perpetual/occasional/extra = 1 0 0 + (1) pair quip, perpetual + attributes: full, newton on + pair build: full/bin/atomonly + stencil: full/bin/3d + bin: standard +Per MPI rank memory allocation (min/avg/max) = 2.689 | 2.689 | 2.689 Mbytes +Step Temp E_pair E_mol TotEng Press + 0 0 -10412.677 0 -10412.677 -107490.01 + 10 173.98393 -10414.096 0 -10412.679 -91270.969 + 20 417.38493 -10416.08 0 -10412.681 -42816.133 + 30 434.34789 -10416.217 0 -10412.68 2459.83 + 40 423.05899 -10416.124 0 -10412.679 22936.209 +Loop time of 1.83555 on 1 procs for 40 steps with 64 atoms + +Performance: 1.883 ns/day, 12.747 hours/ns, 21.792 timesteps/s +98.1% CPU use with 1 MPI tasks x 1 OpenMP threads + +MPI task timing breakdown: +Section | min time | avg time | max time |%varavg| %total +--------------------------------------------------------------- +Pair | 1.8349 | 1.8349 | 1.8349 | 0.0 | 99.96 +Neigh | 0.00022817 | 0.00022817 | 0.00022817 | 0.0 | 0.01 +Comm | 0.00013709 | 0.00013709 | 0.00013709 | 0.0 | 0.01 +Output | 9.8228e-05 | 9.8228e-05 | 9.8228e-05 | 0.0 | 0.01 +Modify | 8.6308e-05 | 8.6308e-05 | 8.6308e-05 | 0.0 | 0.00 +Other | | 0.0001223 | | | 0.01 + +Nlocal: 64 ave 64 max 64 min +Histogram: 1 0 0 0 0 0 0 0 0 0 +Nghost: 303 ave 303 max 303 min +Histogram: 1 0 0 0 0 0 0 0 0 0 +Neighs: 0 ave 0 max 0 min +Histogram: 1 0 0 0 0 0 0 0 0 0 +FullNghs: 1080 ave 1080 max 1080 min +Histogram: 1 0 0 0 0 0 0 0 0 0 + +Total # of neighbors = 1080 +Ave neighs/atom = 16.875 +Neighbor list builds = 2 +Dangerous builds = 0 +Total wall time: 0:00:01 diff --git a/examples/USER/quip/log.24Jul17.gap.g++.4 b/examples/USER/quip/log.24Jul17.gap.g++.4 new file mode 100644 index 000000000..a8127148b --- /dev/null +++ b/examples/USER/quip/log.24Jul17.gap.g++.4 @@ -0,0 +1,76 @@ +LAMMPS (24 Jul 2017) + using 1 OpenMP thread(s) per MPI task +# Test of GAP potential for Si system + +units metal +boundary p p p + +atom_style atomic + +read_data data_gap + orthogonal box = (0 0 0) to (10.9685 10.9685 10.9685) + 1 by 2 by 2 MPI processor grid + reading atoms ... + 64 atoms + +pair_style quip +pair_coeff * * gap_example.xml "Potential xml_label=GAP_2015_2_20_0_10_54_35_765" 14 + +neighbor 0.3 bin +neigh_modify delay 10 + +fix 1 all nve +thermo 10 +timestep 0.001 + +#dump 1 all custom 10 dump.gap id fx fy fz + +run 40 +Neighbor list info ... + update every 1 steps, delay 10 steps, check yes + max neighbors/atom: 2000, page size: 100000 + master list distance cutoff = 4.3 + ghost atom cutoff = 4.3 + binsize = 2.15, bins = 6 6 6 + 1 neighbor lists, perpetual/occasional/extra = 1 0 0 + (1) pair quip, perpetual + attributes: full, newton on + pair build: full/bin/atomonly + stencil: full/bin/3d + bin: standard +Per MPI rank memory allocation (min/avg/max) = 2.685 | 2.779 | 3.06 Mbytes +Step Temp E_pair E_mol TotEng Press + 0 0 -10412.677 0 -10412.677 -107490.01 + 10 173.98393 -10414.096 0 -10412.679 -91270.969 + 20 417.38493 -10416.08 0 -10412.681 -42816.133 + 30 434.34789 -10416.217 0 -10412.68 2459.83 + 40 423.05899 -10416.124 0 -10412.679 22936.209 +Loop time of 0.837345 on 4 procs for 40 steps with 64 atoms + +Performance: 4.127 ns/day, 5.815 hours/ns, 47.770 timesteps/s +96.0% CPU use with 4 MPI tasks x 1 OpenMP threads + +MPI task timing breakdown: +Section | min time | avg time | max time |%varavg| %total +--------------------------------------------------------------- +Pair | 0.73144 | 0.79214 | 0.83586 | 4.3 | 94.60 +Neigh | 5.7936e-05 | 6.5327e-05 | 7.1049e-05 | 0.0 | 0.01 +Comm | 0.00085807 | 0.044631 | 0.10532 | 18.0 | 5.33 +Output | 0.00013208 | 0.00013494 | 0.00013733 | 0.0 | 0.02 +Modify | 6.0558e-05 | 7.8678e-05 | 9.5129e-05 | 0.0 | 0.01 +Other | | 0.0002971 | | | 0.04 + +Nlocal: 16 ave 18 max 14 min +Histogram: 1 0 1 0 0 0 0 1 0 1 +Nghost: 174 ave 182 max 167 min +Histogram: 1 0 0 0 2 0 0 0 0 1 +Neighs: 0 ave 0 max 0 min +Histogram: 4 0 0 0 0 0 0 0 0 0 +FullNghs: 270 ave 294 max 237 min +Histogram: 1 0 0 0 1 0 0 0 1 1 + +Total # of neighbors = 1080 +Ave neighs/atom = 16.875 +Neighbor list builds = 2 +Dangerous builds = 0 +Total wall time: 0:00:00 diff --git a/examples/USER/quip/log.24Jul17.molecular.g++.1 b/examples/USER/quip/log.24Jul17.molecular.g++.1 new file mode 100644 index 000000000..28fc63579 --- /dev/null +++ b/examples/USER/quip/log.24Jul17.molecular.g++.1 @@ -0,0 +1,130 @@ +LAMMPS (24 Jul 2017) + using 1 OpenMP thread(s) per MPI task +units metal +atom_style full +boundary p p p +timestep 0.0001 # 0.1 fs + +read_data methane-box-8.data + orthogonal box = (-0.499095 -0.270629 0.131683) to (8.4109 8.63937 9.04168) + 1 by 1 by 1 MPI processor grid + reading atoms ... + 40 atoms + scanning bonds ... + 4 = max bonds/atom + scanning angles ... + 6 = max angles/atom + reading bonds ... + 32 bonds + reading angles ... + 48 angles + 4 = max # of 1-2 neighbors + 3 = max # of 1-3 neighbors + 3 = max # of 1-4 neighbors + 4 = max # of special neighbors + +# DISCLAIMER: This potential mixes parameters from methane and silane +# potentials and is NOT intended to be a realistic representation of either +# system. It is meant to demonstrate the use of hybrid QUIP/LAMMPS potentials, +# including the use of separate 'special_bonds' settings. + +pair_style hybrid/overlay lj/cut 8.0 quip + +# exclusion setting for quip; cannot be exactly 1.0 1.0 1.0, +# since that would not flag 1-2, 1-3, and 1-4 pairs in lj/cut +special_bonds lj/coul 0.999999999 0.999999999 0.999999999 + 4 = max # of 1-2 neighbors + 3 = max # of 1-3 neighbors + 3 = max # of 1-4 neighbors + 4 = max # of special neighbors + +# Intermolecular: OPLS (JACS 118 (45), p. 11225 (1996)) +# Coulomb interactions ommitted for simplicity +pair_coeff 1 1 lj/cut 0.0028619844 3.5 # CT +pair_coeff 2 2 lj/cut 0.0013009018 2.5 # HC +pair_coeff 1 2 lj/cut 0.0019295487 2.95 +pair_modify shift no +# change exclusion settings for lj/cut only: exclude bonded pairs +pair_modify pair lj/cut special lj/coul 0.0 0.0 0.0 + +# Intramolecular +# Tell QUIP to pretend this is silane (which is covered by the parameter file) +pair_coeff * * quip sw_example.xml "IP SW" 14 1 +bond_style none +angle_style none + +fix 1 all nve + +# Include diagnostics that allow us to compare to a pure QUIP run +compute equip all pair quip +compute evdw all pair lj/cut +compute vir all pressure NULL virial + +thermo_style custom step epair ke etotal temp press c_vir c_evdw c_equip +thermo 1 + +# dump 1 all custom 1 dump.molecular id type x y z fx fy fz +# dump_modify 1 sort id + +run 10 +Neighbor list info ... + update every 1 steps, delay 10 steps, check yes + max neighbors/atom: 2000, page size: 100000 + master list distance cutoff = 10 + ghost atom cutoff = 10 + binsize = 5, bins = 2 2 2 + 2 neighbor lists, perpetual/occasional/extra = 2 0 0 + (1) pair lj/cut, perpetual, half/full from (2) + attributes: half, newton on + pair build: halffull/newton + stencil: none + bin: none + (2) pair quip, perpetual + attributes: full, newton on + pair build: full/bin + stencil: full/bin/3d + bin: standard +Per MPI rank memory allocation (min/avg/max) = 8.288 | 8.288 | 8.288 Mbytes +Step E_pair KinEng TotEng Temp Press c_vir c_evdw c_equip + 0 -5.3530213 0 -5.3530213 0 518847.56 518847.56 -0.10904079 -5.2439805 + 1 -5.9384459 0.58384822 -5.3545977 115.81657 517370.5 516488.87 -0.10783656 -5.8306093 + 2 -7.669616 2.3104051 -5.3592109 458.30954 512986.36 509497.58 -0.10422283 -7.5653932 + 3 -10.473314 5.1069211 -5.3663924 1013.0477 505833.04 498121.43 -0.098049469 -10.375264 + 4 -14.234705 8.859182 -5.3755227 1757.3747 496127.44 482749.79 -0.089147485 -14.145557 + 5 -18.806851 13.420941 -5.3859098 2662.28 484148.76 463882.72 -0.077305196 -18.729546 + 6 -24.021727 18.625147 -5.3965797 3694.6259 470219.95 442095.39 -0.06194509 -23.959782 + 7 -29.702647 24.295529 -5.4071176 4819.446 454683.57 417996.56 -0.042859727 -29.659787 + 8 -35.67405 30.257258 -5.4167913 6002.0599 437887.03 392197.62 -0.019248651 -35.654801 + 9 -41.771047 36.345757 -5.4252893 7209.8209 420163.51 365280.27 0.0096063065 -41.780653 + 10 -47.845522 42.413161 -5.4323614 8413.3973 401821.91 337776.7 0.044743702 -47.890266 +Loop time of 0.0537777 on 1 procs for 10 steps with 40 atoms + +Performance: 1.607 ns/day, 14.938 hours/ns, 185.951 timesteps/s +90.3% CPU use with 1 MPI tasks x 1 OpenMP threads + +MPI task timing breakdown: +Section | min time | avg time | max time |%varavg| %total +--------------------------------------------------------------- +Pair | 0.053478 | 0.053478 | 0.053478 | 0.0 | 99.44 +Bond | 1.9073e-06 | 1.9073e-06 | 1.9073e-06 | 0.0 | 0.00 +Neigh | 0 | 0 | 0 | 0.0 | 0.00 +Comm | 7.7724e-05 | 7.7724e-05 | 7.7724e-05 | 0.0 | 0.14 +Output | 0.00018263 | 0.00018263 | 0.00018263 | 0.0 | 0.34 +Modify | 1.5974e-05 | 1.5974e-05 | 1.5974e-05 | 0.0 | 0.03 +Other | | 2.122e-05 | | | 0.04 + +Nlocal: 40 ave 40 max 40 min +Histogram: 1 0 0 0 0 0 0 0 0 0 +Nghost: 1175 ave 1175 max 1175 min +Histogram: 1 0 0 0 0 0 0 0 0 0 +Neighs: 4768 ave 4768 max 4768 min +Histogram: 1 0 0 0 0 0 0 0 0 0 +FullNghs: 9536 ave 9536 max 9536 min +Histogram: 1 0 0 0 0 0 0 0 0 0 + +Total # of neighbors = 9536 +Ave neighs/atom = 238.4 +Ave special neighs/atom = 4 +Neighbor list builds = 0 +Dangerous builds = 0 +Total wall time: 0:00:00 diff --git a/examples/USER/quip/log.24Jul17.molecular.g++.4 b/examples/USER/quip/log.24Jul17.molecular.g++.4 new file mode 100644 index 000000000..a8be8e77b --- /dev/null +++ b/examples/USER/quip/log.24Jul17.molecular.g++.4 @@ -0,0 +1,130 @@ +LAMMPS (24 Jul 2017) + using 1 OpenMP thread(s) per MPI task +units metal +atom_style full +boundary p p p +timestep 0.0001 # 0.1 fs + +read_data methane-box-8.data + orthogonal box = (-0.499095 -0.270629 0.131683) to (8.4109 8.63937 9.04168) + 1 by 2 by 2 MPI processor grid + reading atoms ... + 40 atoms + scanning bonds ... + 4 = max bonds/atom + scanning angles ... + 6 = max angles/atom + reading bonds ... + 32 bonds + reading angles ... + 48 angles + 4 = max # of 1-2 neighbors + 3 = max # of 1-3 neighbors + 3 = max # of 1-4 neighbors + 4 = max # of special neighbors + +# DISCLAIMER: This potential mixes parameters from methane and silane +# potentials and is NOT intended to be a realistic representation of either +# system. It is meant to demonstrate the use of hybrid QUIP/LAMMPS potentials, +# including the use of separate 'special_bonds' settings. + +pair_style hybrid/overlay lj/cut 8.0 quip + +# exclusion setting for quip; cannot be exactly 1.0 1.0 1.0, +# since that would not flag 1-2, 1-3, and 1-4 pairs in lj/cut +special_bonds lj/coul 0.999999999 0.999999999 0.999999999 + 4 = max # of 1-2 neighbors + 3 = max # of 1-3 neighbors + 3 = max # of 1-4 neighbors + 4 = max # of special neighbors + +# Intermolecular: OPLS (JACS 118 (45), p. 11225 (1996)) +# Coulomb interactions ommitted for simplicity +pair_coeff 1 1 lj/cut 0.0028619844 3.5 # CT +pair_coeff 2 2 lj/cut 0.0013009018 2.5 # HC +pair_coeff 1 2 lj/cut 0.0019295487 2.95 +pair_modify shift no +# change exclusion settings for lj/cut only: exclude bonded pairs +pair_modify pair lj/cut special lj/coul 0.0 0.0 0.0 + +# Intramolecular +# Tell QUIP to pretend this is silane (which is covered by the parameter file) +pair_coeff * * quip sw_example.xml "IP SW" 14 1 +bond_style none +angle_style none + +fix 1 all nve + +# Include diagnostics that allow us to compare to a pure QUIP run +compute equip all pair quip +compute evdw all pair lj/cut +compute vir all pressure NULL virial + +thermo_style custom step epair ke etotal temp press c_vir c_evdw c_equip +thermo 1 + +# dump 1 all custom 1 dump.molecular id type x y z fx fy fz +# dump_modify 1 sort id + +run 10 +Neighbor list info ... + update every 1 steps, delay 10 steps, check yes + max neighbors/atom: 2000, page size: 100000 + master list distance cutoff = 10 + ghost atom cutoff = 10 + binsize = 5, bins = 2 2 2 + 2 neighbor lists, perpetual/occasional/extra = 2 0 0 + (1) pair lj/cut, perpetual, half/full from (2) + attributes: half, newton on + pair build: halffull/newton + stencil: none + bin: none + (2) pair quip, perpetual + attributes: full, newton on + pair build: full/bin + stencil: full/bin/3d + bin: standard +Per MPI rank memory allocation (min/avg/max) = 8.26 | 8.386 | 8.762 Mbytes +Step E_pair KinEng TotEng Temp Press c_vir c_evdw c_equip + 0 -5.3530213 0 -5.3530213 0 518847.56 518847.56 -0.10904079 -5.2439805 + 1 -5.9384459 0.58384822 -5.3545977 115.81657 517370.5 516488.87 -0.10783656 -5.8306093 + 2 -7.669616 2.3104051 -5.3592109 458.30954 512986.36 509497.58 -0.10422283 -7.5653932 + 3 -10.473314 5.1069211 -5.3663924 1013.0477 505833.04 498121.43 -0.098049469 -10.375264 + 4 -14.234705 8.859182 -5.3755227 1757.3747 496127.44 482749.79 -0.089147485 -14.145557 + 5 -18.806851 13.420941 -5.3859098 2662.28 484148.76 463882.72 -0.077305196 -18.729546 + 6 -24.021727 18.625147 -5.3965797 3694.6259 470219.95 442095.39 -0.06194509 -23.959782 + 7 -29.702647 24.295529 -5.4071176 4819.446 454683.57 417996.56 -0.042859727 -29.659787 + 8 -35.67405 30.257258 -5.4167913 6002.0599 437887.03 392197.62 -0.019248651 -35.654801 + 9 -41.771047 36.345757 -5.4252893 7209.8209 420163.51 365280.27 0.0096063065 -41.780653 + 10 -47.845522 42.413161 -5.4323614 8413.3973 401821.91 337776.7 0.044743702 -47.890266 +Loop time of 0.0506847 on 4 procs for 10 steps with 40 atoms + +Performance: 1.705 ns/day, 14.079 hours/ns, 197.298 timesteps/s +94.4% CPU use with 4 MPI tasks x 1 OpenMP threads + +MPI task timing breakdown: +Section | min time | avg time | max time |%varavg| %total +--------------------------------------------------------------- +Pair | 0.04216 | 0.045656 | 0.049349 | 1.2 | 90.08 +Bond | 1.9073e-06 | 2.4438e-06 | 2.861e-06 | 0.0 | 0.00 +Neigh | 0 | 0 | 0 | 0.0 | 0.00 +Comm | 0.00068545 | 0.004438 | 0.0079191 | 3.9 | 8.76 +Output | 0.00048304 | 0.00053334 | 0.00060964 | 0.0 | 1.05 +Modify | 1.1444e-05 | 1.4424e-05 | 1.9312e-05 | 0.0 | 0.03 +Other | | 4.047e-05 | | | 0.08 + +Nlocal: 10 ave 15 max 6 min +Histogram: 1 0 0 1 1 0 0 0 0 1 +Nghost: 878 ave 948 max 812 min +Histogram: 1 0 1 0 0 0 1 0 0 1 +Neighs: 1192 ave 1764 max 731 min +Histogram: 1 0 0 1 1 0 0 0 0 1 +FullNghs: 2384 ave 3527 max 1439 min +Histogram: 1 0 0 1 1 0 0 0 0 1 + +Total # of neighbors = 9536 +Ave neighs/atom = 238.4 +Ave special neighs/atom = 4 +Neighbor list builds = 0 +Dangerous builds = 0 +Total wall time: 0:00:00 diff --git a/examples/USER/quip/log.24Jul17.sw.g++.1 b/examples/USER/quip/log.24Jul17.sw.g++.1 new file mode 100644 index 000000000..c8115f4cf --- /dev/null +++ b/examples/USER/quip/log.24Jul17.sw.g++.1 @@ -0,0 +1,83 @@ +LAMMPS (24 Jul 2017) + using 1 OpenMP thread(s) per MPI task +# Test of SW potential for Si system + +units metal +boundary p p p + +atom_style atomic + +read_data data_sw + orthogonal box = (0 0 0) to (5.431 5.431 5.431) + 1 by 1 by 1 MPI processor grid + reading atoms ... + 8 atoms + +pair_style quip +pair_coeff * * sw_example.xml "IP SW" 14 + +velocity all create 10.0 355311 +neighbor 0.3 bin +neigh_modify delay 10 + +fix 1 all nve +thermo 10 +timestep 0.001 + +#dump 1 all custom 10 dump.sw id fx fy fz + +run 100 +Neighbor list info ... + update every 1 steps, delay 10 steps, check yes + max neighbors/atom: 2000, page size: 100000 + master list distance cutoff = 4.2258 + ghost atom cutoff = 4.2258 + binsize = 2.1129, bins = 3 3 3 + 1 neighbor lists, perpetual/occasional/extra = 1 0 0 + (1) pair quip, perpetual + attributes: full, newton on + pair build: full/bin/atomonly + stencil: full/bin/3d + bin: standard +Per MPI rank memory allocation (min/avg/max) = 2.684 | 2.684 | 2.684 Mbytes +Step Temp E_pair E_mol TotEng Press + 0 10 -34.68 0 -34.670952 32.206289 + 10 4.5659178 -34.675073 0 -34.670942 46.253731 + 20 1.606683 -34.672391 0 -34.670937 44.736892 + 30 6.7007748 -34.677011 0 -34.670948 16.403049 + 40 5.682757 -34.676087 0 -34.670945 18.696408 + 50 2.2140716 -34.672942 0 -34.670939 37.592282 + 60 5.0475382 -34.675512 0 -34.670944 37.331666 + 70 7.0990979 -34.677369 0 -34.670946 40.533757 + 80 5.7306189 -34.676128 0 -34.670943 47.748813 + 90 5.0895648 -34.675549 0 -34.670944 38.092721 + 100 4.1070919 -34.674659 0 -34.670943 28.737864 +Loop time of 0.384233 on 1 procs for 100 steps with 8 atoms + +Performance: 22.486 ns/day, 1.067 hours/ns, 260.259 timesteps/s +94.6% CPU use with 1 MPI tasks x 1 OpenMP threads + +MPI task timing breakdown: +Section | min time | avg time | max time |%varavg| %total +--------------------------------------------------------------- +Pair | 0.38365 | 0.38365 | 0.38365 | 0.0 | 99.85 +Neigh | 0 | 0 | 0 | 0.0 | 0.00 +Comm | 0.00017333 | 0.00017333 | 0.00017333 | 0.0 | 0.05 +Output | 0.00014162 | 0.00014162 | 0.00014162 | 0.0 | 0.04 +Modify | 7.081e-05 | 7.081e-05 | 7.081e-05 | 0.0 | 0.02 +Other | | 0.0001957 | | | 0.05 + +Nlocal: 8 ave 8 max 8 min +Histogram: 1 0 0 0 0 0 0 0 0 0 +Nghost: 162 ave 162 max 162 min +Histogram: 1 0 0 0 0 0 0 0 0 0 +Neighs: 0 ave 0 max 0 min +Histogram: 1 0 0 0 0 0 0 0 0 0 +FullNghs: 128 ave 128 max 128 min +Histogram: 1 0 0 0 0 0 0 0 0 0 + +Total # of neighbors = 128 +Ave neighs/atom = 16 +Neighbor list builds = 0 +Dangerous builds = 0 +Total wall time: 0:00:00 diff --git a/examples/USER/quip/log.24Jul17.sw.g++.4 b/examples/USER/quip/log.24Jul17.sw.g++.4 new file mode 100644 index 000000000..d7306c705 --- /dev/null +++ b/examples/USER/quip/log.24Jul17.sw.g++.4 @@ -0,0 +1,83 @@ +LAMMPS (24 Jul 2017) + using 1 OpenMP thread(s) per MPI task +# Test of SW potential for Si system + +units metal +boundary p p p + +atom_style atomic + +read_data data_sw + orthogonal box = (0 0 0) to (5.431 5.431 5.431) + 1 by 2 by 2 MPI processor grid + reading atoms ... + 8 atoms + +pair_style quip +pair_coeff * * sw_example.xml "IP SW" 14 + +velocity all create 10.0 355311 +neighbor 0.3 bin +neigh_modify delay 10 + +fix 1 all nve +thermo 10 +timestep 0.001 + +#dump 1 all custom 10 dump.sw id fx fy fz + +run 100 +Neighbor list info ... + update every 1 steps, delay 10 steps, check yes + max neighbors/atom: 2000, page size: 100000 + master list distance cutoff = 4.2258 + ghost atom cutoff = 4.2258 + binsize = 2.1129, bins = 3 3 3 + 1 neighbor lists, perpetual/occasional/extra = 1 0 0 + (1) pair quip, perpetual + attributes: full, newton on + pair build: full/bin/atomonly + stencil: full/bin/3d + bin: standard +Per MPI rank memory allocation (min/avg/max) = 2.698 | 2.698 | 2.698 Mbytes +Step Temp E_pair E_mol TotEng Press + 0 10 -34.68 0 -34.670952 32.206289 + 10 4.5659178 -34.675073 0 -34.670942 46.253731 + 20 1.606683 -34.672391 0 -34.670937 44.736892 + 30 6.7007748 -34.677011 0 -34.670948 16.403049 + 40 5.682757 -34.676087 0 -34.670945 18.696408 + 50 2.2140716 -34.672942 0 -34.670939 37.592282 + 60 5.0475382 -34.675512 0 -34.670944 37.331666 + 70 7.0990979 -34.677369 0 -34.670946 40.533757 + 80 5.7306189 -34.676128 0 -34.670943 47.748813 + 90 5.0895648 -34.675549 0 -34.670944 38.092721 + 100 4.1070919 -34.674659 0 -34.670943 28.737864 +Loop time of 0.423803 on 4 procs for 100 steps with 8 atoms + +Performance: 20.387 ns/day, 1.177 hours/ns, 235.959 timesteps/s +90.6% CPU use with 4 MPI tasks x 1 OpenMP threads + +MPI task timing breakdown: +Section | min time | avg time | max time |%varavg| %total +--------------------------------------------------------------- +Pair | 0.39332 | 0.40011 | 0.40704 | 0.8 | 94.41 +Neigh | 0 | 0 | 0 | 0.0 | 0.00 +Comm | 0.015632 | 0.022605 | 0.029425 | 3.3 | 5.33 +Output | 0.00025702 | 0.00028491 | 0.00035429 | 0.0 | 0.07 +Modify | 7.3671e-05 | 8.1897e-05 | 8.9884e-05 | 0.0 | 0.02 +Other | | 0.0007259 | | | 0.17 + +Nlocal: 2 ave 2 max 2 min +Histogram: 4 0 0 0 0 0 0 0 0 0 +Nghost: 113 ave 113 max 113 min +Histogram: 4 0 0 0 0 0 0 0 0 0 +Neighs: 0 ave 0 max 0 min +Histogram: 4 0 0 0 0 0 0 0 0 0 +FullNghs: 32 ave 32 max 32 min +Histogram: 4 0 0 0 0 0 0 0 0 0 + +Total # of neighbors = 128 +Ave neighs/atom = 16 +Neighbor list builds = 0 +Dangerous builds = 0 +Total wall time: 0:00:00 diff --git a/lib/.gitignore b/lib/.gitignore index e153da2c3..cbeae7705 100644 --- a/lib/.gitignore +++ b/lib/.gitignore @@ -1 +1,2 @@ Makefile.lammps +.depend diff --git a/lib/Install.py b/lib/Install.py index 18b426f92..6b9025433 100644 --- a/lib/Install.py +++ b/lib/Install.py @@ -1,82 +1,92 @@ #!/usr/bin/env python # install.py tool to do a generic build of a library # soft linked to by many of the lib/Install.py files # used to automate the steps described in the corresponding lib/README -import sys,commands,os +from __future__ import print_function +import sys,os,subprocess # help message help = """ -Syntax: python Install.py -m machine -e suffix - specify -m and optionally -e, order does not matter +Syntax from src dir: make lib-libname args="-m machine -e suffix" +Syntax from lib dir: python Install.py -m machine -e suffix + +libname = name of lib dir (e.g. atc, h5md, meam, poems, etc) +specify -m and optionally -e, order does not matter + -m = peform a clean followed by "make -f Makefile.machine" machine = suffix of a lib/Makefile.* file -e = set EXTRAMAKE variable in Makefile.machine to Makefile.lammps.suffix does not alter existing Makefile.machine + +Examples: + +make lib-poems args="-m g++" # build COLVARS lib with GNU g++ compiler +make lib-meam args="-m ifort" # build MEAM lib with Intel ifort compiler """ # print error message or help def error(str=None): - if not str: print help - else: print "ERROR",str + if not str: print(help) + else: print("ERROR",str) sys.exit() # parse args args = sys.argv[1:] nargs = len(args) if nargs == 0: error() machine = None extraflag = 0 iarg = 0 while iarg < nargs: if args[iarg] == "-m": if iarg+2 > nargs: error() machine = args[iarg+1] - iarg += 2 + iarg += 2 elif args[iarg] == "-e": if iarg+2 > nargs: error() extraflag = 1 suffix = args[iarg+1] - iarg += 2 + iarg += 2 else: error() # set lib from working dir cwd = os.getcwd() lib = os.path.basename(cwd) # create Makefile.auto as copy of Makefile.machine # reset EXTRAMAKE if requested - + if not os.path.exists("Makefile.%s" % machine): error("lib/%s/Makefile.%s does not exist" % (lib,machine)) lines = open("Makefile.%s" % machine,'r').readlines() fp = open("Makefile.auto",'w') for line in lines: words = line.split() if len(words) == 3 and extraflag and \ words[0] == "EXTRAMAKE" and words[1] == '=': line = line.replace(words[2],"Makefile.lammps.%s" % suffix) print >>fp,line, fp.close() # make the library via Makefile.auto -print "Building lib%s.a ..." % lib +print("Building lib%s.a ..." % lib) cmd = "make -f Makefile.auto clean; make -f Makefile.auto" -txt = commands.getoutput(cmd) -print txt +txt = subprocess.check_output(cmd,shell=True,stderr=subprocess.STDOUT) +print(txt) -if os.path.exists("lib%s.a" % lib): print "Build was successful" +if os.path.exists("lib%s.a" % lib): print("Build was successful") else: error("Build of lib/%s/lib%s.a was NOT successful" % (lib,lib)) if not os.path.exists("Makefile.lammps"): - print "lib/%s/Makefile.lammps was NOT created" % lib + print("lib/%s/Makefile.lammps was NOT created" % lib) diff --git a/lib/atc/Install.py b/lib/atc/Install.py index 37041d2ea..ffe709d44 120000 --- a/lib/atc/Install.py +++ b/lib/atc/Install.py @@ -1 +1 @@ -Install.py \ No newline at end of file +../Install.py \ No newline at end of file diff --git a/lib/atc/Makefile.g++ b/lib/atc/Makefile.g++ index d15e6cb3b..bb3028392 100644 --- a/lib/atc/Makefile.g++ +++ b/lib/atc/Makefile.g++ @@ -1,51 +1,57 @@ +# library build -*- makefile -*- SHELL = /bin/sh # which file will be copied to Makefile.lammps EXTRAMAKE = Makefile.lammps.installed # ------ FILES ------ + SRC = $(wildcard *.cpp) INC = $(wildcard *.h) # ------ DEFINITIONS ------ LIB = libatc.a OBJ = $(SRC:.cpp=.o) # ------ SETTINGS ------ # include any MPI settings needed for the ATC library to build with # must be the same MPI library that LAMMPS is built with CC = g++ CCFLAGS = -O -g -fPIC -I../../src -DMPICH_IGNORE_CXX_SEEK ARCHIVE = ar ARCHFLAG = -rc DEPFLAGS = -M LINK = g++ LINKFLAGS = -O USRLIB = SYSLIB = # ------ MAKE PROCEDURE ------ lib: $(OBJ) $(ARCHIVE) $(ARFLAGS) $(LIB) $(OBJ) @cp $(EXTRAMAKE) Makefile.lammps # ------ COMPILE RULES ------ %.o:%.cpp $(CC) $(CCFLAGS) -c $< %.d:%.cpp $(CC) $(CCFLAGS) $(DEPFLAGS) $< > $@ # ------ DEPENDENCIES ------ DEPENDS = $(OBJ:.o=.d) # ------ CLEAN ------ +.PHONY: clean lib + clean: -rm *.o *.d *~ $(LIB) + +sinclude $(DEPENDS) diff --git a/lib/atc/Makefile.lammps b/lib/atc/Makefile.lammps deleted file mode 100644 index c8cd66af2..000000000 --- a/lib/atc/Makefile.lammps +++ /dev/null @@ -1,5 +0,0 @@ -# Settings that the LAMMPS build will import when this package library is used - -user-atc_SYSINC = -user-atc_SYSLIB = -lblas -llapack -user-atc_SYSPATH = diff --git a/lib/atc/Makefile.mingw32-cross b/lib/atc/Makefile.mingw32-cross deleted file mode 100644 index 8b3354098..000000000 --- a/lib/atc/Makefile.mingw32-cross +++ /dev/null @@ -1,67 +0,0 @@ -# library build -*- makefile -*- -SHELL = /bin/sh - -# which file will be copied to Makefile.lammps -EXTRAMAKE = Makefile.lammps.linalg - -# ------ FILES ------ - -SRC = $(wildcard *.cpp) -INC = $(wildcard *.h) - -# ------ DEFINITIONS ------ - -DIR = Obj_mingw32/ -LIB = $(DIR)libatc.a -OBJ = $(SRC:%.cpp=$(DIR)%.o) - -# ------ SETTINGS ------ - -# include any MPI settings needed for the ATC library to build with -# the same MPI library that LAMMPS is built with - -CC = i686-w64-mingw32-g++ -CCFLAGS = -I../../src -I../../src/STUBS -DMPICH_IGNORE_CXX_SEEK \ - -O3 -march=i686 -mtune=generic -mfpmath=387 -mpc64 \ - -ffast-math -funroll-loops -fstrict-aliasing \ - -DLAMMPS_SMALLSMALL -Wno-uninitialized -ARCHIVE = i686-w64-mingw32-ar -ARCHFLAG = -rcs -DEPFLAGS = -M -LINK = $(CC) -LINKFLAGS = -O -USRLIB = -SYSLIB = - -# ------ MAKE PROCEDURE ------ - -default: $(DIR) $(LIB) Makefile.lammps - -$(DIR): - mkdir $(DIR) - -Makefile.lammps: - @cp $(EXTRAMAKE) Makefile.lammps - -$(LIB): $(OBJ) - $(ARCHIVE) $(ARFLAGS) $(LIB) $(OBJ) - @cp $(EXTRAMAKE) Makefile.lammps - -# ------ COMPILE RULES ------ - -$(DIR)%.o:%.cpp - $(CC) $(CCFLAGS) -c $< -o $@ -$(DIR)%.d:%.cpp - $(CC) $(CCFLAGS) $(DEPFLAGS) $< > $@ - -# ------ DEPENDENCIES ------ - -DEPENDS = $(OBJ:.o=.d) - -# ------ CLEAN ------ - -clean: - -rm $(DIR)*.o $(DIR)*.d *~ $(LIB) - -$(DEPENDS) : $(DIR) -sinclude $(DEPENDS) diff --git a/lib/atc/Makefile.mingw32-cross-mpi b/lib/atc/Makefile.mingw32-cross-mpi deleted file mode 100644 index c5feeca81..000000000 --- a/lib/atc/Makefile.mingw32-cross-mpi +++ /dev/null @@ -1,68 +0,0 @@ -# library build -*- makefile -*- -SHELL = /bin/sh - -# which file will be copied to Makefile.lammps -EXTRAMAKE = Makefile.lammps.linalg - -# ------ FILES ------ - -SRC = $(wildcard *.cpp) -INC = $(wildcard *.h) - -# ------ DEFINITIONS ------ - -DIR = Obj_mingw32-mpi/ -LIB = $(DIR)libatc.a -OBJ = $(SRC:%.cpp=$(DIR)%.o) - -# ------ SETTINGS ------ - -# include any MPI settings needed for the ATC library to build with -# the same MPI library that LAMMPS is built with - -CC = i686-w64-mingw32-g++ -CCFLAGS = -I../../tools/mingw-cross/mpich2-win32/include/ \ - -I../../src -DMPICH_IGNORE_CXX_SEEK \ - -O3 -march=i686 -mtune=generic -mfpmath=387 -mpc64 \ - -ffast-math -funroll-loops -fstrict-aliasing \ - -DLAMMPS_SMALLSMALL -Wno-uninitialized -ARCHIVE = i686-w64-mingw32-ar -ARCHFLAG = -rcs -DEPFLAGS = -M -LINK = $(CC) -LINKFLAGS = -O -USRLIB = -SYSLIB = - -# ------ MAKE PROCEDURE ------ - -default: $(DIR) $(LIB) Makefile.lammps - -$(DIR): - mkdir $(DIR) - -Makefile.lammps: - @cp $(EXTRAMAKE) Makefile.lammps - -$(LIB): $(OBJ) - $(ARCHIVE) $(ARFLAGS) $(LIB) $(OBJ) - @cp $(EXTRAMAKE) Makefile.lammps - -# ------ COMPILE RULES ------ - -$(DIR)%.o:%.cpp - $(CC) $(CCFLAGS) -c $< -o $@ -$(DIR)%.d:%.cpp - $(CC) $(CCFLAGS) $(DEPFLAGS) $< > $@ - -# ------ DEPENDENCIES ------ - -DEPENDS = $(OBJ:.o=.d) - -# ------ CLEAN ------ - -clean: - -rm $(DIR)*.o $(DIR)*.d *~ $(LIB) - -$(DEPENDS) : $(DIR) -sinclude $(DEPENDS) diff --git a/lib/atc/Makefile.mingw64-cross b/lib/atc/Makefile.mingw64-cross deleted file mode 100644 index fbd3a0261..000000000 --- a/lib/atc/Makefile.mingw64-cross +++ /dev/null @@ -1,67 +0,0 @@ -# library build -*- makefile -*- -SHELL = /bin/sh - -# which file will be copied to Makefile.lammps -EXTRAMAKE = Makefile.lammps.linalg - -# ------ FILES ------ - -SRC = $(wildcard *.cpp) -INC = $(wildcard *.h) - -# ------ DEFINITIONS ------ - -DIR = Obj_mingw64/ -LIB = $(DIR)libatc.a -OBJ = $(SRC:%.cpp=$(DIR)%.o) - -# ------ SETTINGS ------ - -# include any MPI settings needed for the ATC library to build with -# the same MPI library that LAMMPS is built with - -CC = x86_64-w64-mingw32-g++ -CCFLAGS = -I../../src -I../../src/STUBS -DMPICH_IGNORE_CXX_SEEK \ - -O3 -march=core2 -mtune=core2 -mpc64 -msse2 \ - -ffast-math -funroll-loops -fstrict-aliasing \ - -DLAMMPS_SMALLBIG -Wno-uninitialized -ARCHIVE = x86_64-w64-mingw32-ar -ARCHFLAG = -rcs -DEPFLAGS = -M -LINK = $(CC) -LINKFLAGS = -O -USRLIB = -SYSLIB = - -# ------ MAKE PROCEDURE ------ - -default: $(DIR) $(LIB) Makefile.lammps - -$(DIR): - mkdir $(DIR) - -Makefile.lammps: - @cp $(EXTRAMAKE) Makefile.lammps - -$(LIB): $(OBJ) - $(ARCHIVE) $(ARFLAGS) $(LIB) $(OBJ) - @cp $(EXTRAMAKE) Makefile.lammps - -# ------ COMPILE RULES ------ - -$(DIR)%.o:%.cpp - $(CC) $(CCFLAGS) -c $< -o $@ -$(DIR)%.d:%.cpp - $(CC) $(CCFLAGS) $(DEPFLAGS) $< > $@ - -# ------ DEPENDENCIES ------ - -DEPENDS = $(OBJ:.o=.d) - -# ------ CLEAN ------ - -clean: - -rm $(DIR)*.o $(DIR)*.d *~ $(LIB) - -$(DEPENDS) : $(DIR) -sinclude $(DEPENDS) diff --git a/lib/atc/Makefile.mingw64-cross-mpi b/lib/atc/Makefile.mingw64-cross-mpi deleted file mode 100644 index f8dd64eae..000000000 --- a/lib/atc/Makefile.mingw64-cross-mpi +++ /dev/null @@ -1,68 +0,0 @@ -# library build -*- makefile -*- -SHELL = /bin/sh - -# which file will be copied to Makefile.lammps -EXTRAMAKE = Makefile.lammps.linalg - -# ------ FILES ------ - -SRC = $(wildcard *.cpp) -INC = $(wildcard *.h) - -# ------ DEFINITIONS ------ - -DIR = Obj_mingw64-mpi/ -LIB = $(DIR)libatc.a -OBJ = $(SRC:%.cpp=$(DIR)%.o) - -# ------ SETTINGS ------ - -# include any MPI settings needed for the ATC library to build with -# the same MPI library that LAMMPS is built with - -CC = x86_64-w64-mingw32-g++ -CCFLAGS = -I../../tools/mingw-cross/mpich2-win64/include/ \ - -I../../src -DMPICH_IGNORE_CXX_SEEK \ - -O3 -march=core2 -mtune=core2 -mpc64 -msse2 \ - -ffast-math -funroll-loops -fstrict-aliasing \ - -DLAMMPS_SMALLBIG -Wno-uninitialized -ARCHIVE = x86_64-w64-mingw32-ar -ARCHFLAG = -rcs -DEPFLAGS = -M -LINK = $(CC) -LINKFLAGS = -O -USRLIB = -SYSLIB = - -# ------ MAKE PROCEDURE ------ - -default: $(DIR) $(LIB) Makefile.lammps - -$(DIR): - mkdir $(DIR) - -Makefile.lammps: - @cp $(EXTRAMAKE) Makefile.lammps - -$(LIB): $(OBJ) - $(ARCHIVE) $(ARFLAGS) $(LIB) $(OBJ) - @cp $(EXTRAMAKE) Makefile.lammps - -# ------ COMPILE RULES ------ - -$(DIR)%.o:%.cpp - $(CC) $(CCFLAGS) -c $< -o $@ -$(DIR)%.d:%.cpp - $(CC) $(CCFLAGS) $(DEPFLAGS) $< > $@ - -# ------ DEPENDENCIES ------ - -DEPENDS = $(OBJ:.o=.d) - -# ------ CLEAN ------ - -clean: - -rm $(DIR)*.o $(DIR)*.d *~ $(LIB) - -$(DEPENDS) : $(DIR) -sinclude $(DEPENDS) diff --git a/lib/atc/Makefile.mpic++ b/lib/atc/Makefile.mpi similarity index 59% rename from lib/atc/Makefile.mpic++ rename to lib/atc/Makefile.mpi index c9dfdb79c..ec941efdc 100644 --- a/lib/atc/Makefile.mpic++ +++ b/lib/atc/Makefile.mpi @@ -1,39 +1,55 @@ # library build -*- makefile -*- SHELL = /bin/sh # which file will be copied to Makefile.lammps -EXTRAMAKE = Makefile.lammps.installed +EXTRAMAKE = Makefile.lammps.linalg + # ------ FILES ------ + SRC = $(wildcard *.cpp) INC = $(wildcard *.h) + # ------ DEFINITIONS ------ + LIB = libatc.a OBJ = $(SRC:.cpp=.o) + +default: lib + # ------ SETTINGS ------ +.PHONY: clean lib depend + # include any MPI settings needed for the ATC library to build with # must be the same MPI library that LAMMPS is built with -CC = mpic++ -CCFLAGS = -O3 -Wall -g -I../../src -fPIC -DMPICH_IGNORE_CXX_SEEK -DOMPI_SKIP_MPICXX=1 +CC = mpicxx +CCFLAGS = -O3 -Wall -g -fPIC +CPPFLAGS = -I../../src -DMPICH_IGNORE_CXX_SEEK -DOMPI_SKIP_MPICXX=1 ARCHIVE = ar ARCHFLAG = -rc -DEPFLAGS = -M -LINK = $(CC) -LINKFLAGS = -O # ------ MAKE PROCEDURE ------ + lib: $(OBJ) $(ARCHIVE) $(ARFLAGS) $(LIB) $(OBJ) @cp $(EXTRAMAKE) Makefile.lammps + # ------ COMPILE RULES ------ + %.o:%.cpp - $(CC) $(CCFLAGS) -c $< -%.d:%.cpp - $(CC) $(CCFLAGS) $(DEPFLAGS) $< > $@ + $(CC) $(CPPFLAGS) $(CCFLAGS) -c $< + # ------ DEPENDENCIES ------ -DEPENDS = $(OBJ:.o=.d) + +depend .depend : fastdep.exe $(SRC) + @./fastdep.exe $(INCFLAGS) -- $^ > .depend || exit 1 + +fastdep.exe: ../../src/DEPEND/fastdep.c + @cc -O -o $@ $< + # ------ CLEAN ------ + clean: - -rm *.o *.d *~ $(LIB) + -rm -f *.o *~ .depend $(LIB) fastdep.exe sinclude $(DEPENDS) diff --git a/lib/atc/Makefile.serial b/lib/atc/Makefile.serial index 44ce5fd34..70b786a6b 100644 --- a/lib/atc/Makefile.serial +++ b/lib/atc/Makefile.serial @@ -1,51 +1,55 @@ # library build -*- makefile -*- SHELL = /bin/sh # which file will be copied to Makefile.lammps EXTRAMAKE = Makefile.lammps.linalg # ------ FILES ------ SRC = $(wildcard *.cpp) INC = $(wildcard *.h) # ------ DEFINITIONS ------ LIB = libatc.a OBJ = $(SRC:.cpp=.o) +default: lib + # ------ SETTINGS ------ +.PHONY: clean lib depend + # include any MPI settings needed for the ATC library to build with # must be the same MPI library that LAMMPS is built with CC = g++ -CCFLAGS = -O -g -fPIC -I../../src -I../../src/STUBS +CCFLAGS = -O3 -g -fPIC +CPPFLAGS = -I../../src -I../../src/STUBS ARCHIVE = ar ARCHFLAG = -rc -DEPFLAGS = -M -LINK = $(CC) -LINKFLAGS = -O # ------ MAKE PROCEDURE ------ lib: $(OBJ) $(ARCHIVE) $(ARFLAGS) $(LIB) $(OBJ) @cp $(EXTRAMAKE) Makefile.lammps # ------ COMPILE RULES ------ %.o:%.cpp - $(CC) $(CCFLAGS) -c $< -%.d:%.cpp - $(CC) $(CCFLAGS) $(DEPFLAGS) $< > $@ + $(CC) $(CPPFLAGS) $(CCFLAGS) -c $< # ------ DEPENDENCIES ------ -DEPENDS = $(OBJ:.o=.d) +depend .depend : fastdep.exe $(SRC) + @./fastdep.exe $(INCFLAGS) -- $^ > .depend || exit 1 + +fastdep.exe: ../../src/DEPEND/fastdep.c + @cc -O -o $@ $< # ------ CLEAN ------ clean: - -rm *.o *.d *~ $(LIB) + -rm -f *.o *~ .depend $(LIB) fastdep.exe -sinclude $(DEPENDS) +sinclude .depend diff --git a/lib/awpmd/Install.py b/lib/awpmd/Install.py index 37041d2ea..ffe709d44 120000 --- a/lib/awpmd/Install.py +++ b/lib/awpmd/Install.py @@ -1 +1 @@ -Install.py \ No newline at end of file +../Install.py \ No newline at end of file diff --git a/lib/awpmd/Makefile.mingw32-cross b/lib/awpmd/Makefile.mingw32-cross deleted file mode 100644 index 6a9398717..000000000 --- a/lib/awpmd/Makefile.mingw32-cross +++ /dev/null @@ -1,80 +0,0 @@ -# library build -*- makefile -*- -SHELL = /bin/sh - -# which file will be copied to Makefile.lammps - -EXTRAMAKE = Makefile.lammps.linalg - -# ------ FILES ------ - -SRC = logexc.cpp wpmd.cpp wpmd_split.cpp -vpath %.cpp ivutils/src -vpath %.cpp systems/interact/TCP - -INC = \ - cerf.h \ - cerf2.h \ - cerf_octave.h \ - cvector_3.h \ - lapack_inter.h \ - logexc.h \ - pairhash.h \ - refobj.h \ - tcpdefs.h \ - vector_3.h \ - wavepacket.h \ - wpmd.h \ - wpmd_split.h - -# ------ DEFINITIONS ------ -DIR = Obj_mingw32/ -LIB = $(DIR)libawpmd.a -OBJ = $(SRC:%.cpp=$(DIR)%.o) - -# ------ SETTINGS ------ - -# include any MPI settings needed for the ATC library to build with -# the same MPI library that LAMMPS is built with - -CC = i686-w64-mingw32-g++ -CCFLAGS = -O2 -march=i686 -mtune=generic -mfpmath=387 -mpc64 \ - -finline-functions \ - -ffast-math -funroll-loops -fstrict-aliasing \ - -Wall -W -Wno-uninitialized -Isystems/interact/TCP/ -Isystems/interact -Iivutils/include -ARCHIVE = i686-w64-mingw32-ar -ARCHFLAG = -rscv -DEPFLAGS = -M -#LINK = -#LINKFLAGS = -USRLIB = -SYSLIB = - -# ------ MAKE PROCEDURE ------ - -default: $(DIR) $(LIB) Makefile.lammps - -$(DIR): - mkdir $(DIR) - -Makefile.lammps: - @cp $(EXTRAMAKE) Makefile.lammps - -$(LIB): $(OBJ) - $(ARCHIVE) $(ARFLAGS) $(LIB) $(OBJ) - @cp $(EXTRAMAKE) Makefile.lammps - -# ------ COMPILE RULES ------ - -$(DIR)%.o:%.cpp - $(CC) $(CCFLAGS) -c $< -o $@ -$(DIR)%.d:%.cpp - $(CC) $(CCFLAGS) $(DEPFLAGS) $< > $@ - -# ------ DEPENDENCIES ------ - -DEPENDS = $(OBJ:.o=.d) - -# ------ CLEAN ------ - -clean: - -rm *.d *~ $(OBJ) $(LIB) diff --git a/lib/awpmd/Makefile.mingw32-cross-mpi b/lib/awpmd/Makefile.mingw32-cross-mpi deleted file mode 100644 index cc2a76111..000000000 --- a/lib/awpmd/Makefile.mingw32-cross-mpi +++ /dev/null @@ -1,13 +0,0 @@ -# -*- makefile -*- wrapper for non-MPI libraries - -SHELL=/bin/sh - -all: - $(MAKE) $(MFLAGS) mingw32-cross - rm -f Obj_mingw32-mpi - ln -s Obj_mingw32 Obj_mingw32-mpi - -clean: - $(MAKE) $(MFLAGS) clean-mingw32-cross - rm -f Obj_mingw32-mpi - diff --git a/lib/awpmd/Makefile.mingw64-cross b/lib/awpmd/Makefile.mingw64-cross deleted file mode 100644 index 1f3e60812..000000000 --- a/lib/awpmd/Makefile.mingw64-cross +++ /dev/null @@ -1,79 +0,0 @@ -# library build -*- makefile -*- -SHELL = /bin/sh - -# which file will be copied to Makefile.lammps - -EXTRAMAKE = Makefile.lammps.linalg - -# ------ FILES ------ - -SRC = logexc.cpp wpmd.cpp wpmd_split.cpp -vpath %.cpp ivutils/src -vpath %.cpp systems/interact/TCP - -INC = \ - cerf.h \ - cerf2.h \ - cerf_octave.h \ - cvector_3.h \ - lapack_inter.h \ - logexc.h \ - pairhash.h \ - refobj.h \ - tcpdefs.h \ - vector_3.h \ - wavepacket.h \ - wpmd.h \ - wpmd_split.h - -# ------ DEFINITIONS ------ -DIR = Obj_mingw64/ -LIB = $(DIR)libawpmd.a -OBJ = $(SRC:%.cpp=$(DIR)%.o) - -# ------ SETTINGS ------ - -# include any MPI settings needed for the ATC library to build with -# the same MPI library that LAMMPS is built with - -CC = x86_64-w64-mingw32-g++ -CCFLAGS = -O3 -march=core2 -mtune=core2 -mpc64 -msse2 \ - -ffast-math -funroll-loops -fstrict-aliasing \ - -Wall -W -Wno-uninitialized -Isystems/interact/TCP/ -Isystems/interact -Iivutils/include -ARCHIVE = x86_64-w64-mingw32-ar -ARCHFLAG = -rscv -DEPFLAGS = -M -#LINK = -#LINKFLAGS = -USRLIB = -SYSLIB = - -# ------ MAKE PROCEDURE ------ - -default: $(DIR) $(LIB) Makefile.lammps - -$(DIR): - mkdir $(DIR) - -Makefile.lammps: - @cp $(EXTRAMAKE) Makefile.lammps - -$(LIB): $(OBJ) - $(ARCHIVE) $(ARFLAGS) $(LIB) $(OBJ) - @cp $(EXTRAMAKE) Makefile.lammps - -# ------ COMPILE RULES ------ - -$(DIR)%.o:%.cpp - $(CC) $(CCFLAGS) -c $< -o $@ -$(DIR)%.d:%.cpp - $(CC) $(CCFLAGS) $(DEPFLAGS) $< > $@ - -# ------ DEPENDENCIES ------ - -DEPENDS = $(OBJ:.o=.d) - -# ------ CLEAN ------ - -clean: - -rm *.d *~ $(OBJ) $(LIB) diff --git a/lib/awpmd/Makefile.mingw64-cross-mpi b/lib/awpmd/Makefile.mingw64-cross-mpi deleted file mode 100644 index 1ec1a0995..000000000 --- a/lib/awpmd/Makefile.mingw64-cross-mpi +++ /dev/null @@ -1,13 +0,0 @@ -# -*- makefile -*- wrapper for non-MPI libraries - -SHELL=/bin/sh - -all: - $(MAKE) $(MFLAGS) mingw64-cross - rm -f Obj_mingw64-mpi - ln -s Obj_mingw64 Obj_mingw64-mpi - -clean: - $(MAKE) $(MFLAGS) clean-mingw64-cross - rm -f Obj_mingw64-mpi - diff --git a/lib/colvars/Install.py b/lib/colvars/Install.py index af658fa26..2fc207710 100644 --- a/lib/colvars/Install.py +++ b/lib/colvars/Install.py @@ -1,142 +1,142 @@ #!/usr/bin/env python # Install.py tool to do automate build of Colvars from __future__ import print_function import sys,os,subprocess # help message help = """ Syntax from src dir: make lib-colvars args="-m machine -e suffix" Syntax from lib/colvars dir: python Install.py -m machine -e suffix specify -m and optionally -e, order does not matter -m = peform a clean followed by "make -f Makefile.machine" machine = suffix of a lib/colvars/Makefile.* or of a src/MAKE/MACHINES/Makefile.* file -e = set EXTRAMAKE variable in Makefile.machine to Makefile.lammps.suffix does not alter existing Makefile.machine Examples: make lib-colvars args="-m g++" # build COLVARS lib with GNU g++ compiler """ # print error message or help def error(str=None): if not str: print(help) - else: print("ERROR"),str + else: print("ERROR",str) sys.exit() # parse args args = sys.argv[1:] nargs = len(args) if nargs == 0: error() machine = None extraflag = False iarg = 0 while iarg < nargs: if args[iarg] == "-m": if iarg+2 > len(args): error() machine = args[iarg+1] iarg += 2 elif args[iarg] == "-e": if iarg+2 > len(args): error() extraflag = True suffix = args[iarg+1] iarg += 2 else: error() # set lib from working dir cwd = os.getcwd() lib = os.path.basename(cwd) def get_lammps_machine_flags(machine): """Parse Makefile.machine from LAMMPS, return dictionary of compiler flags""" if not os.path.exists("../../src/MAKE/MACHINES/Makefile.%s" % machine): error("Cannot locate src/MAKE/MACHINES/Makefile.%s" % machine) lines = open("../../src/MAKE/MACHINES/Makefile.%s" % machine, 'r').readlines() machine_flags = {} for line in lines: line = line.partition('#')[0] line = line.rstrip() words = line.split() if (len(words) > 2): if ((words[0] == 'CC') or (words[0] == 'CCFLAGS') or (words[0] == 'SHFLAGS') or (words[0] == 'ARCHIVE') or (words[0] == 'ARFLAGS') or (words[0] == 'SHELL')): machine_flags[words[0]] = ' '.join(words[2:]) return machine_flags def gen_colvars_makefile_machine(machine, machine_flags): """Generate Makefile.machine for Colvars given the compiler flags""" machine_makefile = open("Makefile.%s" % machine, 'w') machine_makefile.write('''# -*- makefile -*- to build Colvars module with %s COLVARS_LIB = libcolvars.a COLVARS_OBJ_DIR = CXX = %s CXXFLAGS = %s %s AR = %s ARFLAGS = %s SHELL = %s include Makefile.common .PHONY: default clean default: $(COLVARS_LIB) Makefile.lammps clean: -rm -f $(COLVARS_OBJS) $(COLVARS_LIB) ''' % (machine, machine_flags['CC'], machine_flags['CCFLAGS'], machine_flags['SHFLAGS'] , machine_flags['ARCHIVE'], machine_flags['ARFLAGS'], machine_flags['SHELL'])) if not os.path.exists("Makefile.%s" % machine): machine_flags = get_lammps_machine_flags(machine) gen_colvars_makefile_machine(machine, machine_flags) if not os.path.exists("Makefile.%s" % machine): error("lib/%s/Makefile.%s does not exist" % (lib,machine)) # create Makefile.auto as copy of Makefile.machine # reset EXTRAMAKE if requested lines = open("Makefile.%s" % machine,'r').readlines() fp = open("Makefile.auto",'w') for line in lines: words = line.split() if len(words) == 3 and extraflag and \ words[0] == "EXTRAMAKE" and words[1] == '=': line = line.replace(words[2],"Makefile.lammps.%s" % suffix) fp.write(line) fp.close() # make the library via Makefile.auto try: import multiprocessing n_cpus = multiprocessing.cpu_count() except: n_cpus = 1 print("Building lib%s.a ..." % lib) cmd = ["make -f Makefile.auto clean"] print(subprocess.check_output(cmd, shell=True).decode()) cmd = ["make -f Makefile.auto -j%d" % n_cpus] print(subprocess.check_output(cmd, shell=True).decode()) if os.path.exists("lib%s.a" % lib): print("Build was successful") else: error("Build of lib/%s/lib%s.a was NOT successful" % (lib,lib)) if not os.path.exists("Makefile.lammps"): print("lib/%s/Makefile.lammps was NOT created" % lib) diff --git a/lib/gpu/Install.py b/lib/gpu/Install.py index d396be5e1..c6cd1f302 100644 --- a/lib/gpu/Install.py +++ b/lib/gpu/Install.py @@ -1,146 +1,155 @@ #!/usr/bin/env python # Install.py tool to build the GPU library # used to automate the steps described in the README file in this dir import sys,os,re,commands # help message help = """ -Syntax: python Install.py -i isuffix -h hdir -a arch -p precision -e esuffix -m -o osuffix - specify one or more options, order does not matter - copies an existing Makefile.isuffix in lib/gpu to Makefile.auto - optionally edits these variables in Makefile.auto: - CUDA_HOME, CUDA_ARCH, CUDA_PRECISION, EXTRAMAKE - optionally uses Makefile.auto to build the GPU library -> libgpu.a - and to copy a Makefile.lammps.esuffix -> Makefile.lammps - optionally copies Makefile.auto to a new Makefile.osuffix +Syntax from src dir: make lib-gpu args="-i isuffix -h hdir -a arch -p precision -e esuffix -m -o osuffix" +Syntax from lib dir: python Install.py -i isuffix -h hdir -a arch -p precision -e esuffix -m -o osuffix + +specify one or more options, order does not matter + +copies an existing Makefile.isuffix in lib/gpu to Makefile.auto +optionally edits these variables in Makefile.auto: + CUDA_HOME, CUDA_ARCH, CUDA_PRECISION, EXTRAMAKE +optionally uses Makefile.auto to build the GPU library -> libgpu.a + and to copy a Makefile.lammps.esuffix -> Makefile.lammps +optionally copies Makefile.auto to a new Makefile.osuffix -i = use Makefile.isuffix as starting point, copy to Makefile.auto default isuffix = linux -h = set CUDA_HOME variable in Makefile.auto to hdir hdir = path to NVIDIA Cuda software, e.g. /usr/local/cuda -a = set CUDA_ARCH variable in Makefile.auto to arch use arch = ?? for K40 (Tesla) use arch = 37 for dual K80 (Tesla) use arch = 60 for P100 (Pascal) -p = set CUDA_PRECISION variable in Makefile.auto to precision use precision = double or mixed or single -e = set EXTRAMAKE variable in Makefile.auto to Makefile.lammps.esuffix -m = make the GPU library using Makefile.auto first performs a "make clean" produces libgpu.a if successful also copies EXTRAMAKE file -> Makefile.lammps -e can set which Makefile.lammps.esuffix file is copied -o = copy final Makefile.auto to Makefile.osuffix + +Examples: + +make lib-gpu args="-m" # build GPU lib with default Makefile.linux +make lib-gpu args="-i xk7 -p single -o xk7.single" # create new Makefile.xk7.single, altered for single-precision +make lib-gpu args="-i xk7 -p single -o xk7.single -m" # ditto, also build GPU lib """ # print error message or help def error(str=None): if not str: print help else: print "ERROR",str sys.exit() # parse args args = sys.argv[1:] nargs = len(args) if nargs == 0: error() isuffix = "linux" hflag = aflag = pflag = eflag = 0 makeflag = 0 outflag = 0 iarg = 0 while iarg < nargs: if args[iarg] == "-i": if iarg+2 > nargs: error() isuffix = args[iarg+1] iarg += 2 elif args[iarg] == "-h": if iarg+2 > nargs: error() hflag = 1 hdir = args[iarg+1] iarg += 2 elif args[iarg] == "-a": if iarg+2 > nargs: error() aflag = 1 arch = args[iarg+1] iarg += 2 elif args[iarg] == "-p": if iarg+2 > nargs: error() pflag = 1 precision = args[iarg+1] iarg += 2 elif args[iarg] == "-e": if iarg+2 > nargs: error() eflag = 1 lmpsuffix = args[iarg+1] iarg += 2 elif args[iarg] == "-m": makeflag = 1 iarg += 1 elif args[iarg] == "-o": if iarg+2 > nargs: error() outflag = 1 osuffix = args[iarg+1] iarg += 2 else: error() if pflag: if precision == "double": precstr = "-D_DOUBLE_DOUBLE" elif precision == "mixed": precstr = "-D_SINGLE_DOUBLE" elif precision == "single": precstr = "-D_SINGLE_SINGLE" else: error("Invalid precision setting") # create Makefile.auto # reset EXTRAMAKE, CUDA_HOME, CUDA_ARCH, CUDA_PRECISION if requested if not os.path.exists("Makefile.%s" % isuffix): error("lib/gpu/Makefile.%s does not exist" % isuffix) lines = open("Makefile.%s" % isuffix,'r').readlines() fp = open("Makefile.auto",'w') for line in lines: words = line.split() if len(words) != 3: print >>fp,line, continue if hflag and words[0] == "CUDA_HOME" and words[1] == '=': line = line.replace(words[2],hdir) if aflag and words[0] == "CUDA_ARCH" and words[1] == '=': line = line.replace(words[2],"-arch=sm_%s" % arch) if pflag and words[0] == "CUDA_PRECISION" and words[1] == '=': line = line.replace(words[2],precstr) if eflag and words[0] == "EXTRAMAKE" and words[1] == '=': line = line.replace(words[2],"Makefile.lammps.%s" % lmpsuffix) print >>fp,line, fp.close() # perform make # make operations copies EXTRAMAKE file to Makefile.lammps if makeflag: print "Building libgpu.a ..." cmd = "rm -f libgpu.a" commands.getoutput(cmd) cmd = "make -f Makefile.auto clean; make -f Makefile.auto" commands.getoutput(cmd) if not os.path.exists("libgpu.a"): error("Build of lib/gpu/libgpu.a was NOT successful") if not os.path.exists("Makefile.lammps"): error("lib/gpu/Makefile.lammps was NOT created") # copy new Makefile.auto to Makefile.osuffix if outflag: print "Creating new Makefile.%s" % osuffix cmd = "cp Makefile.auto Makefile.%s" % osuffix commands.getoutput(cmd) diff --git a/lib/h5md/Install.py b/lib/h5md/Install.py index 37041d2ea..ffe709d44 120000 --- a/lib/h5md/Install.py +++ b/lib/h5md/Install.py @@ -1 +1 @@ -Install.py \ No newline at end of file +../Install.py \ No newline at end of file diff --git a/lib/h5md/Makefile.mpi b/lib/h5md/Makefile.mpi new file mode 120000 index 000000000..df682a954 --- /dev/null +++ b/lib/h5md/Makefile.mpi @@ -0,0 +1 @@ +Makefile.h5cc \ No newline at end of file diff --git a/lib/h5md/Makefile.serial b/lib/h5md/Makefile.serial new file mode 120000 index 000000000..df682a954 --- /dev/null +++ b/lib/h5md/Makefile.serial @@ -0,0 +1 @@ +Makefile.h5cc \ No newline at end of file diff --git a/lib/kim/.gitignore b/lib/kim/.gitignore index 3be8ecbdd..c1f57fe64 100644 --- a/lib/kim/.gitignore +++ b/lib/kim/.gitignore @@ -1,2 +1,3 @@ /Makefile.KIM_DIR /Makefile.KIM_Config +/installed-kim-api-* diff --git a/lib/kim/Install.py b/lib/kim/Install.py index bcd22dcbb..315bb4e11 100644 --- a/lib/kim/Install.py +++ b/lib/kim/Install.py @@ -1,150 +1,276 @@ #!/usr/bin/env python # install.py tool to setup the kim-api library # used to automate the steps described in the README file in this dir +from __future__ import print_function +import sys,os,re,subprocess -import sys,os,re,urllib,commands +# transparently use either urllib or an external tool +try: + import ssl + try: from urllib.request import urlretrieve as geturl + except: from urllib import urlretrieve as geturl +except: + def geturl(url,fname): + cmd = "curl -o %s %s" % (fname,url) + txt = subprocess.check_output(cmd,stderr=subprocess.STDOUT,shell=True) + return txt help = """ -Syntax: install.py -v version -c kim-dir -b kim-model-name -a kim-name - specify one or more options, order does not matter - -v = version of kim-api to download and work with - default = kim-api-v1.8.2 (current as of June 2017) - -c = create Makefile.KIM_DIR within lammps lib/kim to configure lammps - for use with the kim-api library installed at "kim-dir" (absolute - path). default = this dir - -b = build kim-api and kim model where kim-model-name can be a specific - openkim.org model name (such as - "EAM_Dynamo_Ackland_W__MO_141627196590_002") or the keyword - "OpenKIM" to install all compatible models from the openkim.org - site. - -a = add kim-name openkim.org item (model driver or model) to existing - kim-api instalation. +Syntax from src dir: make lib-kim args="-v version -a kim-name" +Syntax from lib dir: python Install.py -v version -a kim-name + +specify one or more options, order does not matter + + -v = version of KIM API library to use + default = kim-api-v1.8.2 (current as of June 2017) + -b = download and build base KIM API library with example Models (default) + this will delete any previous installation in the current folder + -n = do NOT download and build base KIM API library. Use an existing installation + -p = specify location of KIM API installation (implies -n) + -a = add single KIM model or model driver with kim-name + to existing KIM API lib (see example below). + If kim-name = everything, then rebuild KIM API library with + all available OpenKIM Models (this implies -b). + -vv = be more verbose about what is happening while the script runs + +Examples: + +make lib-kim # install KIM API lib with only example models +make lib-kim args="-a Glue_Ercolessi_Adams_Al__MO_324507536345_001" # Ditto plus one model +make lib-kim args="-a everything" # install KIM API lib with all models +make lib-kim args="-n -a EAM_Dynamo_Ackland_W__MO_141627196590_002" # only add one model or model driver + +See the list of KIM model drivers here: +https://openkim.org/kim-items/model-drivers/alphabetical + +See the list of all KIM models here: +https://openkim.org/kim-items/models/by-model-drivers + +See the list of example KIM models included by default here: +https://openkim.org/kim-api +in the "What is in the KIM API source package?" section """ def error(): - print help + print(help) sys.exit() +# expand to full path name +# process leading '~' or relative path + +def fullpath(path): + return os.path.abspath(os.path.expanduser(path)) + # parse args -args = sys.argv +args = sys.argv[1:] +nargs = len(args) thisdir = os.environ['PWD'] -dir = thisdir version = "kim-api-v1.8.2" -dirflag = 0 -buildflag = 0 -addflag = 0 +buildflag = True +everythingflag = False +addflag = False +verboseflag = False +pathflag = False -iarg = 1 +iarg = 0 while iarg < len(args): if args[iarg] == "-v": if iarg+2 > len(args): error() version = args[iarg+1] iarg += 2 - elif args[iarg] == "-c": - dirflag = 1 - if iarg+2 > len(args): error() - dir = args[iarg+1] - iarg += 2 elif args[iarg] == "-b": - buildflag = 1 + buildflag = True + iarg += 1 + elif args[iarg] == "-n": + buildflag = False + iarg += 1 + elif args[iarg] == "-p": if iarg+2 > len(args): error() - modelname = args[iarg+1] + kimdir = fullpath(args[iarg+1]) + pathflag = True + buildflag = False iarg += 2 elif args[iarg] == "-a": - addflag = 1 + addflag = True if iarg+2 > len(args): error() addmodelname = args[iarg+1] + if addmodelname == "everything": + buildflag = True + everythingflag = True + addflag = False iarg += 2 + elif args[iarg] == "-vv": + verboseflag = True + iarg += 1 else: error() thisdir = os.path.abspath(thisdir) -dir = os.path.abspath(dir) url = "https://s3.openkim.org/kim-api/%s.tgz" % version -# download and unpack tarball +# set KIM API directory +if pathflag: + if not os.path.isdir(kimdir): + print("\nkim-api is not installed at %s" % kimdir) + error() -if not os.path.isfile("%s/Makefile.KIM_DIR" % thisdir): - open("%s/Makefile.KIM_DIR" % thisdir, 'w').write("KIM_INSTALL_DIR=%s" % dir) - open("%s/Makefile.KIM_Config" % thisdir, 'w').write("include %s/lib/kim-api/Makefile.KIM_Config" % dir) - print "Created %s/Makefile.KIM_DIR : using %s" % (thisdir,dir) + # configure LAMMPS to use existing kim-api installation + with open("%s/Makefile.KIM_DIR" % thisdir, 'w') as mkfile: + mkfile.write("KIM_INSTALL_DIR=%s\n\n" % kimdir) + mkfile.write(".DUMMY: print_dir\n\n") + mkfile.write("print_dir:\n") + mkfile.write(" @printf $(KIM_INSTALL_DIR)\n") + + with open("%s/Makefile.KIM_Config" % thisdir, 'w') as cfgfile: + cfgfile.write("include %s/lib/kim-api/Makefile.KIM_Config" % kimdir) + + print("Created %s/Makefile.KIM_DIR\n using %s" % (thisdir,kimdir)) else: - if dirflag == 1: - open("%s/Makefile.KIM_DIR" % thisdir, 'w').write("KIM_INSTALL_DIR=%s" % dir) - open("%s/Makefile.KIM_Config" % thisdir, 'w').write("include %s/lib/kim-api/Makefile.KIM_Config" % dir) - print "Updated %s/Makefile.KIM_DIR : using %s" % (thisdir,dir) + kimdir = os.path.join(os.path.abspath(thisdir), "installed-" + version) + +# download KIM tarball, unpack, build KIM +if buildflag: + + # check to see if an installed kim-api already exists and wipe it out. + + if os.path.isdir(kimdir): + print("kim-api is already installed at %s.\nRemoving it for re-install" % kimdir) + cmd = "rm -rf %s" % kimdir + subprocess.check_output(cmd,stderr=subprocess.STDOUT,shell=True) + # configure LAMMPS to use kim-api to be installed -if buildflag == 1: - # download kim-api - print "Downloading kim-api tarball ..." - urllib.urlretrieve(url,"%s/%s.tgz" % (thisdir,version)) - print "Unpacking kim-api tarball ..." + with open("%s/Makefile.KIM_DIR" % thisdir, 'w') as mkfile: + mkfile.write("KIM_INSTALL_DIR=%s\n\n" % kimdir) + mkfile.write(".DUMMY: print_dir\n\n") + mkfile.write("print_dir:\n") + mkfile.write(" @printf $(KIM_INSTALL_DIR)\n") + + with open("%s/Makefile.KIM_Config" % thisdir, 'w') as cfgfile: + cfgfile.write("include %s/lib/kim-api/Makefile.KIM_Config" % kimdir) + + print("Created %s/Makefile.KIM_DIR\n using %s" % (thisdir,kimdir)) + + # download entire kim-api tarball + + print("Downloading kim-api tarball ...") + geturl(url,"%s/%s.tgz" % (thisdir,version)) + print("Unpacking kim-api tarball ...") cmd = "cd %s; rm -rf %s; tar zxvf %s.tgz" % (thisdir,version,version) - txt = commands.getstatusoutput(cmd) - if txt[0] != 0: error() + subprocess.check_output(cmd,stderr=subprocess.STDOUT,shell=True) # configure kim-api - print "Configuring kim-api ..." - cmd = "cd %s/%s; ./configure --prefix='%s'" % (thisdir,version,dir) - txt = commands.getstatusoutput(cmd) - print txt[1] - if txt[0] != 0: error() + + print("Configuring kim-api ...") + cmd = "cd %s/%s; ./configure --prefix='%s'" % (thisdir,version,kimdir) + subprocess.check_output(cmd,stderr=subprocess.STDOUT,shell=True) # build kim-api - print "Configuring model : %s" % modelname - cmd = "cd %s/%s; make add-%s" % (thisdir,version,modelname) - txt = commands.getstatusoutput(cmd) - print txt[1] - if txt[0] != 0: error() - # - print "Building kim-api ..." + + print("Configuring example Models") + cmd = "cd %s/%s; make add-examples" % (thisdir,version) + txt = subprocess.check_output(cmd,stderr=subprocess.STDOUT,shell=True) + if verboseflag: print (txt.decode("UTF-8")) + + if everythingflag: + print("Configuring all OpenKIM models, this will take a while ...") + cmd = "cd %s/%s; make add-OpenKIM" % (thisdir,version) + txt = subprocess.check_output(cmd,stderr=subprocess.STDOUT,shell=True) + if verboseflag: print(txt.decode("UTF-8")) + + print("Building kim-api ...") cmd = "cd %s/%s; make" % (thisdir,version) - txt = commands.getstatusoutput(cmd) - print txt[1] - if txt[0] != 0: error() + txt = subprocess.check_output(cmd,stderr=subprocess.STDOUT,shell=True) + if verboseflag: print(txt.decode("UTF-8")) # install kim-api - print "Installing kim-api ..." + + print("Installing kim-api ...") cmd = "cd %s/%s; make install" % (thisdir,version) - txt = commands.getstatusoutput(cmd) - print txt[1] - if txt[0] != 0: error() - # + txt = subprocess.check_output(cmd,stderr=subprocess.STDOUT,shell=True) + if verboseflag: print(txt.decode("UTF-8")) + cmd = "cd %s/%s; make install-set-default-to-v1" %(thisdir,version) - txt = commands.getstatusoutput(cmd) - print txt[1] - if txt[0] != 0: error() + txt = subprocess.check_output(cmd,stderr=subprocess.STDOUT,shell=True) + if verboseflag: print(txt.decode("UTF-8")) # remove source files - print "Removing kim-api source and build files ..." + + print("Removing kim-api source and build files ...") cmd = "cd %s; rm -rf %s; rm -rf %s.tgz" % (thisdir,version,version) - txt = commands.getstatusoutput(cmd) - print txt[1] - if txt[0] != 0: error() + subprocess.check_output(cmd,stderr=subprocess.STDOUT,shell=True) -if addflag == 1: - # download model +# add a single model (and possibly its driver) to existing KIM installation + +if addflag: + + if not os.path.isdir(kimdir): + print("\nkim-api is not installed") + error() + + # download single model + + print("Downloading tarball for %s..." % addmodelname) url = "https://openkim.org/download/%s.tgz" % addmodelname - print "Downloading item tarball ..." - urllib.urlretrieve(url,"%s/%s.tgz" % (thisdir,addmodelname)) - print "Unpacking item tarball ..." + geturl(url,"%s/%s.tgz" % (thisdir,addmodelname)) + + print("Unpacking item tarball ...") cmd = "cd %s; tar zxvf %s.tgz" % (thisdir,addmodelname) - txt = commands.getstatusoutput(cmd) - if txt[0] != 0: error() - # - print "Building item ..." + subprocess.check_output(cmd,stderr=subprocess.STDOUT,shell=True) + + print("Building item ...") cmd = "cd %s/%s; make; make install" %(thisdir,addmodelname) - txt = commands.getstatusoutput(cmd) - print txt[1] - if txt[0] != 0: error() - # - print "Removing kim item source and build files ..." + try: + txt = subprocess.check_output(cmd,stderr=subprocess.STDOUT,shell=True) + except subprocess.CalledProcessError as e: + + # Error: but first, check to see if it needs a driver + firstRunOutput = e.output.decode("UTF-8") + + cmd = "cd %s/%s; make kim-item-type" % (thisdir,addmodelname) + txt = subprocess.check_output(cmd,stderr=subprocess.STDOUT,shell=True) + txt = txt.decode("UTF-8") + if txt == "ParameterizedModel": + + # Get and install driver + + cmd = "cd %s/%s; make model-driver-name" % (thisdir,addmodelname) + txt = subprocess.check_output(cmd,stderr=subprocess.STDOUT,shell=True) + adddrivername = txt.decode("UTF-8").strip() + print("First installing model driver: %s..." % adddrivername) + cmd = "cd %s; python Install.py -n -a %s" % (thisdir,adddrivername) + try: + txt = subprocess.check_output(cmd,stderr=subprocess.STDOUT,shell=True) + except subprocess.CalledProcessError as e: + print(e.output) + sys.exit() + + if verboseflag: print(txt.decode("UTF-8")) + + # now install the model that needed the driver + + print("Now installing model : %s" % addmodelname) + cmd = "cd %s; python Install.py -n -a %s" % (thisdir,addmodelname) + try: + txt = subprocess.check_output(cmd,stderr=subprocess.STDOUT,shell=True) + except subprocess.CalledProcessError as e: + print(e.output) + sys.exit() + print(txt.decode("UTF-8")) + sys.exit() + else: + print(firstRunOutput) + print("Error, unable to build and install OpenKIM item: %s" \ + % addmodelname) + sys.exit() + + # success the first time + + if verboseflag: print(txt.decode("UTF-8")) + print("Removing kim item source and build files ...") cmd = "cd %s; rm -rf %s; rm -rf %s.tgz" %(thisdir,addmodelname,addmodelname) - txt = commands.getstatusoutput(cmd) - print txt[1] - if txt[0] != 0: error() + subprocess.check_output(cmd,stderr=subprocess.STDOUT,shell=True) diff --git a/lib/kim/README b/lib/kim/README index 00d6ea8fa..7a4230dc2 100644 --- a/lib/kim/README +++ b/lib/kim/README @@ -1,74 +1,76 @@ This directory contains build settings for the KIM API library which is required to use the KIM package and its pair_style kim command in a LAMMPS input script. Information about the KIM project can be found at https://openkim.org. The KIM project is lead by Ellad Tadmor and Ryan Elliott (U Minn) and James Sethna (Cornell U). Ryan Elliott is the main developer for the KIM API and he also maintains the code that implements the pair_style kim command. -To download, build, and install the KIM API on your system, follow -these steps. You can use the install.py script to automate these steps. +You can type "make lib-kim" from the src directory to see help on +how to download and build this library via make commands, or you can +do the same thing by typing "python Install.py" from within this +directory, or you can do it manually by following the instructions +below. ----------------- Instructions: - 1. Configure lammps for use with the kim-api library installed in this directory $ printf "KIM_INSTALL_DIR=${PWD}\n" > ./Makefile.KIM_DIR $ printf "include ${PWD}/lib/kim-api/Makefile.KIM_Config\n" > ./Makefile.KIM_Config 2. Download and unpack the kim-api # replace X.Y.Z as appropriate here and below $ wget http://s3.openkim.org/kim-api/kim-api-vX.Y.Z.tgz $ tar zxvf kim-api-vX.Y.Z.tgz # configure the kim-api $ cd kim-api-vX.Y.Z $ ./configure --prefix=${PWD}/../ # setup the desired kim item $ make add-Pair_Johnson_Fe__MO_857282754307_002 3. Build and install the kim-api and model $ make $ make install # replace X with the KIM API major version number $ make install-set-default-to-vX $ cd ../ 4. Remove source and build files $ rm -rf kim-api-vX.Y.Z $ rm -rf kim-api-vX.Y.Z.tgz 5. To add additional items do the following (replace the kim item name with your desired value) $ wget https://openkim.org/download/EAM_Johnson_NearestNeighbor_Cu__MO_887933271505_001.tgz $ tar zxvf EAM_Johnson_NearestNeighbor_Cu__MO_887933271505_001.tgz $ cd EAM_Johnson_NearestNeighbor_Cu__MO_887933271505_001 $ make $ make install $ cd .. $ rm -rf EAM_Johnson_NearestNeighbor_Cu__MO_887933271505_001 $ rm -rf EAM_Johnson_NearestNeighbor_Cu__MO_887933271505_001.tgz ----------------- When these steps are complete you can build LAMMPS with the KIM package installed: -$ cd ../../src +$ cd lammpos/src $ make yes-kim $ make g++ (or whatever target you wish) Note that the Makefile.lammps and Makefile.KIM_DIR files in this directory are required to allow the LAMMPS build to find the necessary KIM files. You should not normally need to edit this file. diff --git a/lib/linalg/Install.py b/lib/linalg/Install.py index c7076ca52..560afecec 100644 --- a/lib/linalg/Install.py +++ b/lib/linalg/Install.py @@ -1,52 +1,58 @@ #!/usr/bin/env python # install.py tool to do build of the linear algebra library # used to automate the steps described in the README file in this dir import sys,commands,os # help message help = """ -Syntax: python Install.py -m machine +Syntax from src dir: make lib-linalg args="-m machine" +Syntax from lib dir: python Install.py -m machine + -m = peform a clean followed by "make -f Makefile.machine" machine = suffix of a lib/Makefile.* file + +Example: + +make lib-linalg args="-m gfortran" # build with GNU Fortran compiler """ # print error message or help def error(str=None): if not str: print help else: print "ERROR",str sys.exit() # parse args args = sys.argv[1:] nargs = len(args) if nargs == 0: error() machine = None iarg = 0 while iarg < nargs: if args[iarg] == "-m": if iarg+2 > nargs: error() machine = args[iarg+1] iarg += 2 else: error() # set lib from working dir cwd = os.getcwd() lib = os.path.basename(cwd) # make the library print "Building lib%s.a ..." % lib cmd = "make -f Makefile.%s clean; make -f Makefile.%s" % (machine,machine) txt = commands.getoutput(cmd) print txt if os.path.exists("lib%s.a" % lib): print "Build was successful" else: error("Build of lib/%s/lib%s.a was NOT successful" % (lib,lib)) diff --git a/lib/meam/Install.py b/lib/meam/Install.py index 37041d2ea..ffe709d44 120000 --- a/lib/meam/Install.py +++ b/lib/meam/Install.py @@ -1 +1 @@ -Install.py \ No newline at end of file +../Install.py \ No newline at end of file diff --git a/lib/mscg/Install.py b/lib/mscg/Install.py index e54723261..7b10be189 100644 --- a/lib/mscg/Install.py +++ b/lib/mscg/Install.py @@ -1,122 +1,129 @@ #!/usr/bin/env python # Install.py tool to download, unpack, build, and link to the MS-CG library # used to automate the steps described in the README file in this dir import sys,os,re,commands # help message help = """ -Syntax: python Install.py -h hpath hdir -g -b [suffix] -l - specify one or more options, order does not matter +Syntax from src dir: make lib-mscg args="-h hpath hdir -g -b [suffix] -l" +Syntax from lib dir: python Install.py -h hpath hdir -g -b [suffix] -l + +specify one or more options, order does not matter + -h = set home dir of MS-CG to be hpath/hdir hpath can be full path, contain '~' or '.' chars default hpath = . = lib/mscg default hdir = MSCG-release-master = what GitHub zipfile unpacks to -g = grab (download) zipfile from MS-CG GitHub website unpack it to hpath/hdir hpath must already exist if hdir already exists, it will be deleted before unpack -b = build MS-CG library in its src dir optional suffix specifies which src/Make/Makefile.suffix to use default suffix = g++_simple -l = create 2 softlinks (includelink,liblink) in lib/mscg to MS-CG src dir + +Example: + +make lib-mscg args="-g -b -l" # download/build in lib/mscg/MSCG-release-master """ # settings url = "https://github.com/uchicago-voth/MSCG-release/archive/master.zip" zipfile = "MS-CG-master.zip" zipdir = "MSCG-release-master" # print error message or help def error(str=None): if not str: print help else: print "ERROR",str sys.exit() # expand to full path name # process leading '~' or relative path def fullpath(path): return os.path.abspath(os.path.expanduser(path)) # parse args args = sys.argv[1:] nargs = len(args) if nargs == 0: error() homepath = "." homedir = zipdir grabflag = 0 buildflag = 0 msuffix = "g++_simple" linkflag = 0 iarg = 0 while iarg < nargs: if args[iarg] == "-h": if iarg+3 > nargs: error() homepath = args[iarg+1] homedir = args[iarg+2] iarg += 3 elif args[iarg] == "-g": grabflag = 1 iarg += 1 elif args[iarg] == "-b": buildflag = 1 if iarg+1 < nargs and args[iarg+1][0] != '-': msuffix = args[iarg+1] iarg += 1 iarg += 1 elif args[iarg] == "-l": linkflag = 1 iarg += 1 else: error() homepath = fullpath(homepath) if not os.path.isdir(homepath): error("MS-CG path does not exist") homedir = "%s/%s" % (homepath,homedir) # download and unpack MS-CG zipfile if grabflag: print "Downloading MS-CG ..." cmd = "curl -L %s > %s/%s" % (url,homepath,zipfile) print cmd print commands.getoutput(cmd) print "Unpacking MS-CG zipfile ..." if os.path.exists("%s/%s" % (homepath,zipdir)): commands.getoutput("rm -rf %s/%s" % (homepath,zipdir)) cmd = "cd %s; unzip %s" % (homepath,zipfile) commands.getoutput(cmd) if os.path.basename(homedir) != zipdir: if os.path.exists(homedir): commands.getoutput("rm -rf %s" % homedir) os.rename("%s/%s" % (homepath,zipdir),homedir) # build MS-CG if buildflag: print "Building MS-CG ..." cmd = "cd %s/src; cp Make/Makefile.%s .; make -f Makefile.%s" % \ (homedir,msuffix,msuffix) txt = commands.getoutput(cmd) print txt # create 2 links in lib/mscg to MS-CG src dir if linkflag: print "Creating links to MS-CG include and lib files" if os.path.isfile("includelink") or os.path.islink("includelink"): os.remove("includelink") if os.path.isfile("liblink") or os.path.islink("liblink"): os.remove("liblink") cmd = "ln -s %s/src includelink" % homedir commands.getoutput(cmd) cmd = "ln -s %s/src liblink" % homedir commands.getoutput(cmd) diff --git a/lib/poems/Install.py b/lib/poems/Install.py index 37041d2ea..ffe709d44 120000 --- a/lib/poems/Install.py +++ b/lib/poems/Install.py @@ -1 +1 @@ -Install.py \ No newline at end of file +../Install.py \ No newline at end of file diff --git a/lib/qmmm/Install.py b/lib/qmmm/Install.py index 37041d2ea..ffe709d44 120000 --- a/lib/qmmm/Install.py +++ b/lib/qmmm/Install.py @@ -1 +1 @@ -Install.py \ No newline at end of file +../Install.py \ No newline at end of file diff --git a/lib/quip/.gitignore b/lib/quip/.gitignore new file mode 100644 index 000000000..d6797a67f --- /dev/null +++ b/lib/quip/.gitignore @@ -0,0 +1 @@ +/QUIP diff --git a/lib/quip/Makefile.lammps b/lib/quip/Makefile.lammps index 19ff20b07..e471d3f6f 100644 --- a/lib/quip/Makefile.lammps +++ b/lib/quip/Makefile.lammps @@ -1,30 +1,40 @@ # Settings that the LAMMPS build will import when this package library is used -# include ${QUIP_ROOT}/Makefiles/Makefile.${QUIP_ARCH} - -F95=$(shell egrep 'F95[ ]*=' ${QUIP_ROOT}/arch/Makefile.${QUIP_ARCH} | sed 's/.*F95[ ]*=[ ]*//') - +# try to guess settings assuming there is a configured QUIP git checkout inside the lib/quip directory +QUIPDIR=$(abspath ../../lib/quip/QUIP) ifeq (${QUIP_ROOT},) -$(error Environment variable QUIP_ROOT must be set.) + QUIP_ROOT=$(shell test -d $(QUIPDIR) && echo $(QUIPDIR)) + ifeq (${QUIP_ARCH},) + QUIP_ARCH=$(notdir $(wildcard $(QUIP_ROOT)/build/*)) + endif +else +# uncomment and set manually or set the corresponding environment variables +# QUIP_ROOT= +# QUIP_ARCH= endif +ifeq (${QUIP_ROOT},) +$(error Environment or make variable QUIP_ROOT must be set.) +endif ifeq (${QUIP_ARCH},) -$(error Environment variable QUIP_ARCH must be set.) +$(error Environment or make variable QUIP_ARCH must be set.) endif +F95=$(shell egrep 'F95[ ]*=' ${QUIP_ROOT}/arch/Makefile.${QUIP_ARCH} | sed 's/.*F95[ ]*=[ ]*//') include ${QUIP_ROOT}/build/${QUIP_ARCH}/Makefile.inc include ${QUIP_ROOT}/Makefile.rules quip_SYSLIB = -lquip quip_SYSLIB += ${NETCDF_SYSLIBS} quip_SYSLIB += ${MATH_LINKOPTS} ifeq (${F95},gfortran) quip_SYSLIB += -lgfortran else ifeq (${F95},ifort) quip_SYSLIB += -lifcore -lifport else $(error fortran compiler >>${F95}<< not recognised. Edit lib/quip/Makefile.lammps to specify the fortran library your linker should link to) endif quip_SYSPATH = -L${QUIP_ROOT}/build/${QUIP_ARCH} + diff --git a/lib/quip/README b/lib/quip/README index 94039cfa1..e6cc3903b 100644 --- a/lib/quip/README +++ b/lib/quip/README @@ -1,91 +1,102 @@ QUIP library Albert Bartok-Partay apbartok at gmail dot com 2014 This library provides a plug-in for calling QUIP potentials from LAMMPS. The QUIP package should be built separately, and then the resulting libraries can be linked to the LAMMPS code. In case of some potentials, such as BOP or GAP, third-party packages are needed, which must be downloaded and compiled separately. NB: although GAP has to be downloaded separately as it is licensed under a different license agreement, it is compiled together with the rest of QUIP. Building LAMMPS with QUIP support: 1) Building QUIP 1.1) Obtaining QUIP -The most current release of QUIP can be obtained from github: +The most current release of QUIP can be obtained from github: $ git clone https://github.com/libAtoms/QUIP.git QUIP If GAP is needed, it may be downloaded from the `Software' section of libatoms.org, after accepting the terms and conditions of the Academic License Agreement. Extract the tarball under the /path/to/QUIP/src/ directory. 1.2) Building QUIP There is a README file in the top-level QUIP directory, but here are the main steps. The arch directory contains a selection of machine- and compiler-specific makefiles, e.g. Makefile.linux_x86_64_gfortran. Decide which one is most appropriate for your system, and edit if necessary. The configuring step will use the makefile based on the QUIP_ARCH environment variable, i.e. Makefile.${QUIP_ARCH}. The script will create a build directory, build/${QUIP_ARCH}, and all the building will happen there. First it will ask you some questions about where you keep libraries and other stuff. Please note: if you are building QUIP to link it to LAMMPS, the serial version of QUIP must be compiled. For example, QUIP_ARCH may be: darwin_x86_64_gfortran linux_x86_64_gfortran linux_x86_64_ifort_icc etc. If you don't use something it is asking for, just leave it blank. NB make sure to answer `y' to `Do you want to compile with GAP prediction support ? [y/n]'. The answers will be stored in Makefile.inc in the build/${QUIP_ARCH} directory, and you can edit them later (e.g. to change optimisation or debug options). Note that the default state is usually with rather heavy debugging on, including bounds checking, which makes the code quite slow. The make command has to be executed from the top-level directory. Making `libquip' ensures all the necessary libraries will be built. for example: $ cd QUIP -$ export QUIP_ROOT=/path/to/QUIP +$ export QUIP_ROOT=${PWD} $ export QUIP_ARCH=linux_x86_64_gfortran $ make config $ make libquip Optionally, do $ make test to run a test suite. 2) Building LAMMPS -LAMMPS is now shipped with the interface necessary to use QUIP potentials, but -it should be enabled first. Enter the LAMMPS directory: +Edit Makefile.lammps in the lib/quip folder, if necessary. If you +have cloned, configured, and built QUIP inside this folder, QUIP_ROOT +and QUIP_ARCH should be autodetected, even without having to set +the environment variables. Otherwise export the environment variables +as shown above or edit Makefile.lammps + +LAMMPS ships with a user package containing the interface necessary +to use QUIP potentials, but it needs to be added to the compilation +first. To do that, enter the LAMMPS source directory and type: -$ cd LAMMPS -$ cd src $ make yes-user-quip 2.2) Build LAMMPS according to the instructions on the LAMMPS website. -3) There are two example sets in examples/USER/quip: +3) There are three example sets in examples/USER/quip: - a set of input files to compute the energy of an 8-atom cubic diamond cell of silicon with the Stillinger-Weber potential. Use this to benchmark that the interface is working correctly. +- a set of input files demonstrating the use of the QUIP pair style + for a molecular system with pair style hybrid/overlay and different + exclusion settings for different pair styles. This input is + for DEMONSTRATION purposes only, and does not simulate a physically + meaningful system. + - a set of input files to demonstrate how GAP potentials are specified in a LAMMPS input file to run a short MD. The GAP parameter file gap_example.xml is intended for TESTING purposes only. Potentials can be downloaded from http://www.libatoms.org or obtained from the authors of QUIP. diff --git a/lib/reax/Install.py b/lib/reax/Install.py index 37041d2ea..ffe709d44 120000 --- a/lib/reax/Install.py +++ b/lib/reax/Install.py @@ -1 +1 @@ -Install.py \ No newline at end of file +../Install.py \ No newline at end of file diff --git a/lib/smd/.gitignore b/lib/smd/.gitignore new file mode 100644 index 000000000..4ab7a789e --- /dev/null +++ b/lib/smd/.gitignore @@ -0,0 +1,5 @@ +# ignore these entries with git +/eigen.tar.gz +/eigen-eigen-* +/includelink +/eigen3 diff --git a/lib/smd/Install.py b/lib/smd/Install.py index dc0a3187c..337f993be 100644 --- a/lib/smd/Install.py +++ b/lib/smd/Install.py @@ -1,103 +1,117 @@ #!/usr/bin/env python # Install.py tool to download, unpack, and point to the Eigen library # used to automate the steps described in the README file in this dir -import sys,os,re,glob,commands +from __future__ import print_function +import sys,os,re,glob,subprocess +try: from urllib.request import urlretrieve as geturl +except: from urllib import urlretrieve as geturl # help message help = """ -Syntax: python Install.py -h hpath hdir -g -l - specify one or more options, order does not matter - -h = set home dir of Eigen to be hpath/hdir - hpath can be full path, contain '~' or '.' chars - default hpath = . = lib/smd - default hdir = "ee" = what tarball unpacks to (eigen-eigen-*) - -g = grab (download) tarball from http://eigen.tuxfamily.org website - unpack it to hpath/hdir - hpath must already exist - if hdir already exists, it will be deleted before unpack - -l = create softlink (includelink) in lib/smd to Eigen src dir +Syntax from src dir: make lib-smd + or: make lib-smd args="-p /usr/include/eigen3" + +Syntax from lib dir: python Install.py + or: python Install.py -p /usr/include/eigen3" + or: python Install.py -v 3.3.4 -b + +specify one or more options, order does not matter + + -b = download and unpack/configure the Eigen library (default) + -p = specify folder holding an existing installation of Eigen + -v = set version of Eigen library to download and set up (default = 3.3.4) + + +Example: + +make lib-smd args="-b" # download/build in default lib/smd/eigen-eigen-* """ # settings -url = "http://bitbucket.org/eigen/eigen/get/3.3.3.tar.gz" +version = '3.3.4' tarball = "eigen.tar.gz" # print error message or help def error(str=None): - if not str: print help - else: print "ERROR",str + if not str: print(help) + else: print("ERROR",str) sys.exit() # expand to full path name # process leading '~' or relative path - + def fullpath(path): return os.path.abspath(os.path.expanduser(path)) - + # parse args args = sys.argv[1:] nargs = len(args) -if nargs == 0: error() homepath = "." -homedir = "ee" +homedir = "eigen3" -grabflag = 0 -linkflag = 0 +grabflag = True +buildflag = True +pathflag = False +linkflag = True iarg = 0 while iarg < nargs: - if args[iarg] == "-h": - if iarg+3 > nargs: error() - homepath = args[iarg+1] - homedir = args[iarg+2] - iarg += 3 - elif args[iarg] == "-g": - grabflag = 1 - iarg += 1 - elif args[iarg] == "-l": - linkflag = 1 + if args[iarg] == "-v": + if iarg+2 > nargs: error() + version = args[iarg+1] + iarg += 2 + elif args[iarg] == "-p": + if iarg+2 > nargs: error() + eigenpath = fullpath(args[iarg+1]) + pathflag = True + buildflag = False + iarg += 2 + elif args[iarg] == "-b": + buildflag = True iarg += 1 else: error() homepath = fullpath(homepath) -if not os.path.isdir(homepath): error("Eigen path does not exist") + +if (pathflag): + if not os.path.isdir(eigenpath): error("Eigen path does not exist") + +if (buildflag and pathflag): + error("Cannot use -b and -p flag at the same time") # download and unpack Eigen tarball -# glob to find name of dir it unpacks to +# use glob to find name of dir it unpacks to -if grabflag: - print "Downloading Eigen ..." - cmd = "curl -L %s > %s/%s" % (url,homepath,tarball) - print cmd - print commands.getoutput(cmd) +if buildflag: + print("Downloading Eigen ...") + url = "http://bitbucket.org/eigen/eigen/get/%s.tar.gz" % version + geturl(url,"%s/%s" % (homepath,tarball)) - print "Unpacking Eigen tarball ..." + print("Unpacking Eigen tarball ...") edir = glob.glob("%s/eigen-eigen-*" % homepath) for one in edir: - if os.path.isdir(one): commands.getoutput("rm -rf %s" % one) - cmd = "cd %s; tar zxvf %s" % (homepath,tarball) - commands.getoutput(cmd) - if homedir != "ee": - if os.path.exists(homedir): commands.getoutput("rm -rf %s" % homedir) - edir = glob.glob("%s/eigen-eigen-*" % homepath) - os.rename(edir[0],"%s/%s" % (homepath,homedir)) + if os.path.isdir(one): + subprocess.check_output("rm -rf %s" % one,stderr=subprocess.STDOUT,shell=True) + cmd = 'cd "%s"; tar -xzvf %s' % (homepath,tarball) + subprocess.check_output(cmd,stderr=subprocess.STDOUT,shell=True) + edir = glob.glob("%s/eigen-eigen-*" % homepath) + os.rename(edir[0],"%s/%s" % (homepath,homedir)) + os.remove(tarball) # create link in lib/smd to Eigen src dir if linkflag: - print "Creating link to Eigen files" + print("Creating link to Eigen files") if os.path.isfile("includelink") or os.path.islink("includelink"): os.remove("includelink") - if homedir == "ee": - edir = glob.glob("%s/eigen-eigen-*" % homepath) - linkdir = edir[0] + if pathflag: linkdir = eigenpath else: linkdir = "%s/%s" % (homepath,homedir) cmd = "ln -s %s includelink" % linkdir - commands.getoutput(cmd) + subprocess.check_output(cmd,stderr=subprocess.STDOUT,shell=True) diff --git a/lib/voronoi/.gitignore b/lib/voronoi/.gitignore new file mode 100644 index 000000000..6ca01c094 --- /dev/null +++ b/lib/voronoi/.gitignore @@ -0,0 +1,4 @@ +# files to ignore +/liblink +/includelink +/voro++-* diff --git a/lib/voronoi/Install.py b/lib/voronoi/Install.py index 7d847183b..17bba5e8e 100644 --- a/lib/voronoi/Install.py +++ b/lib/voronoi/Install.py @@ -1,118 +1,128 @@ #!/usr/bin/env python # Install.py tool to download, unpack, build, and link to the Voro++ library # used to automate the steps described in the README file in this dir -import sys,os,re,urllib,commands +from __future__ import print_function +import sys,os,re,subprocess +try: from urllib.request import urlretrieve as geturl +except: from urllib import urlretrieve as geturl # help message help = """ -Syntax: python Install.py -v version -h hpath hdir -g -b -l - specify one or more options, order does not matter - -v = version of Voro++ to download and build - default version = voro++-0.4.6 (current as of Jan 2015) - -h = set home dir of Voro++ to be hpath/hdir - hpath can be full path, contain '~' or '.' chars - default hpath = . = lib/voronoi - default hdir = voro++-0.4.6 = what tarball unpacks to - -g = grab (download) tarball from math.lbl.gov/voro++ website - unpack it to hpath/hdir - hpath must already exist - if hdir already exists, it will be deleted before unpack - -b = build Voro++ library in its src dir - -l = create 2 softlinks (includelink,liblink) in lib/voronoi to Voro++ src dir +Syntax from src dir: make lib-voronoi + or: make lib-voronoi args="-p /usr/local/voro++-0.4.6" + or: make lib-voronoi args="-v voro++-0.4.6 -b" +Syntax from lib dir: python Install.py -v voro++-0.4.6 -b + or: python Install.py + or: python Install.py -p /usr/local/voro++-0.4.6 + +specify one or more options, order does not matter + + -b = download and build the Voro++ library (default) + -p = specify folder of existing Voro++ installation + -v = set version of Voro++ to download and build (default voro++-0.4.6) + +Example: + +make lib-voronoi args="-b" # download/build in lib/voronoi/voro++-0.4.6 """ # settings version = "voro++-0.4.6" url = "http://math.lbl.gov/voro++/download/dir/%s.tar.gz" % version # print error message or help def error(str=None): - if not str: print help - else: print "ERROR",str + if not str: print(help) + else: print("ERROR",str) sys.exit() # expand to full path name # process leading '~' or relative path - + def fullpath(path): return os.path.abspath(os.path.expanduser(path)) - + # parse args args = sys.argv[1:] nargs = len(args) -if nargs == 0: error() homepath = "." homedir = version -grabflag = 0 -buildflag = 0 -linkflag = 0 +grabflag = True +buildflag = True +pathflag = False +linkflag = True iarg = 0 while iarg < nargs: if args[iarg] == "-v": if iarg+2 > nargs: error() version = args[iarg+1] iarg += 2 - elif args[iarg] == "-h": - if iarg+3 > nargs: error() - homepath = args[iarg+1] - homedir = args[iarg+2] - iarg += 3 - elif args[iarg] == "-g": - grabflag = 1 - iarg += 1 + elif args[iarg] == "-p": + if iarg+2 > nargs: error() + voropath = fullpath(args[iarg+1]) + pathflag = True + buildflag = False + iarg += 2 elif args[iarg] == "-b": - buildflag = 1 - iarg += 1 - elif args[iarg] == "-l": - linkflag = 1 + buildflag = True iarg += 1 else: error() homepath = fullpath(homepath) -if not os.path.isdir(homepath): error("Voro++ path does not exist") -homedir = "%s/%s" % (homepath,homedir) +homedir = "%s/%s" % (homepath,version) + +if (pathflag): + if not os.path.isdir(voropath): error("Voro++ path does not exist") + homedir = voropath + +if (buildflag and pathflag): + error("Cannot use -b and -p flag at the same time") # download and unpack Voro++ tarball if grabflag: - print "Downloading Voro++ ..." - urllib.urlretrieve(url,"%s/%s.tar.gz" % (homepath,version)) - - print "Unpacking Voro++ tarball ..." + print("Downloading Voro++ ...") + geturl(url,"%s/%s.tar.gz" % (homepath,version)) + + print("Unpacking Voro++ tarball ...") if os.path.exists("%s/%s" % (homepath,version)): - commands.getoutput("rm -rf %s/%s" % (homepath,version)) - cmd = "cd %s; tar zxvf %s.tar.gz" % (homepath,version) - commands.getoutput(cmd) + cmd = 'rm -rf "%s/%s"' % (homepath,version) + subprocess.check_output(cmd,stderr=subprocess.STDOUT,shell=True) + cmd = 'cd "%s"; tar -xzvf %s.tar.gz' % (homepath,version) + subprocess.check_output(cmd,stderr=subprocess.STDOUT,shell=True) + os.remove("%s/%s.tar.gz" % (homepath,version)) if os.path.basename(homedir) != version: - if os.path.exists(homedir): commands.getoutput("rm -rf %s" % homedir) + if os.path.exists(homedir): + cmd = 'rm -rf "%s"' % homedir + subprocess.check_output(cmd,stderr=subprocess.STDOUT,shell=True) os.rename("%s/%s" % (homepath,version),homedir) # build Voro++ if buildflag: - print "Building Voro++ ..." - cmd = "cd %s; make" % homedir - txt = commands.getoutput(cmd) - print txt + print("Building Voro++ ...") + cmd = 'cd "%s"; make' % homedir + txt = subprocess.check_output(cmd,stderr=subprocess.STDOUT,shell=True) + print(txt.decode('UTF-8')) # create 2 links in lib/voronoi to Voro++ src dir if linkflag: - print "Creating links to Voro++ include and lib files" + print("Creating links to Voro++ include and lib files") if os.path.isfile("includelink") or os.path.islink("includelink"): os.remove("includelink") if os.path.isfile("liblink") or os.path.islink("liblink"): os.remove("liblink") - cmd = "ln -s %s/src includelink" % homedir - commands.getoutput(cmd) - cmd = "ln -s %s/src liblink" % homedir - commands.getoutput(cmd) + cmd = ['ln -s "%s/src" includelink' % homedir, 'includelink'] + subprocess.check_output(cmd,stderr=subprocess.STDOUT,shell=True) + cmd = ['ln -s "%s/src" liblink' % homedir] + subprocess.check_output(cmd,stderr=subprocess.STDOUT,shell=True) diff --git a/lib/voronoi/README b/lib/voronoi/README index 9863632be..2ca11c922 100644 --- a/lib/voronoi/README +++ b/lib/voronoi/README @@ -1,63 +1,63 @@ This directory contains links to the Voro++ library which is required to use the VORONOI package and its compute voronoi/atom command in a LAMMPS input script. The Voro++ library is available at http://math.lbl.gov/voro++ and was developed by Chris H. Rycroft while at UC Berkeley / Lawrence Berkeley Laboratory. You can type "make lib-voronoi" from the src directory to see help on how to download and build this library via make commands, or you can do the same thing by typing "python Install.py" from within this directory, or you can do it manually by following the instructions below. ----------------- Instructions: 1. Download Voro++ at http://math.lbl.gov/voro++/download either as a tarball or via SVN, and unpack the tarball either in this /lib/voronoi directory or somewhere else on your system. 2. compile Voro++ from within its home directory - % make + % make 3. There is no need to install Voro++ if you only wish to use it from LAMMPS. You can install it if you wish to use it stand-alone or from other codes: a) install under the default /usr/local % sudo make install b) install under a user-writeable location by first changing the PREFIX variable in the config.mk file, then % make install 4. Create two soft links in this dir (lib/voronoi) to the Voro++ src directory is. E.g if you built Voro++ in this dir: % ln -s voro++-0.4.6/src includelink % ln -s voro++-0.4.6/src liblink These links could instead be set to the include and lib directories created by a Voro++ install, e.g. % ln -s /usr/local/include includelink % ln -s /usr/local/lib liblink ----------------- When these steps are complete you can build LAMMPS with the VORONOI package installed: % cd lammps/src % make yes-voronoi % make g++ (or whatever target you wish) Note that if you download and unpack a new LAMMPS tarball, the "includelink" and "liblink" files will be lost and you will need to re-create them (step 4). If you built Voro++ in this directory (as opposed to somewhere else on your system) and did not install it somewhere else, you will also need to repeat steps 1,2,3. The Makefile.lammps file in this directory is there for compatibility with the way other libraries under the lib dir are linked with by LAMMPS. However, Voro++ requires no auxiliary files or settings, so its variables are blank. diff --git a/src/.gitignore b/src/.gitignore index e26f3c6ca..80166e260 100644 --- a/src/.gitignore +++ b/src/.gitignore @@ -1,1082 +1,1084 @@ /Makefile.package /Makefile.package.settings /MAKE/MINE /Make.py.last /lmp_* /style_*.h /*_gpu.h /*_gpu.cpp /*_intel.h /*_intel.cpp /*_kokkos.h /*_kokkos.cpp /*_omp.h /*_omp.cpp /*_tally.h /*_tally.cpp /*_rx.h /*_rx.cpp /*_ssa.h /*_ssa.cpp /kokkos.cpp /kokkos.h /kokkos_type.h /kokkos_few.h /manifold*.cpp /manifold*.h /fix_*manifold*.cpp /fix_*manifold*.h /meam*.h /meam*.cpp /pair_meamc.cpp /pair_meamc.h /fix_qeq*.cpp /fix_qeq*.h /compute_test_nbl.cpp /compute_test_nbl.h /pair_multi_lucy.cpp /pair_multi_lucy.h /colvarproxy_lammps.cpp /colvarproxy_lammps.h /fix_colvars.cpp /fix_colvars.h /dump_molfile.cpp /dump_molfile.h /molfile_interface.cpp /molfile_interface.h /type_detector.h /intel_buffers.cpp /intel_buffers.h /intel_intrinsics.h /intel_preprocess.h /intel_simd.h /compute_sna_atom.cpp /compute_sna_atom.h /compute_snad_atom.cpp /compute_snad_atom.h /compute_snav_atom.cpp /compute_snav_atom.h /openmp_snap.h /pair_snap.cpp /pair_snap.h /sna.cpp /sna.h /atom_vec_wavepacket.cpp /atom_vec_wavepacket.h /fix_nve_awpmd.cpp /fix_nve_awpmd.h /pair_awpmd_cut.cpp /pair_awpmd_cut.h /dihedral_charmmfsw.cpp /dihedral_charmmfsw.h /pair_lj_charmmfsw_coul_charmmfsh.cpp /pair_lj_charmmfsw_coul_charmmfsh.h /pair_lj_charmmfsw_coul_long.cpp /pair_lj_charmmfsw_coul_long.h /angle_cg_cmm.cpp /angle_cg_cmm.h /angle_charmm.cpp /angle_charmm.h /angle_class2.cpp /angle_class2.h /angle_cosine.cpp /angle_cosine.h /angle_cosine_delta.cpp /angle_cosine_delta.h /angle_cosine_periodic.cpp /angle_cosine_periodic.h /angle_cosine_shift.cpp /angle_cosine_shift.h /angle_cosine_shift_exp.cpp /angle_cosine_shift_exp.h /angle_cosine_squared.cpp /angle_cosine_squared.h /angle_dipole.cpp /angle_dipole.h /angle_fourier.cpp /angle_fourier.h /angle_fourier_simple.cpp /angle_fourier_simple.h /angle_harmonic.cpp /angle_harmonic.h /angle_quartic.cpp /angle_quartic.h /angle_sdk.cpp /angle_sdk.h /angle_table.cpp /angle_table.h /atom_vec_angle.cpp /atom_vec_angle.h /atom_vec_bond.cpp /atom_vec_bond.h /atom_vec_colloid.cpp /atom_vec_colloid.h /atom_vec_dipole.cpp /atom_vec_dipole.h /atom_vec_dpd.cpp /atom_vec_dpd.h /atom_vec_electron.cpp /atom_vec_electron.h /atom_vec_ellipsoid.cpp /atom_vec_ellipsoid.h /atom_vec_full.cpp /atom_vec_full.h /atom_vec_full_hars.cpp /atom_vec_full_hars.h /atom_vec_granular.cpp /atom_vec_granular.h /atom_vec_meso.cpp /atom_vec_meso.h /atom_vec_molecular.cpp /atom_vec_molecular.h /atom_vec_peri.cpp /atom_vec_peri.h /atom_vec_template.cpp /atom_vec_template.h /body_nparticle.cpp /body_nparticle.h /bond_class2.cpp /bond_class2.h /bond_fene.cpp /bond_fene.h /bond_fene_expand.cpp /bond_fene_expand.h /bond_harmonic.cpp /bond_harmonic.h /bond_harmonic_shift.cpp /bond_harmonic_shift.h /bond_harmonic_shift_cut.cpp /bond_harmonic_shift_cut.h /bond_morse.cpp /bond_morse.h /bond_nonlinear.cpp /bond_nonlinear.h /bond_oxdna_fene.cpp /bond_oxdna_fene.h /bond_oxdna2_fene.cpp /bond_oxdna2_fene.h /bond_quartic.cpp /bond_quartic.h /bond_table.cpp /bond_table.h /cg_cmm_parms.cpp /cg_cmm_parms.h /commgrid.cpp /commgrid.h /compute_ackland_atom.cpp /compute_ackland_atom.h /compute_basal_atom.cpp /compute_basal_atom.h /compute_body_local.cpp /compute_body_local.h /compute_cnp_atom.cpp /compute_cnp_atom.h /compute_damage_atom.cpp /compute_damage_atom.h /compute_dilatation_atom.cpp /compute_dilatation_atom.h /compute_dpd.cpp /compute_dpd.h /compute_dpd_atom.cpp /compute_dpd_atom.h /compute_erotate_asphere.cpp /compute_erotate_asphere.h /compute_erotate_rigid.cpp /compute_erotate_rigid.h /compute_event_displace.cpp /compute_event_displace.h /compute_fep.cpp /compute_fep.h /compute_force_tally.cpp /compute_force_tally.h /compute_heat_flux_tally.cpp /compute_heat_flux_tally.h /compute_ke_atom_eff.cpp /compute_ke_atom_eff.h /compute_ke_eff.cpp /compute_ke_eff.h /compute_ke_rigid.cpp /compute_ke_rigid.h /compute_meso_e_atom.cpp /compute_meso_e_atom.h /compute_meso_rho_atom.cpp /compute_meso_rho_atom.h /compute_meso_t_atom.cpp /compute_meso_t_atom.h /compute_msd_nongauss.cpp /compute_msd_nongauss.h /compute_pe_tally.cpp /compute_pe_tally.h /compute_plasticity_atom.cpp /compute_plasticity_atom.h /compute_pressure_grem.cpp /compute_pressure_grem.h /compute_rigid_local.cpp /compute_rigid_local.h /compute_spec_atom.cpp /compute_spec_atom.h /compute_stress_tally.cpp /compute_stress_tally.h /compute_temp_asphere.cpp /compute_temp_asphere.h /compute_temp_body.cpp /compute_temp_body.h /compute_temp_deform_eff.cpp /compute_temp_deform_eff.h /compute_temp_eff.cpp /compute_temp_eff.h /compute_temp_region_eff.cpp /compute_temp_region_eff.h /compute_temp_rotate.cpp /compute_temp_rotate.h /compute_ti.cpp /compute_ti.h /compute_voronoi_atom.cpp /compute_voronoi_atom.h /dihedral_charmm.cpp /dihedral_charmm.h /dihedral_class2.cpp /dihedral_class2.h /dihedral_cosine_shift_exp.cpp /dihedral_cosine_shift_exp.h /dihedral_fourier.cpp /dihedral_fourier.h /dihedral_harmonic.cpp /dihedral_harmonic.h /dihedral_helix.cpp /dihedral_helix.h /dihedral_hybrid.cpp /dihedral_hybrid.h /dihedral_multi_harmonic.cpp /dihedral_multi_harmonic.h /dihedral_nharmonic.cpp /dihedral_nharmonic.h /dihedral_opls.cpp /dihedral_opls.h /dihedral_quadratic.cpp /dihedral_quadratic.h /dihedral_spherical.cpp /dihedral_spherical.h /dihedral_table.cpp /dihedral_table.h /dump_atom_gz.cpp /dump_atom_gz.h /dump_xyz_gz.cpp /dump_xyz_gz.h /dump_atom_mpiio.cpp /dump_atom_mpiio.h /dump_cfg_gz.cpp /dump_cfg_gz.h /dump_cfg_mpiio.cpp /dump_cfg_mpiio.h /dump_custom_gz.cpp /dump_custom_gz.h /dump_custom_mpiio.cpp /dump_custom_mpiio.h /dump_h5md.cpp /dump_h5md.h /dump_netcdf.cpp /dump_netcdf.h /dump_netcdf_mpiio.cpp /dump_netcdf_mpiio.h /dump_vtk.cpp /dump_vtk.h /dump_xtc.cpp /dump_xtc.h /dump_xyz_mpiio.cpp /dump_xyz_mpiio.h /ewald.cpp /ewald.h /ewald_cg.cpp /ewald_cg.h /ewald_disp.cpp /ewald_disp.h /ewald_n.cpp /ewald_n.h /fft3d.cpp /fft3d.h /fft3d_wrap.cpp /fft3d_wrap.h /fix_adapt_fep.cpp /fix_adapt_fep.h /fix_addtorque.cpp /fix_addtorque.h /fix_append_atoms.cpp /fix_append_atoms.h /fix_atc.cpp /fix_atc.h /fix_ave_correlate_long.cpp /fix_ave_correlate_long.h /fix_bond_break.cpp /fix_bond_break.h /fix_bond_create.cpp /fix_bond_create.h /fix_bond_swap.cpp /fix_bond_swap.h /fix_cmap.cpp /fix_cmap.h /fix_deposit.cpp /fix_deposit.h /fix_dpd_energy.cpp /fix_dpd_energy.h /fix_efield.cpp /fix_efield.h /fix_eos_cv.cpp /fix_eos_cv.h /fix_eos_table.cpp /fix_eos_table.h /fix_evaporate.cpp /fix_evaporate.h /fix_filter_corotate.cpp /fix_filter_corotate.h /fix_viscosity.cpp /fix_viscosity.h /fix_ehex.cpp /fix_ehex.h /fix_event.cpp /fix_event.h /fix_event_prd.cpp /fix_event_prd.h /fix_event_tad.cpp /fix_event_tad.h /fix_flow_gauss.cpp /fix_flow_gauss.h /fix_freeze.cpp /fix_freeze.h /fix_gcmc.cpp /fix_gcmc.h /fix_gld.cpp /fix_gld.h /fix_gle.cpp /fix_gle.h /fix_gpu.cpp /fix_gpu.h /fix_grem.cpp /fix_grem.h /fix_imd.cpp /fix_imd.h /fix_ipi.cpp /fix_ipi.h /fix_lambdah_calc.cpp /fix_lambdah_calc.h /fix_langevin_eff.cpp /fix_langevin_eff.h /fix_lb_fluid.cpp /fix_lb_fluid.h /fix_lb_momentum.cpp /fix_lb_momentum.h /fix_lb_pc.cpp /fix_lb_pc.h /fix_lb_rigid_pc_sphere.cpp /fix_lb_rigid_pc_sphere.h /fix_lb_viscous.cpp /fix_lb_viscous.h /fix_load_report.cpp /fix_load_report.h /fix_meso.cpp /fix_meso.h /fix_meso_stationary.cpp /fix_meso_stationary.h /fix_mscg.cpp /fix_mscg.h /fix_msst.cpp /fix_msst.h /fix_neb.cpp /fix_neb.h /fix_nh_asphere.cpp /fix_nh_asphere.h /fix_nph_asphere.cpp /fix_nph_asphere.h /fix_npt_asphere.cpp /fix_npt_asphere.h /fix_nve_asphere.cpp /fix_nve_asphere.h /fix_nve_asphere_noforce.cpp /fix_nve_asphere_noforce.h /fix_nve_dot.cpp /fix_nve_dot.h /fix_nve_dotc_langevin.cpp /fix_nve_dotc_langevin.h /fix_nh_body.cpp /fix_nh_body.h /fix_nph_body.cpp /fix_nph_body.h /fix_npt_body.cpp /fix_npt_body.h /fix_nvk.cpp /fix_nvk.h /fix_nvt_body.cpp /fix_nvt_body.h /fix_nve_body.cpp /fix_nve_body.h /fix_nvt_asphere.cpp /fix_nvt_asphere.h /fix_nh_eff.cpp /fix_nh_eff.h /fix_nph_eff.cpp /fix_nph_eff.h /fix_nphug.cpp /fix_nphug.h /fix_npt_eff.cpp /fix_npt_eff.h /fix_nve_eff.cpp /fix_nve_eff.h /fix_nve_line.cpp /fix_nve_line.h /fix_nvt_eff.cpp /fix_nvt_eff.h /fix_nvt_sllod_eff.cpp /fix_nvt_sllod_eff.h /fix_nve_tri.cpp /fix_nve_tri.h /fix_oneway.cpp /fix_oneway.h /fix_orient_bcc.cpp /fix_orient_bcc.h /fix_orient_fcc.cpp /fix_orient_fcc.h /fix_peri_neigh.cpp /fix_peri_neigh.h /fix_phonon.cpp /fix_phonon.h /fix_poems.cpp /fix_poems.h /fix_pour.cpp /fix_pour.h /fix_qeq_comb.cpp /fix_qeq_comb.h /fix_qeq_reax.cpp /fix_qeq_fire.cpp /fix_qeq_fire.h /fix_qeq_reax.h /fix_qmmm.cpp /fix_qmmm.h /fix_reax_bonds.cpp /fix_reax_bonds.h /fix_reaxc.cpp /fix_reaxc.h /fix_reaxc_bonds.cpp /fix_reaxc_bonds.h /fix_reaxc_species.cpp /fix_reaxc_species.h /fix_rigid.cpp /fix_rigid.h /fix_rigid_nh.cpp /fix_rigid_nh.h /fix_rigid_nph.cpp /fix_rigid_nph.h /fix_rigid_npt.cpp /fix_rigid_npt.h /fix_rigid_nve.cpp /fix_rigid_nve.h /fix_rigid_nvt.cpp /fix_rigid_nvt.h /fix_rigid_nh_small.cpp /fix_rigid_nh_small.h /fix_rigid_nph_small.cpp /fix_rigid_nph_small.h /fix_rigid_npt_small.cpp /fix_rigid_npt_small.h /fix_rigid_nve_small.cpp /fix_rigid_nve_small.h /fix_rigid_nvt_small.cpp /fix_rigid_nvt_small.h /fix_rigid_small.cpp /fix_rigid_small.h /fix_shake.cpp /fix_shake.h /fix_shardlow.cpp /fix_shardlow.h /fix_smd.cpp /fix_smd.h /fix_species.cpp /fix_species.h /fix_spring_pull.cpp /fix_spring_pull.h /fix_srd.cpp /fix_srd.h /fix_temp_rescale_eff.cpp /fix_temp_rescale_eff.h /fix_thermal_conductivity.cpp /fix_thermal_conductivity.h /fix_ti_rs.cpp /fix_ti_rs.h /fix_ti_spring.cpp /fix_ti_spring.h /fix_ttm.cpp /fix_ttm.h /fix_tune_kspace.cpp /fix_tune_kspace.h /fix_wall_colloid.cpp /fix_wall_colloid.h /fix_wall_ees.cpp /fix_wall_ees.h /fix_wall_region_ees.cpp /fix_wall_region_ees.h /fix_wall_gran.cpp /fix_wall_gran.h /fix_wall_gran_region.cpp /fix_wall_gran_region.h /fix_wall_piston.cpp /fix_wall_piston.h /fix_wall_srd.cpp /fix_wall_srd.h /gpu_extra.h /gridcomm.cpp /gridcomm.h /group_ndx.cpp /group_ndx.h /ndx_group.cpp /ndx_group.h /improper_class2.cpp /improper_class2.h /improper_cossq.cpp /improper_cossq.h /improper_cvff.cpp /improper_cvff.h /improper_distance.cpp /improper_distance.h /improper_fourier.cpp /improper_fourier.h /improper_harmonic.cpp /improper_harmonic.h /improper_hybrid.cpp /improper_hybrid.h /improper_ring.cpp /improper_ring.h /improper_umbrella.cpp /improper_umbrella.h /kissfft.h /lj_sdk_common.h /math_complex.h /math_vector.h /mgpt_*.cpp /mgpt_*.h /msm.cpp /msm.h /msm_cg.cpp /msm_cg.h /neb.cpp /neb.h /pair_adp.cpp /pair_adp.h /pair_agni.cpp /pair_agni.h /pair_airebo.cpp /pair_airebo.h /pair_airebo_morse.cpp /pair_airebo_morse.h /pair_body.cpp /pair_body.h /pair_bop.cpp /pair_bop.h /pair_born_coul_long.cpp /pair_born_coul_long.h /pair_born_coul_msm.cpp /pair_born_coul_msm.h /pair_brownian.cpp /pair_brownian.h /pair_brownian_poly.cpp /pair_brownian_poly.h /pair_buck_coul_long.cpp /pair_buck_coul_long.h /pair_buck_coul_msm.cpp /pair_buck_coul_msm.h /pair_buck_coul.cpp /pair_buck_coul.h /pair_buck_long_coul_long.cpp /pair_buck_long_coul_long.h /pair_cdeam.cpp /pair_cdeam.h /pair_cg_cmm.cpp /pair_cg_cmm.h /pair_cg_cmm_coul_cut.cpp /pair_cg_cmm_coul_cut.h /pair_cg_cmm_coul_long.cpp /pair_cg_cmm_coul_long.h /pair_cmm_common.cpp /pair_cmm_common.h /pair_cg_cmm_coul_msm.cpp /pair_cg_cmm_coul_msm.h /pair_comb.cpp /pair_comb.h /pair_comb3.cpp /pair_comb3.h /pair_colloid.cpp /pair_colloid.h /pair_coul_diel.cpp /pair_coul_diel.h /pair_coul_long.cpp /pair_coul_long.h /pair_coul_msm.cpp /pair_coul_msm.h /pair_dipole_cut.cpp /pair_dipole_cut.h /pair_dipole_sf.cpp /pair_dipole_sf.h /pair_dpd_mt.cpp /pair_dpd_mt.h /pair_dsmc.cpp /pair_dsmc.h /pair_eam.cpp /pair_eam.h /pair_eam_opt.cpp /pair_eam_opt.h /pair_eam_alloy.cpp /pair_eam_alloy.h /pair_eam_alloy_opt.cpp /pair_eam_alloy_opt.h /pair_eam_fs.cpp /pair_eam_fs.h /pair_eam_fs_opt.cpp /pair_eam_fs_opt.h /pair_edip.cpp /pair_edip.h /pair_edip_multi.cpp /pair_edip_multi.h /pair_eff_cut.cpp /pair_eff_cut.h /pair_eff_inline.h /pair_eim.cpp /pair_eim.h /pair_gauss_cut.cpp /pair_gauss_cut.h /pair_gayberne.cpp /pair_gayberne.h /pair_gran_easy.cpp /pair_gran_easy.h /pair_gran_hertz_history.cpp /pair_gran_hertz_history.h /pair_gran_hooke.cpp /pair_gran_hooke.h /pair_gran_hooke_history.cpp /pair_gran_hooke_history.h /pair_gw.cpp /pair_gw.h /pair_gw_zbl.cpp /pair_gw_zbl.h /pair_hbond_dreiding_lj.cpp /pair_hbond_dreiding_lj.h /pair_hbond_dreiding_morse.cpp /pair_hbond_dreiding_morse.h /pair_kolmogorov_crespi_z.cpp /pair_kolmogorov_crespi_z.h /pair_lcbop.cpp /pair_lcbop.h /pair_line_lj.cpp /pair_line_lj.h /pair_list.cpp /pair_list.h /pair_lj_charmm_coul_charmm.cpp /pair_lj_charmm_coul_charmm.h /pair_lj_charmm_coul_charmm_implicit.cpp /pair_lj_charmm_coul_charmm_implicit.h /pair_lj_charmm_coul_long.cpp /pair_lj_charmm_coul_long.h /pair_lj_charmm_coul_long_opt.cpp /pair_lj_charmm_coul_long_opt.h /pair_lj_charmm_coul_long_soft.cpp /pair_lj_charmm_coul_long_soft.h /pair_lj_charmm_coul_msm.cpp /pair_lj_charmm_coul_msm.h /pair_lj_class2.cpp /pair_lj_class2.h /pair_lj_class2_coul_cut.cpp /pair_lj_class2_coul_cut.h /pair_lj_class2_coul_long.cpp /pair_lj_class2_coul_long.h /pair_lj_coul.cpp /pair_lj_coul.h /pair_coul_cut_soft.cpp /pair_coul_cut_soft.h /pair_coul_long_soft.cpp /pair_coul_long_soft.h /pair_lj_cut_coul_cut_soft.cpp /pair_lj_cut_coul_cut_soft.h /pair_lj_cut_tip4p_cut.cpp /pair_lj_cut_tip4p_cut.h /pair_lj_cut_coul_long.cpp /pair_lj_cut_coul_long.h /pair_lj_cut_coul_long_opt.cpp /pair_lj_cut_coul_long_opt.h /pair_lj_cut_coul_long_soft.cpp /pair_lj_cut_coul_long_soft.h /pair_lj_cut_coul_msm.cpp /pair_lj_cut_coul_msm.h /pair_lj_cut_dipole_cut.cpp /pair_lj_cut_dipole_cut.h /pair_lj_cut_dipole_long.cpp /pair_lj_cut_dipole_long.h /pair_lj_cut_*hars_*.cpp /pair_lj_cut_*hars_*.h /pair_lj_cut_soft.cpp /pair_lj_cut_soft.h /pair_lj_cut_tip4p_long.cpp /pair_lj_cut_tip4p_long.h /pair_lj_cut_tip4p_long_opt.cpp /pair_lj_cut_tip4p_long_opt.h /pair_lj_cut_tip4p_long_soft.cpp /pair_lj_cut_tip4p_long_soft.h /pair_lj_long_coul_long.cpp /pair_lj_long_coul_long.h /pair_lj_long_coul_long_opt.cpp /pair_lj_long_coul_long_opt.h /pair_lj_long_dipole_long.cpp /pair_lj_long_dipole_long.h /pair_lj_long_tip4p_long.cpp /pair_lj_long_tip4p_long.h /pair_lj_cut_opt.cpp /pair_lj_cut_opt.h /pair_lj_cut_tgpu.cpp /pair_lj_cut_tgpu.h /pair_lj_sdk.cpp /pair_lj_sdk.h /pair_lj_sdk_coul_long.cpp /pair_lj_sdk_coul_long.h /pair_lj_sdk_coul_msm.cpp /pair_lj_sdk_coul_msm.h /pair_lj_sf_dipole_sf.cpp /pair_lj_sf_dipole_sf.h /pair_lubricateU.cpp /pair_lubricateU.h /pair_lubricateU_poly.cpp /pair_lubricateU_poly.h /pair_lubricate_poly.cpp /pair_lubricate_poly.h /pair_lubricate.cpp /pair_lubricate.h /pair_meam.cpp /pair_meam.h /pair_meam_spline.cpp /pair_meam_spline.h /pair_meam_sw_spline.cpp /pair_meam_sw_spline.h /pair_morse_opt.cpp /pair_morse_opt.h /pair_morse_soft.cpp /pair_morse_soft.h /pair_nb3b_harmonic.cpp /pair_nb3b_harmonic.h /pair_nm_cut.cpp /pair_nm_cut.h /pair_nm_cut_coul_cut.cpp /pair_nm_cut_coul_cut.h /pair_nm_cut_coul_long.cpp /pair_nm_cut_coul_long.h /pair_oxdna_*.cpp /pair_oxdna_*.h /pair_oxdna2_*.cpp /pair_oxdna2_*.h /mf_oxdna.h /pair_peri_eps.cpp /pair_peri_eps.h /pair_peri_lps.cpp /pair_peri_lps.h /pair_peri_pmb.cpp /pair_peri_pmb.h /pair_peri_ves.cpp /pair_peri_ves.h +/pair_quip.cpp +/pair_quip.h /pair_reax.cpp /pair_reax.h /pair_reax_fortran.h /pair_reaxc.cpp /pair_reaxc.h /pair_rebo.cpp /pair_rebo.h /pair_resquared.cpp /pair_resquared.h /pair_sph_heatconduction.cpp /pair_sph_heatconduction.h /pair_sph_idealgas.cpp /pair_sph_idealgas.h /pair_sph_lj.cpp /pair_sph_lj.h /pair_sph_rhosum.cpp /pair_sph_rhosum.h /pair_sph_taitwater.cpp /pair_sph_taitwater.h /pair_sph_taitwater_morris.cpp /pair_sph_taitwater_morris.h /pair_sw.cpp /pair_sw.h /pair_tersoff.cpp /pair_tersoff.h /pair_tersoff_mod.cpp /pair_tersoff_mod.h /pair_tersoff_mod_c.cpp /pair_tersoff_mod_c.h /pair_tersoff_table.cpp /pair_tersoff_table.h /pair_tersoff_zbl.cpp /pair_tersoff_zbl.h /pair_tip4p_cut.cpp /pair_tip4p_cut.h /pair_tip4p_long.cpp /pair_tip4p_long.h /pair_tip4p_long_soft.cpp /pair_tip4p_long_soft.h /pair_tri_lj.cpp /pair_tri_lj.h /pair_yukawa_colloid.cpp /pair_yukawa_colloid.h /pair_momb.cpp /pair_momb.h /pppm.cpp /pppm.h /pppm_cg.cpp /pppm_cg.h /pppm_disp.cpp /pppm_disp.h /pppm_disp_tip4p.cpp /pppm_disp_tip4p.h /pppm_old.cpp /pppm_old.h /pppm_proxy.cpp /pppm_proxy.h /pppm_stagger.cpp /pppm_stagger.h /pppm_tip4p.cpp /pppm_tip4p.h /pppm_tip4p_proxy.cpp /pppm_tip4p_proxy.h /pppm_tip4p_cg.cpp /pppm_tip4p_cg.h /prd.cpp /prd.h /python_impl.cpp /python_impl.h /python_compat.h /fix_python.cpp /fix_python.h /pair_python.cpp /pair_python.h /reader_molfile.cpp /reader_molfile.h /reaxc_allocate.cpp /reaxc_allocate.h /reaxc_basic_comm.cpp /reaxc_basic_comm.h /reaxc_bond_orders.cpp /reaxc_bond_orders.h /reaxc_bonds.cpp /reaxc_bonds.h /reaxc_control.cpp /reaxc_control.h /reaxc_defs.h /reaxc_ffield.cpp /reaxc_ffield.h /reaxc_forces.cpp /reaxc_forces.h /reaxc_hydrogen_bonds.cpp /reaxc_hydrogen_bonds.h /reaxc_init_md.cpp /reaxc_init_md.h /reaxc_io_tools.cpp /reaxc_io_tools.h /reaxc_list.cpp /reaxc_list.h /reaxc_lookup.cpp /reaxc_lookup.h /reaxc_multi_body.cpp /reaxc_multi_body.h /reaxc_nonbonded.cpp /reaxc_nonbonded.h /reaxc_reset_tools.cpp /reaxc_reset_tools.h /reaxc_system_props.cpp /reaxc_system_props.h /reaxc_tool_box.cpp /reaxc_tool_box.h /reaxc_torsion_angles.cpp /reaxc_torsion_angles.h /reaxc_traj.cpp /reaxc_traj.h /reaxc_types.h /reaxc_valence_angles.cpp /reaxc_valence_angles.h /reaxc_vector.cpp /reaxc_vector.h /remap.cpp /remap.h /remap_wrap.cpp /remap_wrap.h /restart_mpiio.cpp /restart_mpiio.h /smd_kernels.h /smd_material_models.cpp /smd_material_models.h /smd_math.h /tad.cpp /tad.h /temper.cpp /temper.h /temper_grem.cpp /temper_grem.h /thr_data.cpp /thr_data.h /verlet_split.cpp /verlet_split.h /write_dump.cpp /write_dump.h /xdr_compat.cpp /xdr_compat.h /atom_vec_smd.cpp /atom_vec_smd.h /compute_saed.cpp /compute_saed.h /compute_saed_consts.h /compute_smd_contact_radius.cpp /compute_smd_contact_radius.h /compute_smd_damage.cpp /compute_smd_damage.h /compute_smd_hourglass_error.cpp /compute_smd_hourglass_error.h /compute_smd_internal_energy.cpp /compute_smd_internal_energy.h /compute_smd_plastic_strain.cpp /compute_smd_plastic_strain.h /compute_smd_plastic_strain_rate.cpp /compute_smd_plastic_strain_rate.h /compute_smd_rho.cpp /compute_smd_rho.h /compute_smd_tlsph_defgrad.cpp /compute_smd_tlsph_defgrad.h /compute_smd_tlsph_dt.cpp /compute_smd_tlsph_dt.h /compute_smd_tlsph_num_neighs.cpp /compute_smd_tlsph_num_neighs.h /compute_smd_tlsph_shape.cpp /compute_smd_tlsph_shape.h /compute_smd_tlsph_strain.cpp /compute_smd_tlsph_strain.h /compute_smd_tlsph_strain_rate.cpp /compute_smd_tlsph_strain_rate.h /compute_smd_tlsph_stress.cpp /compute_smd_tlsph_stress.h /compute_smd_triangle_mesh_vertices.cpp /compute_smd_triangle_mesh_vertices.h /compute_smd_ulsph_effm.cpp /compute_smd_ulsph_effm.h /compute_smd_ulsph_num_neighs.cpp /compute_smd_ulsph_num_neighs.h /compute_smd_ulsph_strain.cpp /compute_smd_ulsph_strain.h /compute_smd_ulsph_strain_rate.cpp /compute_smd_ulsph_strain_rate.h /compute_smd_ulsph_stress.cpp /compute_smd_ulsph_stress.h /compute_smd_vol.cpp /compute_smd_vol.h /compute_temp_cs.cpp /compute_temp_cs.h /compute_temp_drude.cpp /compute_temp_drude.h /compute_xrd.cpp /compute_xrd.h /compute_xrd_consts.h /fix_atom_swap.cpp /fix_atom_swap.h /fix_ave_spatial_sphere.cpp /fix_ave_spatial_sphere.h /fix_drude.cpp /fix_drude.h /fix_drude_transform.cpp /fix_drude_transform.h /fix_langevin_drude.cpp /fix_langevin_drude.h /fix_pimd.cpp /fix_pimd.h /fix_qbmsst.cpp /fix_qbmsst.h /fix_qtb.cpp /fix_qtb.h /fix_rattle.cpp /fix_rattle.h /fix_saed_vtk.cpp /fix_saed_vtk.h /fix_smd_adjust_dt.cpp /fix_smd_adjust_dt.h /fix_smd_integrate_tlsph.cpp /fix_smd_integrate_tlsph.h /fix_smd_integrate_ulsph.cpp /fix_smd_integrate_ulsph.h /fix_smd_move_triangulated_surface.cpp /fix_smd_move_triangulated_surface.h /fix_smd_setvel.cpp /fix_smd_setvel.h /fix_smd_tlsph_reference_configuration.cpp /fix_smd_tlsph_reference_configuration.h /fix_smd_wall_surface.cpp /fix_smd_wall_surface.h /fix_srp.cpp /fix_srp.h /fix_tfmc.cpp /fix_tfmc.h /fix_ttm_mod.cpp /fix_ttm_mod.h /pair_born_coul_long_cs.cpp /pair_born_coul_long_cs.h /pair_born_coul_dsf_cs.cpp /pair_born_coul_dsf_cs.h /pair_buck_coul_long_cs.cpp /pair_buck_coul_long_cs.h /pair_coul_long_cs.cpp /pair_coul_long_cs.h /pair_lj_cut_thole_long.cpp /pair_lj_cut_thole_long.h /pair_plum_hb.cpp /pair_plum_hb.h /pair_plum_hp.cpp /pair_plum_hp.h /pair_polymorphic.cpp /pair_polymorphic.h /pair_smd_hertz.cpp /pair_smd_hertz.h /pair_smd_tlsph.cpp /pair_smd_tlsph.h /pair_smd_triangulated_surface.cpp /pair_smd_triangulated_surface.h /pair_smd_ulsph.cpp /pair_smd_ulsph.h /pair_srp.cpp /pair_srp.h /pair_thole.cpp /pair_thole.h /pair_buck_mdf.cpp /pair_buck_mdf.h /pair_dpd_conservative.cpp /pair_dpd_conservative.h /pair_dpd_fdt.cpp /pair_dpd_fdt.h /pair_dpd_fdt_energy.cpp /pair_dpd_fdt_energy.h /pair_lennard_mdf.cpp /pair_lennard_mdf.h /pair_lj_cut_coul_long_cs.cpp /pair_lj_cut_coul_long_cs.h /pair_lj_mdf.cpp /pair_lj_mdf.h /pair_mgpt.cpp /pair_mgpt.h /pair_morse_smooth_linear.cpp /pair_morse_smooth_linear.h /pair_smtbq.cpp /pair_smtbq.h /pair_vashishta*.cpp /pair_vashishta*.h diff --git a/src/Makefile b/src/Makefile index c7b20dcb1..3d1085e0b 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,383 +1,384 @@ # LAMMPS multiple-machine -*- Makefile -*- SHELL = /bin/bash PYTHON = python #.IGNORE: # Definitions ROOT = lmp EXE = lmp_$@ ARLIB = liblammps_$@.a SHLIB = liblammps_$@.so ARLINK = liblammps.a SHLINK = liblammps.so OBJDIR = Obj_$@ OBJSHDIR = Obj_shared_$@ SRC = $(wildcard *.cpp) INC = $(wildcard *.h) OBJ = $(SRC:.cpp=.o) SRCLIB = $(filter-out main.cpp,$(SRC)) OBJLIB = $(filter-out main.o,$(OBJ)) # Command-line options for mode: exe (default), shexe, lib, shlib mode = exe objdir = $(OBJDIR) ifeq ($(mode),shexe) objdir = $(OBJSHDIR) endif ifeq ($(mode),lib) objdir = $(OBJDIR) endif ifeq ($(mode),shlib) objdir = $(OBJSHDIR) endif # Package variables # PACKAGE = standard packages # PACKUSER = user packagse # PACKLIB = all packages that require an additional lib # should be PACKSYS + PACKINT + PACKEXT # PACKSYS = subset that reqiure a common system library # include MPIIO and LB b/c require full MPI, not just STUBS # PACKINT = subset that require an internal (provided) library # PACKEXT = subset that require an external (downloaded) library PACKAGE = asphere body class2 colloid compress coreshell dipole gpu \ granular kim kokkos kspace manybody mc meam misc molecule \ mpiio mscg opt peri poems \ python qeq reax replica rigid shock snap srd voronoi PACKUSER = user-atc user-awpmd user-cgdna user-cgsdk user-colvars \ user-diffraction user-dpd user-drude user-eff user-fep user-h5md \ user-intel user-lb user-manifold user-meamc user-mgpt user-misc user-molfile \ user-netcdf user-omp user-phonon user-qmmm user-qtb \ user-quip user-reaxc user-smd user-smtbq user-sph user-tally \ user-vtk PACKLIB = compress gpu kim kokkos meam mpiio mscg poems \ python reax voronoi \ user-atc user-awpmd user-colvars user-h5md user-lb user-molfile \ user-netcdf user-qmmm user-quip user-smd user-vtk PACKSYS = compress mpiio python user-lb PACKINT = gpu kokkos meam poems reax user-atc user-awpmd user-colvars PACKEXT = kim mscg voronoi \ user-h5md user-molfile user-netcdf user-qmmm user-quip \ user-smd user-vtk PACKALL = $(PACKAGE) $(PACKUSER) PACKAGEUC = $(shell echo $(PACKAGE) | tr a-z A-Z) PACKUSERUC = $(shell echo $(PACKUSER) | tr a-z A-Z) YESDIR = $(shell echo $(@:yes-%=%) | tr a-z A-Z) NODIR = $(shell echo $(@:no-%=%) | tr a-z A-Z) LIBDIR = $(shell echo $(@:lib-%=%)) LIBUSERDIR = $(shell echo $(@:lib-user-%=%)) # List of all targets help: @echo '' @echo 'make clean-all delete all object files' @echo 'make clean-machine delete object files for one machine' @echo 'make mpi-stubs build dummy MPI library in STUBS' @echo 'make install-python install LAMMPS wrapper in Python' @echo 'make tar create lmp_src.tar.gz for src dir and packages' @echo '' @echo 'make package list available packages and their dependencies' @echo 'make package-status (ps) status of all packages' @echo 'make yes-package install a single pgk in src dir' @echo 'make no-package remove a single pkg from src dir' @echo 'make yes-all install all pgks in src dir' @echo 'make no-all remove all pkgs from src dir' @echo 'make yes-standard (yes-std) install all standard pkgs' @echo 'make no-standard (no-std) remove all standard pkgs' @echo 'make yes-user install all user pkgs' @echo 'make no-user remove all user pkgs' @echo 'make yes-lib install all pkgs with libs (included or ext)' @echo 'make no-lib remove all pkgs with libs (included or ext)' @echo 'make yes-ext install all pkgs with external libs' @echo 'make no-ext remove all pkgs with external libs' @echo '' @echo 'make package-update (pu) replace src files with updated package files' @echo 'make package-overwrite replace package files with src files' @echo 'make package-diff (pd) diff src files against package files' @echo '' - @echo 'make lib-package download/build/install a package library' + @echo 'make lib-package help for download/build/install a package library' + @echo 'make lib-package args="..." download/build/install a package library' @echo 'make purge purge obsolete copies of source files' @echo '' @echo 'make machine build LAMMPS for machine' @echo 'make mode=lib machine build LAMMPS as static lib for machine' @echo 'make mode=shlib machine build LAMMPS as shared lib for machine' @echo 'make mode=shexe machine build LAMMPS as shared exe for machine' @echo 'make makelist create Makefile.list used by old makes' @echo 'make -f Makefile.list machine build LAMMPS for machine (old)' @echo '' @echo 'machine is one of these from src/MAKE:' @echo '' @files="`ls MAKE/Makefile.*`"; \ for file in $$files; do head -1 $$file; done @echo '' @echo '... or one of these from src/MAKE/OPTIONS:' @echo '' @files="`ls MAKE/OPTIONS/Makefile.*`"; \ for file in $$files; do head -1 $$file; done @echo '' @echo '... or one of these from src/MAKE/MACHINES:' @echo '' @files="`ls MAKE/MACHINES/Makefile.*`"; \ for file in $$files; do head -1 $$file; done @echo '' @echo '... or one of these from src/MAKE/MINE:' @echo '' @files="`ls MAKE/MINE/Makefile.* 2>/dev/null`"; \ for file in $$files; do head -1 $$file; done @echo '' # Build LAMMPS in one of 4 modes # exe = exe with static compile in Obj_machine (default) # shexe = exe with shared compile in Obj_shared_machine # lib = static lib in Obj_machine # shlib = shared lib in Obj_shared_machine .DEFAULT: @if [ $@ = "serial" -a ! -f STUBS/libmpi_stubs.a ]; \ then $(MAKE) mpi-stubs; fi @test -f MAKE/Makefile.$@ -o -f MAKE/OPTIONS/Makefile.$@ -o \ -f MAKE/MACHINES/Makefile.$@ -o -f MAKE/MINE/Makefile.$@ @if [ ! -d $(objdir) ]; then mkdir $(objdir); fi @$(SHELL) Make.sh style @if [ -f MAKE/MACHINES/Makefile.$@ ]; \ then cp MAKE/MACHINES/Makefile.$@ $(objdir)/Makefile; fi @if [ -f MAKE/OPTIONS/Makefile.$@ ]; \ then cp MAKE/OPTIONS/Makefile.$@ $(objdir)/Makefile; fi @if [ -f MAKE/Makefile.$@ ]; \ then cp MAKE/Makefile.$@ $(objdir)/Makefile; fi @if [ -f MAKE/MINE/Makefile.$@ ]; \ then cp MAKE/MINE/Makefile.$@ $(objdir)/Makefile; fi @if [ ! -e Makefile.package ]; \ then cp Makefile.package.empty Makefile.package; fi @if [ ! -e Makefile.package.settings ]; \ then cp Makefile.package.settings.empty Makefile.package.settings; fi @cp Makefile.package Makefile.package.settings $(objdir) @cd $(objdir); rm -f .depend; \ $(MAKE) $(MFLAGS) "SRC = $(SRC)" "INC = $(INC)" depend || : ifeq ($(mode),exe) @cd $(objdir); \ $(MAKE) $(MFLAGS) "OBJ = $(OBJ)" "INC = $(INC)" "SHFLAGS =" \ "EXE = ../$(EXE)" ../$(EXE) endif ifeq ($(mode),shexe) @cd $(objdir); \ $(MAKE) $(MFLAGS) "OBJ = $(OBJ)" "INC = $(INC)" \ "EXE = ../$(EXE)" ../$(EXE) endif ifeq ($(mode),lib) @cd $(objdir); \ $(MAKE) $(MFLAGS) "OBJ = $(OBJLIB)" "INC = $(INC)" "SHFLAGS =" \ "EXE = ../$(ARLIB)" lib @rm -f $(ARLINK) @ln -s $(ARLIB) $(ARLINK) endif ifeq ($(mode),shlib) @cd $(objdir); \ $(MAKE) $(MFLAGS) "OBJ = $(OBJLIB)" "INC = $(INC)" \ "EXE = ../$(SHLIB)" shlib @rm -f $(SHLINK) @ln -s $(SHLIB) $(SHLINK) endif # Remove machine-specific object files clean: @echo 'make clean-all delete all object files' @echo 'make clean-machine delete object files for one machine' clean-all: rm -rf Obj_* clean-%: rm -rf Obj_$(@:clean-%=%) Obj_shared_$(@:clean-%=%) # Create Makefile.list makelist: @$(SHELL) Make.sh style @$(SHELL) Make.sh Makefile.list # Make MPI STUBS library mpi-stubs: @cd STUBS; $(MAKE) clean; $(MAKE) # install LAMMPS shared lib and Python wrapper for Python usage # include python package settings to # automatically adapt name of python interpreter sinclude ../lib/python/Makefile.lammps install-python: @$(PYTHON) ../python/install.py # Create a tarball of src dir and packages tar: @cd STUBS; $(MAKE) clean @cd ..; tar cvzf src/$(ROOT)_src.tar.gz \ src/Make* src/Package.sh src/Depend.sh src/Install.sh \ src/MAKE src/DEPEND src/*.cpp src/*.h src/STUBS \ $(patsubst %,src/%,$(PACKAGEUC)) $(patsubst %,src/%,$(PACKUSERUC)) \ --exclude=*/.svn @cd STUBS; $(MAKE) @echo "Created $(ROOT)_src.tar.gz" # Package management package: @echo 'Standard packages:' $(PACKAGE) @echo '' @echo 'User-contributed packages:' $(PACKUSER) @echo '' @echo 'Packages that need system libraries:' $(PACKSYS) @echo '' @echo 'Packages that need provided libraries:' $(PACKINT) @echo '' @echo 'Packages that need external libraries:' $(PACKEXT) @echo '' @echo 'make package list available packages' @echo 'make package list available packages' @echo 'make package-status (ps) status of all packages' @echo 'make yes-package install a single pgk in src dir' @echo 'make no-package remove a single pkg from src dir' @echo 'make yes-all install all pgks in src dir' @echo 'make no-all remove all pkgs from src dir' @echo 'make yes-standard (yes-std) install all standard pkgs' @echo 'make no-standard (no-srd) remove all standard pkgs' @echo 'make yes-user install all user pkgs' @echo 'make no-user remove all user pkgs' @echo 'make yes-lib install all pkgs with libs (included or ext)' @echo 'make no-lib remove all pkgs with libs (included or ext)' @echo 'make yes-ext install all pkgs with external libs' @echo 'make no-ext remove all pkgs with external libs' @echo '' @echo 'make package-update (pu) replace src files with package files' @echo 'make package-overwrite replace package files with src files' @echo 'make package-diff (pd) diff src files against package file' @echo '' @echo 'make lib-package build and/or download a package library' yes-all: @for p in $(PACKALL); do $(MAKE) yes-$$p; done no-all: @for p in $(PACKALL); do $(MAKE) no-$$p; done yes-standard yes-std: @for p in $(PACKAGE); do $(MAKE) yes-$$p; done no-standard no-std: @for p in $(PACKAGE); do $(MAKE) no-$$p; done yes-user: @for p in $(PACKUSER); do $(MAKE) yes-$$p; done no-user: @for p in $(PACKUSER); do $(MAKE) no-$$p; done yes-lib: @for p in $(PACKLIB); do $(MAKE) yes-$$p; done no-lib: @for p in $(PACKLIB); do $(MAKE) no-$$p; done yes-ext: @for p in $(PACKEXT); do $(MAKE) yes-$$p; done no-ext: @for p in $(PACKEXT); do $(MAKE) no-$$p; done yes-%: @if [ ! -e Makefile.package ]; \ then cp Makefile.package.empty Makefile.package; fi @if [ ! -e Makefile.package.settings ]; \ then cp Makefile.package.settings.empty Makefile.package.settings; fi @if [ ! -e $(YESDIR) ]; then \ echo "Package $(@:yes-%=%) does not exist"; \ elif [ -e $(YESDIR)/Install.sh ]; then \ echo "Installing package $(@:yes-%=%)"; \ cd $(YESDIR); $(SHELL) Install.sh 1; cd ..; \ $(SHELL) Depend.sh $(YESDIR) 1; \ else \ echo "Installing package $(@:yes-%=%)"; \ cd $(YESDIR); $(SHELL) ../Install.sh 1; cd ..; \ $(SHELL) Depend.sh $(YESDIR) 1; \ fi; no-%: @if [ ! -e $(NODIR) ]; then \ echo "Package $(@:no-%=%) does not exist"; \ elif [ -e $(NODIR)/Install.sh ]; then \ echo "Uninstalling package $(@:no-%=%)"; \ cd $(NODIR); $(SHELL) Install.sh 0; cd ..; \ $(SHELL) Depend.sh $(NODIR) 0; \ else \ echo "Uninstalling package $(@:no-%=%)"; \ cd $(NODIR); $(SHELL) ../Install.sh 0; cd ..; \ $(SHELL) Depend.sh $(NODIR) 0; \ fi; # download/build/install a package library lib-%: @if [ -e ../lib/$(LIBDIR)/Install.py ]; then \ echo "Installing lib $(@:lib-%=%)"; \ cd ../lib/$(LIBDIR); python Install.py $(args); \ elif [ -e ../lib/$(LIBUSERDIR)/Install.py ]; then \ echo "Installing lib $(@:lib-user-%=%)"; \ cd ../lib/$(LIBUSERDIR); python Install.py $(args); \ else \ echo "Install script for lib $(@:lib-%=%) does not exist"; \ fi; # status = list src files that differ from package files # update = replace src files with newer package files # overwrite = overwrite package files with newer src files # diff = show differences between src and package files # purge = delete obsolete and auto-generated package files package-status ps: @for p in $(PACKAGEUC); do $(SHELL) Package.sh $$p status; done @echo '' @for p in $(PACKUSERUC); do $(SHELL) Package.sh $$p status; done package-update pu: @for p in $(PACKAGEUC); do $(SHELL) Package.sh $$p update; done @echo '' @for p in $(PACKUSERUC); do $(SHELL) Package.sh $$p update; done package-overwrite: @for p in $(PACKAGEUC); do $(SHELL) Package.sh $$p overwrite; done @echo '' @for p in $(PACKUSERUC); do $(SHELL) Package.sh $$p overwrite; done package-diff pd: @for p in $(PACKAGEUC); do $(SHELL) Package.sh $$p diff; done @echo '' @for p in $(PACKUSERUC); do $(SHELL) Package.sh $$p diff; done purge: Purge.list @echo 'Purging obsolete and auto-generated source files' @for f in `grep -v '#' Purge.list` ; \ do test -f $$f && rm $$f && echo $$f || : ; \ done diff --git a/src/balance.cpp b/src/balance.cpp index c184a72d3..8f994466a 100644 --- a/src/balance.cpp +++ b/src/balance.cpp @@ -1,1337 +1,1337 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain 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, for weighted balancing: Axel Kohlmeyer (Temple U), Iain Bethune (EPCC) ------------------------------------------------------------------------- */ //#define BALANCE_DEBUG 1 #include #include #include #include #include "balance.h" #include "atom.h" #include "comm.h" #include "rcb.h" #include "irregular.h" #include "domain.h" #include "force.h" #include "update.h" #include "group.h" #include "modify.h" #include "fix_store.h" #include "imbalance.h" #include "imbalance_group.h" #include "imbalance_time.h" #include "imbalance_neigh.h" #include "imbalance_store.h" #include "imbalance_var.h" #include "timer.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; enum{XYZ,SHIFT,BISECTION}; enum{NONE,UNIFORM,USER}; enum{X,Y,Z}; enum{LAYOUT_UNIFORM,LAYOUT_NONUNIFORM,LAYOUT_TILED}; // several files /* ---------------------------------------------------------------------- */ Balance::Balance(LAMMPS *lmp) : Pointers(lmp) { MPI_Comm_rank(world,&me); MPI_Comm_size(world,&nprocs); user_xsplit = user_ysplit = user_zsplit = NULL; shift_allocate = 0; proccost = allproccost = NULL; rcb = NULL; nimbalance = 0; imbalances = NULL; fixstore = NULL; fp = NULL; firststep = 1; } /* ---------------------------------------------------------------------- */ Balance::~Balance() { memory->destroy(proccost); memory->destroy(allproccost); delete [] user_xsplit; delete [] user_ysplit; delete [] user_zsplit; if (shift_allocate) { delete [] bdim; delete [] onecost; delete [] allcost; delete [] sum; delete [] target; delete [] lo; delete [] hi; delete [] losum; delete [] hisum; } delete rcb; for (int i = 0; i < nimbalance; i++) delete imbalances[i]; delete [] imbalances; // check nfix in case all fixes have already been deleted if (fixstore && modify->nfix) modify->delete_fix(fixstore->id); fixstore = NULL; if (fp) fclose(fp); } /* ---------------------------------------------------------------------- called as balance command in input script ------------------------------------------------------------------------- */ void Balance::command(int narg, char **arg) { if (domain->box_exist == 0) error->all(FLERR,"Balance command before simulation box is defined"); if (me == 0 && screen) fprintf(screen,"Balancing ...\n"); // parse required arguments if (narg < 2) error->all(FLERR,"Illegal balance command"); thresh = force->numeric(FLERR,arg[0]); int dimension = domain->dimension; int *procgrid = comm->procgrid; style = -1; xflag = yflag = zflag = NONE; int iarg = 1; while (iarg < narg) { if (strcmp(arg[iarg],"x") == 0) { if (style != -1 && style != XYZ) error->all(FLERR,"Illegal balance command"); style = XYZ; if (strcmp(arg[iarg+1],"uniform") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal balance command"); xflag = UNIFORM; iarg += 2; } else { if (1 + procgrid[0]-1 > narg) error->all(FLERR,"Illegal balance command"); xflag = USER; delete [] user_xsplit; user_xsplit = new double[procgrid[0]+1]; user_xsplit[0] = 0.0; iarg++; for (int i = 1; i < procgrid[0]; i++) user_xsplit[i] = force->numeric(FLERR,arg[iarg++]); user_xsplit[procgrid[0]] = 1.0; } } else if (strcmp(arg[iarg],"y") == 0) { if (style != -1 && style != XYZ) error->all(FLERR,"Illegal balance command"); style = XYZ; if (strcmp(arg[iarg+1],"uniform") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal balance command"); yflag = UNIFORM; iarg += 2; } else { if (1 + procgrid[1]-1 > narg) error->all(FLERR,"Illegal balance command"); yflag = USER; delete [] user_ysplit; user_ysplit = new double[procgrid[1]+1]; user_ysplit[0] = 0.0; iarg++; for (int i = 1; i < procgrid[1]; i++) user_ysplit[i] = force->numeric(FLERR,arg[iarg++]); user_ysplit[procgrid[1]] = 1.0; } } else if (strcmp(arg[iarg],"z") == 0) { if (style != -1 && style != XYZ) error->all(FLERR,"Illegal balance command"); style = XYZ; if (strcmp(arg[iarg+1],"uniform") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal balance command"); zflag = UNIFORM; iarg += 2; } else { if (1 + procgrid[2]-1 > narg) error->all(FLERR,"Illegal balance command"); zflag = USER; delete [] user_zsplit; user_zsplit = new double[procgrid[2]+1]; user_zsplit[0] = 0.0; iarg++; for (int i = 1; i < procgrid[2]; i++) user_zsplit[i] = force->numeric(FLERR,arg[iarg++]); user_zsplit[procgrid[2]] = 1.0; } } else if (strcmp(arg[iarg],"shift") == 0) { if (style != -1) error->all(FLERR,"Illegal balance command"); if (iarg+4 > narg) error->all(FLERR,"Illegal balance command"); style = SHIFT; if (strlen(arg[iarg+1]) > 3) error->all(FLERR,"Illegal balance command"); strcpy(bstr,arg[iarg+1]); nitermax = force->inumeric(FLERR,arg[iarg+2]); if (nitermax <= 0) error->all(FLERR,"Illegal balance command"); stopthresh = force->numeric(FLERR,arg[iarg+3]); if (stopthresh < 1.0) error->all(FLERR,"Illegal balance command"); iarg += 4; } else if (strcmp(arg[iarg],"rcb") == 0) { if (style != -1) error->all(FLERR,"Illegal balance command"); style = BISECTION; iarg++; } else break; } // error checks if (style == XYZ) { if (zflag != NONE && dimension == 2) error->all(FLERR,"Cannot balance in z dimension for 2d simulation"); if (xflag == USER) for (int i = 1; i <= procgrid[0]; i++) if (user_xsplit[i-1] >= user_xsplit[i]) error->all(FLERR,"Illegal balance command"); if (yflag == USER) for (int i = 1; i <= procgrid[1]; i++) if (user_ysplit[i-1] >= user_ysplit[i]) error->all(FLERR,"Illegal balance command"); if (zflag == USER) for (int i = 1; i <= procgrid[2]; i++) if (user_zsplit[i-1] >= user_zsplit[i]) error->all(FLERR,"Illegal balance command"); } if (style == SHIFT) { const int blen=strlen(bstr); for (int i = 0; i < blen; i++) { if (bstr[i] != 'x' && bstr[i] != 'y' && bstr[i] != 'z') error->all(FLERR,"Balance shift string is invalid"); if (bstr[i] == 'z' && dimension == 2) error->all(FLERR,"Balance shift string is invalid"); for (int j = i+1; j < blen; j++) if (bstr[i] == bstr[j]) error->all(FLERR,"Balance shift string is invalid"); } } if (style == BISECTION && comm->style == 0) error->all(FLERR,"Balance rcb cannot be used with comm_style brick"); // process remaining optional args options(iarg,narg,arg); if (wtflag) weight_storage(NULL); // insure particles are in current box & update box via shrink-wrap // init entire system since comm->setup is done // comm::init needs neighbor::init needs pair::init needs kspace::init, etc // must reset atom map after exchange() since it clears it MPI_Barrier(world); double start_time = MPI_Wtime(); lmp->init(); if (domain->triclinic) domain->x2lamda(atom->nlocal); domain->pbc(); domain->reset_box(); comm->setup(); comm->exchange(); if (atom->map_style) atom->map_set(); if (domain->triclinic) domain->lamda2x(atom->nlocal); // imbinit = initial imbalance double maxinit; init_imbalance(0); set_weights(); double imbinit = imbalance_factor(maxinit); // no load-balance if imbalance doesn't exceed threshold // unless switching from tiled to non tiled layout, then force rebalance if (comm->layout == LAYOUT_TILED && style != BISECTION) { } else if (imbinit < thresh) return; // debug output of initial state #ifdef BALANCE_DEBUG if (outflag) dumpout(update->ntimestep); #endif int niter = 0; // perform load-balance // style XYZ = explicit setting of cutting planes of logical 3d grid if (style == XYZ) { if (comm->layout == LAYOUT_UNIFORM) { if (xflag == USER || yflag == USER || zflag == USER) comm->layout = LAYOUT_NONUNIFORM; } else if (comm->style == LAYOUT_NONUNIFORM) { if (xflag == UNIFORM && yflag == UNIFORM && zflag == UNIFORM) comm->layout = LAYOUT_UNIFORM; } else if (comm->style == LAYOUT_TILED) { if (xflag == UNIFORM && yflag == UNIFORM && zflag == UNIFORM) comm->layout = LAYOUT_UNIFORM; else comm->layout = LAYOUT_NONUNIFORM; } if (xflag == UNIFORM) { for (int i = 0; i < procgrid[0]; i++) comm->xsplit[i] = i * 1.0/procgrid[0]; comm->xsplit[procgrid[0]] = 1.0; } else if (xflag == USER) for (int i = 0; i <= procgrid[0]; i++) comm->xsplit[i] = user_xsplit[i]; if (yflag == UNIFORM) { for (int i = 0; i < procgrid[1]; i++) comm->ysplit[i] = i * 1.0/procgrid[1]; comm->ysplit[procgrid[1]] = 1.0; } else if (yflag == USER) for (int i = 0; i <= procgrid[1]; i++) comm->ysplit[i] = user_ysplit[i]; if (zflag == UNIFORM) { for (int i = 0; i < procgrid[2]; i++) comm->zsplit[i] = i * 1.0/procgrid[2]; comm->zsplit[procgrid[2]] = 1.0; } else if (zflag == USER) for (int i = 0; i <= procgrid[2]; i++) comm->zsplit[i] = user_zsplit[i]; } // style SHIFT = adjust cutting planes of logical 3d grid if (style == SHIFT) { comm->layout = LAYOUT_NONUNIFORM; shift_setup_static(bstr); niter = shift(); } // style BISECTION = recursive coordinate bisectioning if (style == BISECTION) { comm->layout = LAYOUT_TILED; bisection(1); } // reset proc sub-domains // for either brick or tiled comm style if (domain->triclinic) domain->set_lamda_box(); domain->set_local_box(); // move particles to new processors via irregular() if (domain->triclinic) domain->x2lamda(atom->nlocal); Irregular *irregular = new Irregular(lmp); if (wtflag) fixstore->disable = 0; if (style == BISECTION) irregular->migrate_atoms(1,1,rcb->sendproc); else irregular->migrate_atoms(1); if (wtflag) fixstore->disable = 1; delete irregular; if (domain->triclinic) domain->lamda2x(atom->nlocal); // output of final result if (outflag) dumpout(update->ntimestep); // check if any particles were lost bigint natoms; bigint nblocal = atom->nlocal; MPI_Allreduce(&nblocal,&natoms,1,MPI_LMP_BIGINT,MPI_SUM,world); if (natoms != atom->natoms) { char str[128]; sprintf(str,"Lost atoms via balance: original " BIGINT_FORMAT " current " BIGINT_FORMAT,atom->natoms,natoms); error->all(FLERR,str); } // imbfinal = final imbalance double maxfinal; double imbfinal = imbalance_factor(maxfinal); // stats output double stop_time = MPI_Wtime(); if (me == 0) { if (screen) { fprintf(screen," rebalancing time: %g seconds\n",stop_time-start_time); fprintf(screen," iteration count = %d\n",niter); for (int i = 0; i < nimbalance; ++i) imbalances[i]->info(screen); fprintf(screen," initial/final max load/proc = %g %g\n", maxinit,maxfinal); fprintf(screen," initial/final imbalance factor = %g %g\n", imbinit,imbfinal); } if (logfile) { fprintf(logfile," rebalancing time: %g seconds\n",stop_time-start_time); fprintf(logfile," iteration count = %d\n",niter); for (int i = 0; i < nimbalance; ++i) imbalances[i]->info(logfile); fprintf(logfile," initial/final max load/proc = %g %g\n", maxinit,maxfinal); fprintf(logfile," initial/final imbalance factor = %g %g\n", imbinit,imbfinal); } } if (style != BISECTION) { if (me == 0) { if (screen) { fprintf(screen," x cuts:"); for (int i = 0; i <= comm->procgrid[0]; i++) fprintf(screen," %g",comm->xsplit[i]); fprintf(screen,"\n"); fprintf(screen," y cuts:"); for (int i = 0; i <= comm->procgrid[1]; i++) fprintf(screen," %g",comm->ysplit[i]); fprintf(screen,"\n"); fprintf(screen," z cuts:"); for (int i = 0; i <= comm->procgrid[2]; i++) fprintf(screen," %g",comm->zsplit[i]); fprintf(screen,"\n"); } if (logfile) { fprintf(logfile," x cuts:"); for (int i = 0; i <= comm->procgrid[0]; i++) fprintf(logfile," %g",comm->xsplit[i]); fprintf(logfile,"\n"); fprintf(logfile," y cuts:"); for (int i = 0; i <= comm->procgrid[1]; i++) fprintf(logfile," %g",comm->ysplit[i]); fprintf(logfile,"\n"); fprintf(logfile," z cuts:"); for (int i = 0; i <= comm->procgrid[2]; i++) fprintf(logfile," %g",comm->zsplit[i]); fprintf(logfile,"\n"); } } } } /* ---------------------------------------------------------------------- process optional command args for Balance and FixBalance ------------------------------------------------------------------------- */ void Balance::options(int iarg, int narg, char **arg) { // count max number of weight settings nimbalance = 0; for (int i = iarg; i < narg; i++) if (strcmp(arg[i],"weight") == 0) nimbalance++; if (nimbalance) imbalances = new Imbalance*[nimbalance]; nimbalance = 0; wtflag = 0; varflag = 0; oldrcb = 0; outflag = 0; int outarg = 0; fp = NULL; while (iarg < narg) { if (strcmp(arg[iarg],"weight") == 0) { wtflag = 1; Imbalance *imb; int nopt = 0; if (strcmp(arg[iarg+1],"group") == 0) { imb = new ImbalanceGroup(lmp); nopt = imb->options(narg-iarg,arg+iarg+2); imbalances[nimbalance++] = imb; } else if (strcmp(arg[iarg+1],"time") == 0) { imb = new ImbalanceTime(lmp); nopt = imb->options(narg-iarg,arg+iarg+2); imbalances[nimbalance++] = imb; } else if (strcmp(arg[iarg+1],"neigh") == 0) { imb = new ImbalanceNeigh(lmp); nopt = imb->options(narg-iarg,arg+iarg+2); imbalances[nimbalance++] = imb; } else if (strcmp(arg[iarg+1],"var") == 0) { varflag = 1; imb = new ImbalanceVar(lmp); nopt = imb->options(narg-iarg,arg+iarg+2); imbalances[nimbalance++] = imb; } else if (strcmp(arg[iarg+1],"store") == 0) { imb = new ImbalanceStore(lmp); nopt = imb->options(narg-iarg,arg+iarg+2); imbalances[nimbalance++] = imb; } else { error->all(FLERR,"Unknown (fix) balance weight method"); } iarg += 2+nopt; } else if (strcmp(arg[iarg],"old") == 0) { oldrcb = 1; iarg++; } else if (strcmp(arg[iarg],"out") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal (fix) balance command"); outflag = 1; outarg = iarg+1; iarg += 2; } else error->all(FLERR,"Illegal (fix) balance command"); } // output file if (outflag && comm->me == 0) { fp = fopen(arg[outarg],"w"); if (fp == NULL) error->one(FLERR,"Cannot open (fix) balance output file"); } } /* ---------------------------------------------------------------------- allocate per-particle weight storage via FixStore use prefix to distinguish Balance vs FixBalance storage fix could already be allocated if fix balance is re-specified ------------------------------------------------------------------------- */ void Balance::weight_storage(char *prefix) { char *fixargs[6]; if (prefix) { int n = strlen(prefix) + 32; fixargs[0] = new char[n]; strcpy(fixargs[0],prefix); strcat(fixargs[0],"IMBALANCE_WEIGHTS"); } else fixargs[0] = (char *) "IMBALANCE_WEIGHTS"; fixargs[1] = (char *) "all"; fixargs[2] = (char *) "STORE"; fixargs[3] = (char *) "peratom"; fixargs[4] = (char *) "0"; fixargs[5] = (char *) "1"; int ifix = modify->find_fix(fixargs[0]); if (ifix < 1) { modify->add_fix(6,fixargs); fixstore = (FixStore *) modify->fix[modify->nfix-1]; } else fixstore = (FixStore *) modify->fix[ifix]; fixstore->disable = 1; if (prefix) delete [] fixargs[0]; } /* ---------------------------------------------------------------------- invoke init() for each Imbalance class flag = 0 for call from Balance, 1 for call from FixBalance ------------------------------------------------------------------------- */ void Balance::init_imbalance(int flag) { if (!wtflag) return; for (int n = 0; n < nimbalance; n++) imbalances[n]->init(flag); } /* ---------------------------------------------------------------------- set weight for each particle via list of Nimbalance classes ------------------------------------------------------------------------- */ void Balance::set_weights() { if (!wtflag) return; weight = fixstore->vstore; int nlocal = atom->nlocal; for (int i = 0; i < nlocal; i++) weight[i] = 1.0; for (int n = 0; n < nimbalance; n++) imbalances[n]->compute(weight); } /* ---------------------------------------------------------------------- calculate imbalance factor based on particle count or particle weights return max = max load per proc return imbalance = max load per proc / ave load per proc ------------------------------------------------------------------------- */ double Balance::imbalance_factor(double &maxcost) { double mycost,totalcost; if (wtflag) { weight = fixstore->vstore; int nlocal = atom->nlocal; mycost = 0.0; for (int i = 0; i < nlocal; i++) mycost += weight[i]; } else mycost = atom->nlocal; MPI_Allreduce(&mycost,&maxcost,1,MPI_DOUBLE,MPI_MAX,world); MPI_Allreduce(&mycost,&totalcost,1,MPI_DOUBLE,MPI_SUM,world); double imbalance = 1.0; if (maxcost > 0.0) imbalance = maxcost / (totalcost/nprocs); return imbalance; } /* ---------------------------------------------------------------------- perform balancing via RCB class sortflag = flag for sorting order of received messages by proc ID return list of procs to send my atoms to ------------------------------------------------------------------------- */ int *Balance::bisection(int sortflag) { if (!rcb) rcb = new RCB(lmp); // NOTE: this logic is specific to orthogonal boxes, not triclinic int dim = domain->dimension; double *boxlo = domain->boxlo; double *boxhi = domain->boxhi; double *prd = domain->prd; // shrink-wrap simulation box around atoms for input to RCB // leads to better-shaped sub-boxes when atoms are far from box boundaries double shrink[6],shrinkall[6]; shrink[0] = boxhi[0]; shrink[1] = boxhi[1]; shrink[2] = boxhi[2]; shrink[3] = boxlo[0]; shrink[4] = boxlo[1]; shrink[5] = boxlo[2]; double **x = atom->x; int nlocal = atom->nlocal; for (int i = 0; i < nlocal; i++) { shrink[0] = MIN(shrink[0],x[i][0]); shrink[1] = MIN(shrink[1],x[i][1]); shrink[2] = MIN(shrink[2],x[i][2]); shrink[3] = MAX(shrink[3],x[i][0]); shrink[4] = MAX(shrink[4],x[i][1]); shrink[5] = MAX(shrink[5],x[i][2]); } shrink[3] = -shrink[3]; shrink[4] = -shrink[4]; shrink[5] = -shrink[5]; MPI_Allreduce(shrink,shrinkall,6,MPI_DOUBLE,MPI_MIN,world); shrinkall[3] = -shrinkall[3]; shrinkall[4] = -shrinkall[4]; shrinkall[5] = -shrinkall[5]; double *shrinklo = &shrinkall[0]; double *shrinkhi = &shrinkall[3]; // invoke RCB // then invert() to create list of proc assignments for my atoms // NOTE: (3/2017) can remove undocumented "old" option at some point // ditto in rcb.cpp if (oldrcb) { if (wtflag) { weight = fixstore->vstore; rcb->compute_old(dim,atom->nlocal,atom->x,weight,shrinklo,shrinkhi); } else rcb->compute_old(dim,atom->nlocal,atom->x,NULL,shrinklo,shrinkhi); } else { if (wtflag) { weight = fixstore->vstore; rcb->compute(dim,atom->nlocal,atom->x,weight,shrinklo,shrinkhi); } else rcb->compute(dim,atom->nlocal,atom->x,NULL,shrinklo,shrinkhi); } rcb->invert(sortflag); // reset RCB lo/hi bounding box to full simulation box as needed double *lo = rcb->lo; double *hi = rcb->hi; if (lo[0] == shrinklo[0]) lo[0] = boxlo[0]; if (lo[1] == shrinklo[1]) lo[1] = boxlo[1]; if (lo[2] == shrinklo[2]) lo[2] = boxlo[2]; if (hi[0] == shrinkhi[0]) hi[0] = boxhi[0]; if (hi[1] == shrinkhi[1]) hi[1] = boxhi[1]; if (hi[2] == shrinkhi[2]) hi[2] = boxhi[2]; // store RCB cut, dim, lo/hi box in CommTiled // cut and lo/hi need to be in fractional form so can // OK if changes by epsilon from what RCB used since atoms // will subsequently migrate to new owning procs by exchange() anyway // ditto for atoms exactly on lo/hi RCB box boundaries due to ties comm->rcbnew = 1; int idim = rcb->cutdim; if (idim >= 0) comm->rcbcutfrac = (rcb->cut - boxlo[idim]) / prd[idim]; else comm->rcbcutfrac = 0.0; comm->rcbcutdim = idim; double (*mysplit)[2] = comm->mysplit; mysplit[0][0] = (lo[0] - boxlo[0]) / prd[0]; if (hi[0] == boxhi[0]) mysplit[0][1] = 1.0; else mysplit[0][1] = (hi[0] - boxlo[0]) / prd[0]; mysplit[1][0] = (lo[1] - boxlo[1]) / prd[1]; if (hi[1] == boxhi[1]) mysplit[1][1] = 1.0; else mysplit[1][1] = (hi[1] - boxlo[1]) / prd[1]; mysplit[2][0] = (lo[2] - boxlo[2]) / prd[2]; if (hi[2] == boxhi[2]) mysplit[2][1] = 1.0; else mysplit[2][1] = (hi[2] - boxlo[2]) / prd[2]; // return list of procs to send my atoms to return rcb->sendproc; } /* ---------------------------------------------------------------------- setup static load balance operations called from command and indirectly initially from fix balance set rho = 0 for static balancing ------------------------------------------------------------------------- */ void Balance::shift_setup_static(char *str) { shift_allocate = 1; memory->create(proccost,nprocs,"balance:proccost"); memory->create(allproccost,nprocs,"balance:allproccost"); ndim = strlen(str); bdim = new int[ndim]; for (int i = 0; i < ndim; i++) { if (str[i] == 'x') bdim[i] = X; if (str[i] == 'y') bdim[i] = Y; if (str[i] == 'z') bdim[i] = Z; } int max = MAX(comm->procgrid[0],comm->procgrid[1]); max = MAX(max,comm->procgrid[2]); onecost = new double[max]; allcost = new double[max]; sum = new double[max+1]; target = new double[max+1]; lo = new double[max+1]; hi = new double[max+1]; losum = new double[max+1]; hisum = new double[max+1]; // if current layout is TILED, set initial uniform splits in Comm // this gives starting point to subsequent shift balancing if (comm->layout == LAYOUT_TILED) { int *procgrid = comm->procgrid; double *xsplit = comm->xsplit; double *ysplit = comm->ysplit; double *zsplit = comm->zsplit; for (int i = 0; i < procgrid[0]; i++) xsplit[i] = i * 1.0/procgrid[0]; for (int i = 0; i < procgrid[1]; i++) ysplit[i] = i * 1.0/procgrid[1]; for (int i = 0; i < procgrid[2]; i++) zsplit[i] = i * 1.0/procgrid[2]; xsplit[procgrid[0]] = ysplit[procgrid[1]] = zsplit[procgrid[2]] = 1.0; } rho = 0; } /* ---------------------------------------------------------------------- setup shift load balance operations called from fix balance set rho = 1 to do dynamic balancing after call to shift_setup_static() ------------------------------------------------------------------------- */ void Balance::shift_setup(char *str, int nitermax_in, double thresh_in) { shift_setup_static(str); nitermax = nitermax_in; stopthresh = thresh_in; rho = 1; } /* ---------------------------------------------------------------------- load balance by changing xyz split proc boundaries in Comm called one time from input script command or many times from fix balance return niter = iteration count ------------------------------------------------------------------------- */ int Balance::shift() { - int i,j,k,m,np,max; + int i,j,k,m,np; double mycost,totalcost; double *split; // no balancing if no atoms bigint natoms = atom->natoms; if (natoms == 0) return 0; // set delta for 1d balancing = root of threshold // root = # of dimensions being balanced on double delta = pow(stopthresh,1.0/ndim) - 1.0; int *procgrid = comm->procgrid; // all balancing done in lamda coords domain->x2lamda(atom->nlocal); // loop over dimensions in balance string int niter = 0; for (int idim = 0; idim < ndim; idim++) { // split = ptr to xyz split in Comm if (bdim[idim] == X) split = comm->xsplit; else if (bdim[idim] == Y) split = comm->ysplit; else if (bdim[idim] == Z) split = comm->zsplit; else continue; // initial count and sum np = procgrid[bdim[idim]]; tally(bdim[idim],np,split); // target[i] = desired sum at split I if (wtflag) { weight = fixstore->vstore; int nlocal = atom->nlocal; mycost = 0.0; for (i = 0; i < nlocal; i++) mycost += weight[i]; } else mycost = atom->nlocal; MPI_Allreduce(&mycost,&totalcost,1,MPI_DOUBLE,MPI_SUM,world); for (i = 0; i < np; i++) target[i] = totalcost/np * i; target[np] = totalcost; // lo[i] = closest split <= split[i] with a sum <= target // hi[i] = closest split >= split[i] with a sum >= target lo[0] = hi[0] = 0.0; lo[np] = hi[np] = 1.0; losum[0] = hisum[0] = 0.0; losum[np] = hisum[np] = totalcost; for (i = 1; i < np; i++) { for (j = i; j >= 0; j--) if (sum[j] <= target[i]) { lo[i] = split[j]; losum[i] = sum[j]; break; } for (j = i; j <= np; j++) if (sum[j] >= target[i]) { hi[i] = split[j]; hisum[i] = sum[j]; break; } } // iterate until balanced #ifdef BALANCE_DEBUG if (me == 0) debug_shift_output(idim,0,np,split); #endif int doneflag; int change = 1; for (m = 0; m < nitermax; m++) { change = adjust(np,split); tally(bdim[idim],np,split); niter++; #ifdef BALANCE_DEBUG if (me == 0) debug_shift_output(idim,m+1,np,split); if (outflag) dumpout(update->ntimestep); #endif // stop if no change in splits, b/c all targets are met exactly if (!change) break; // stop if all split sums are within delta of targets // this is a 1d test of particle count per slice // assumption is that this is sufficient accuracy // for 3d imbalance factor to reach threshold doneflag = 1; for (i = 1; i < np; i++) if (fabs(1.0*(sum[i]-target[i]))/target[i] > delta) doneflag = 0; if (doneflag) break; } // eliminate final adjacent splits that are duplicates // can happen if particle distribution is narrow and Nitermax is small // set lo = midpt between splits // spread duplicates out evenly between bounding midpts with non-duplicates // i,j = lo/hi indices of set of duplicate splits // delta = new spacing between duplicates // bounding midpts = lo[i-1] and lo[j] int duplicate = 0; for (i = 1; i < np-1; i++) if (split[i] == split[i+1]) duplicate = 1; if (duplicate) { for (i = 0; i < np; i++) lo[i] = 0.5 * (split[i] + split[i+1]); i = 1; while (i < np-1) { j = i+1; while (split[j] == split[i]) j++; j--; if (j > i) { delta = (lo[j] - lo[i-1]) / (j-i+2); for (k = i; k <= j; k++) split[k] = lo[i-1] + (k-i+1)*delta; } i = j+1; } } // sanity check on bad duplicate or inverted splits // zero or negative width sub-domains will break Comm class // should never happen if recursive multisection algorithm is correct int bad = 0; for (i = 0; i < np; i++) if (split[i] >= split[i+1]) bad = 1; if (bad) error->all(FLERR,"Balance produced bad splits"); /* if (me == 0) { printf("BAD SPLITS %d %d %d\n",np+1,niter,delta); for (i = 0; i < np+1; i++) printf(" %g",split[i]); printf("\n"); } */ // stop at this point in bstr if imbalance factor < threshold // this is a true 3d test of particle count per processor double imbfactor = imbalance_splits(); if (imbfactor <= stopthresh) break; } // restore real coords domain->lamda2x(atom->nlocal); return niter; } /* ---------------------------------------------------------------------- count atoms in each slice, based on their dim coordinate N = # of slices split = N+1 cuts between N slices return updated count = particles per slice return updated sum = cumulative count below each of N+1 splits use binary search to find which slice each atom is in ------------------------------------------------------------------------- */ void Balance::tally(int dim, int n, double *split) { for (int i = 0; i < n; i++) onecost[i] = 0.0; double **x = atom->x; int nlocal = atom->nlocal; int index; if (wtflag) { weight = fixstore->vstore; for (int i = 0; i < nlocal; i++) { index = binary(x[i][dim],n,split); onecost[index] += weight[i]; } } else { for (int i = 0; i < nlocal; i++) { index = binary(x[i][dim],n,split); onecost[index] += 1.0; } } MPI_Allreduce(onecost,allcost,n,MPI_DOUBLE,MPI_SUM,world); sum[0] = 0.0; for (int i = 1; i < n+1; i++) sum[i] = sum[i-1] + allcost[i-1]; } /* ---------------------------------------------------------------------- adjust cuts between N slices in a dim via recursive multisectioning method split = current N+1 cuts, with 0.0 and 1.0 at end points sum = cumulative count up to each split target = desired cumulative count up to each split lo/hi = split values that bound current split update lo/hi to reflect sums at current split values overwrite split with new cuts guaranteed that splits will remain in ascending order, though adjacent values may be identical recursive bisectioning zooms in on each cut by halving lo/hi return 0 if no changes in any splits, b/c they are all perfect ------------------------------------------------------------------------- */ int Balance::adjust(int n, double *split) { int i; double fraction; // reset lo/hi based on current sum and splits // insure lo is monotonically increasing, ties are OK // insure hi is monotonically decreasing, ties are OK // this effectively uses info from nearby splits // to possibly tighten bounds on lo/hi for (i = 1; i < n; i++) { if (sum[i] <= target[i]) { lo[i] = split[i]; losum[i] = sum[i]; } if (sum[i] >= target[i]) { hi[i] = split[i]; hisum[i] = sum[i]; } } for (i = 1; i < n; i++) if (lo[i] < lo[i-1]) { lo[i] = lo[i-1]; losum[i] = losum[i-1]; } for (i = n-1; i > 0; i--) if (hi[i] > hi[i+1]) { hi[i] = hi[i+1]; hisum[i] = hisum[i+1]; } int change = 0; for (int i = 1; i < n; i++) if (sum[i] != target[i]) { change = 1; if (rho == 0) split[i] = 0.5 * (lo[i]+hi[i]); else { fraction = 1.0*(target[i]-losum[i]) / (hisum[i]-losum[i]); split[i] = lo[i] + fraction * (hi[i]-lo[i]); } } return change; } /* ---------------------------------------------------------------------- calculate imbalance based on processor splits in 3 dims atoms must be in lamda coords (0-1) before called map particles to 3d grid of procs return imbalance factor = max load per proc / ave load per proc ------------------------------------------------------------------------- */ double Balance::imbalance_splits() { double *xsplit = comm->xsplit; double *ysplit = comm->ysplit; double *zsplit = comm->zsplit; int nx = comm->procgrid[0]; int ny = comm->procgrid[1]; int nz = comm->procgrid[2]; for (int i = 0; i < nprocs; i++) proccost[i] = 0.0; double **x = atom->x; int nlocal = atom->nlocal; int ix,iy,iz; if (wtflag) { weight = fixstore->vstore; for (int i = 0; i < nlocal; i++) { ix = binary(x[i][0],nx,xsplit); iy = binary(x[i][1],ny,ysplit); iz = binary(x[i][2],nz,zsplit); proccost[iz*nx*ny + iy*nx + ix] += weight[i]; } } else { for (int i = 0; i < nlocal; i++) { ix = binary(x[i][0],nx,xsplit); iy = binary(x[i][1],ny,ysplit); iz = binary(x[i][2],nz,zsplit); proccost[iz*nx*ny + iy*nx + ix] += 1.0; } } // one proc's particles may map to many partitions, so must Allreduce MPI_Allreduce(proccost,allproccost,nprocs,MPI_DOUBLE,MPI_SUM,world); double maxcost = 0.0; double totalcost = 0.0; for (int i = 0; i < nprocs; i++) { maxcost = MAX(maxcost,allproccost[i]); totalcost += allproccost[i]; } double imbalance = 1.0; if (maxcost > 0.0) imbalance = maxcost / (totalcost/nprocs); return imbalance; } /* ---------------------------------------------------------------------- binary search for where value falls in N-length vec note that vec actually has N+1 values, but ignore last one values in vec are monotonically increasing, but adjacent values can be ties value may be outside range of vec limits always return index from 0 to N-1 inclusive return 0 if value < vec[0] reutrn N-1 if value >= vec[N-1] return index = 1 to N-2 inclusive if vec[index] <= value < vec[index+1] note that for adjacent tie values, index of lower tie is not returned since never satisfies 2nd condition that value < vec[index+1] ------------------------------------------------------------------------- */ int Balance::binary(double value, int n, double *vec) { int lo = 0; int hi = n-1; if (value < vec[lo]) return lo; if (value >= vec[hi]) return hi; // insure vec[lo] <= value < vec[hi] at every iteration // done when lo,hi are adjacent int index = (lo+hi)/2; while (lo < hi-1) { if (value < vec[index]) hi = index; else if (value >= vec[index]) lo = index; index = (lo+hi)/2; } return index; } /* ---------------------------------------------------------------------- write dump snapshot of line segments in Pizza.py mdump mesh format write xy lines around each proc's sub-domain for 2d write xyz cubes around each proc's sub-domain for 3d only called by proc 0 NOTE: only implemented for orthogonal boxes, not triclinic ------------------------------------------------------------------------- */ void Balance::dumpout(bigint tstep) { int dimension = domain->dimension; int triclinic = domain->triclinic; // Allgather each proc's sub-box // could use Gather, but that requires MPI to alloc memory double *lo,*hi; if (triclinic == 0) { lo = domain->sublo; hi = domain->subhi; } else { lo = domain->sublo_lamda; hi = domain->subhi_lamda; } double box[6]; box[0] = lo[0]; box[1] = lo[1]; box[2] = lo[2]; box[3] = hi[0]; box[4] = hi[1]; box[5] = hi[2]; double **boxall; memory->create(boxall,nprocs,6,"balance:dumpout"); MPI_Allgather(box,6,MPI_DOUBLE,&boxall[0][0],6,MPI_DOUBLE,world); if (me) { memory->destroy(boxall); return; } // proc 0 writes out nodal coords // some will be duplicates double *boxlo = domain->boxlo; double *boxhi = domain->boxhi; fprintf(fp,"ITEM: TIMESTEP\n"); fprintf(fp,BIGINT_FORMAT "\n",tstep); fprintf(fp,"ITEM: NUMBER OF NODES\n"); if (dimension == 2) fprintf(fp,"%d\n",4*nprocs); else fprintf(fp,"%d\n",8*nprocs); fprintf(fp,"ITEM: BOX BOUNDS\n"); fprintf(fp,"%g %g\n",boxlo[0],boxhi[0]); fprintf(fp,"%g %g\n",boxlo[1],boxhi[1]); fprintf(fp,"%g %g\n",boxlo[2],boxhi[2]); fprintf(fp,"ITEM: NODES\n"); if (triclinic == 0) { if (dimension == 2) { int m = 0; for (int i = 0; i < nprocs; i++) { fprintf(fp,"%d %d %g %g %g\n",m+1,1,boxall[i][0],boxall[i][1],0.0); fprintf(fp,"%d %d %g %g %g\n",m+2,1,boxall[i][3],boxall[i][1],0.0); fprintf(fp,"%d %d %g %g %g\n",m+3,1,boxall[i][3],boxall[i][4],0.0); fprintf(fp,"%d %d %g %g %g\n",m+4,1,boxall[i][0],boxall[i][4],0.0); m += 4; } } else { int m = 0; for (int i = 0; i < nprocs; i++) { fprintf(fp,"%d %d %g %g %g\n",m+1,1, boxall[i][0],boxall[i][1],boxall[i][2]); fprintf(fp,"%d %d %g %g %g\n",m+2,1, boxall[i][3],boxall[i][1],boxall[i][2]); fprintf(fp,"%d %d %g %g %g\n",m+3,1, boxall[i][3],boxall[i][4],boxall[i][2]); fprintf(fp,"%d %d %g %g %g\n",m+4,1, boxall[i][0],boxall[i][4],boxall[i][2]); fprintf(fp,"%d %d %g %g %g\n",m+5,1, boxall[i][0],boxall[i][1],boxall[i][5]); fprintf(fp,"%d %d %g %g %g\n",m+6,1, boxall[i][3],boxall[i][1],boxall[i][5]); fprintf(fp,"%d %d %g %g %g\n",m+7,1, boxall[i][3],boxall[i][4],boxall[i][5]); fprintf(fp,"%d %d %g %g %g\n",m+8,1, boxall[i][0],boxall[i][4],boxall[i][5]); m += 8; } } } else { double (*bc)[3] = domain->corners; if (dimension == 2) { int m = 0; for (int i = 0; i < nprocs; i++) { domain->lamda_box_corners(&boxall[i][0],&boxall[i][3]); fprintf(fp,"%d %d %g %g %g\n",m+1,1,bc[0][0],bc[0][1],0.0); fprintf(fp,"%d %d %g %g %g\n",m+2,1,bc[1][0],bc[1][1],0.0); fprintf(fp,"%d %d %g %g %g\n",m+3,1,bc[2][0],bc[2][1],0.0); fprintf(fp,"%d %d %g %g %g\n",m+4,1,bc[3][0],bc[3][1],0.0); m += 4; } } else { int m = 0; for (int i = 0; i < nprocs; i++) { domain->lamda_box_corners(&boxall[i][0],&boxall[i][3]); fprintf(fp,"%d %d %g %g %g\n",m+1,1,bc[0][0],bc[0][1],bc[0][1]); fprintf(fp,"%d %d %g %g %g\n",m+2,1,bc[1][0],bc[1][1],bc[1][1]); fprintf(fp,"%d %d %g %g %g\n",m+3,1,bc[2][0],bc[2][1],bc[2][1]); fprintf(fp,"%d %d %g %g %g\n",m+4,1,bc[3][0],bc[3][1],bc[3][1]); fprintf(fp,"%d %d %g %g %g\n",m+5,1,bc[4][0],bc[4][1],bc[4][1]); fprintf(fp,"%d %d %g %g %g\n",m+6,1,bc[5][0],bc[5][1],bc[5][1]); fprintf(fp,"%d %d %g %g %g\n",m+7,1,bc[6][0],bc[6][1],bc[6][1]); fprintf(fp,"%d %d %g %g %g\n",m+8,1,bc[7][0],bc[7][1],bc[7][1]); m += 8; } } } // write out one square/cube per processor for 2d/3d fprintf(fp,"ITEM: TIMESTEP\n"); fprintf(fp,BIGINT_FORMAT "\n",tstep); if (dimension == 2) fprintf(fp,"ITEM: NUMBER OF SQUARES\n"); else fprintf(fp,"ITEM: NUMBER OF CUBES\n"); fprintf(fp,"%d\n",nprocs); if (dimension == 2) fprintf(fp,"ITEM: SQUARES\n"); else fprintf(fp,"ITEM: CUBES\n"); if (dimension == 2) { int m = 0; for (int i = 0; i < nprocs; i++) { fprintf(fp,"%d %d %d %d %d %d\n",i+1,1,m+1,m+2,m+3,m+4); m += 4; } } else { int m = 0; for (int i = 0; i < nprocs; i++) { fprintf(fp,"%d %d %d %d %d %d %d %d %d %d\n", i+1,1,m+1,m+2,m+3,m+4,m+5,m+6,m+7,m+8); m += 8; } } memory->destroy(boxall); } /* ---------------------------------------------------------------------- debug output for Idim and count only called by proc 0 ------------------------------------------------------------------------- */ #ifdef BALANCE_DEBUG void Balance::debug_shift_output(int idim, int m, int np, double *split) { int i; const char *dim = NULL; double *boxlo = domain->boxlo; double *prd = domain->prd; if (bdim[idim] == X) dim = "X"; else if (bdim[idim] == Y) dim = "Y"; else if (bdim[idim] == Z) dim = "Z"; fprintf(stderr,"Dimension %s, Iteration %d\n",dim,m); fprintf(stderr," Count:"); for (i = 0; i < np; i++) fprintf(stderr," " BIGINT_FORMAT,count[i]); fprintf(stderr,"\n"); fprintf(stderr," Sum:"); for (i = 0; i <= np; i++) fprintf(stderr," " BIGINT_FORMAT,sum[i]); fprintf(stderr,"\n"); fprintf(stderr," Target:"); for (i = 0; i <= np; i++) fprintf(stderr," " BIGINT_FORMAT,target[i]); fprintf(stderr,"\n"); fprintf(stderr," Actual cut:"); for (i = 0; i <= np; i++) fprintf(stderr," %g",boxlo[bdim[idim]] + split[i]*prd[bdim[idim]]); fprintf(stderr,"\n"); fprintf(stderr," Split:"); for (i = 0; i <= np; i++) fprintf(stderr," %g",split[i]); fprintf(stderr,"\n"); fprintf(stderr," Low:"); for (i = 0; i <= np; i++) fprintf(stderr," %g",lo[i]); fprintf(stderr,"\n"); fprintf(stderr," Low-sum:"); for (i = 0; i <= np; i++) fprintf(stderr," " BIGINT_FORMAT,losum[i]); fprintf(stderr,"\n"); fprintf(stderr," Hi:"); for (i = 0; i <= np; i++) fprintf(stderr," %g",hi[i]); fprintf(stderr,"\n"); fprintf(stderr," Hi-sum:"); for (i = 0; i <= np; i++) fprintf(stderr," " BIGINT_FORMAT,hisum[i]); fprintf(stderr,"\n"); fprintf(stderr," Delta:"); for (i = 0; i < np; i++) fprintf(stderr," %g",split[i+1]-split[i]); fprintf(stderr,"\n"); bigint max = 0; for (i = 0; i < np; i++) max = MAX(max,count[i]); fprintf(stderr," Imbalance factor: %g\n",1.0*max*np/target[np]); } #endif diff --git a/src/variable.cpp b/src/variable.cpp index 6e16597c6..a8f195dbc 100644 --- a/src/variable.cpp +++ b/src/variable.cpp @@ -1,4986 +1,4988 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain 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 #include #include #include #include #include "variable.h" #include "universe.h" #include "atom.h" #include "update.h" #include "group.h" #include "domain.h" #include "comm.h" #include "region.h" #include "modify.h" #include "compute.h" #include "fix.h" #include "fix_store.h" #include "force.h" #include "output.h" #include "thermo.h" #include "random_mars.h" #include "math_const.h" #include "atom_masks.h" #include "python.h" #include "memory.h" #include "info.h" #include "error.h" using namespace LAMMPS_NS; using namespace MathConst; #define VARDELTA 4 #define MAXLEVEL 4 #define MAXLINE 256 #define CHUNK 1024 #define VALUELENGTH 64 // also in python.cpp #define MAXFUNCARG 6 #define MYROUND(a) (( a-floor(a) ) >= .5) ? ceil(a) : floor(a) enum{INDEX,LOOP,WORLD,UNIVERSE,ULOOP,STRING,GETENV, SCALARFILE,ATOMFILE,FORMAT,EQUAL,ATOM,VECTOR,PYTHON,INTERNAL}; enum{ARG,OP}; // customize by adding a function // if add before XOR: // also set precedence level in constructor and precedence length in *.h enum{DONE,ADD,SUBTRACT,MULTIPLY,DIVIDE,CARAT,MODULO,UNARY, NOT,EQ,NE,LT,LE,GT,GE,AND,OR,XOR, SQRT,EXP,LN,LOG,ABS,SIN,COS,TAN,ASIN,ACOS,ATAN,ATAN2, RANDOM,NORMAL,CEIL,FLOOR,ROUND,RAMP,STAGGER,LOGFREQ,LOGFREQ2, STRIDE,STRIDE2,VDISPLACE,SWIGGLE,CWIGGLE,GMASK,RMASK,GRMASK, IS_ACTIVE,IS_DEFINED,IS_AVAILABLE, VALUE,ATOMARRAY,TYPEARRAY,INTARRAY,BIGINTARRAY,VECTORARRAY}; // customize by adding a special function enum{SUM,XMIN,XMAX,AVE,TRAP,SLOPE}; #define INVOKED_SCALAR 1 #define INVOKED_VECTOR 2 #define INVOKED_ARRAY 4 #define INVOKED_PERATOM 8 #define BIG 1.0e20 /* ---------------------------------------------------------------------- */ Variable::Variable(LAMMPS *lmp) : Pointers(lmp) { MPI_Comm_rank(world,&me); nvar = maxvar = 0; names = NULL; style = NULL; num = NULL; which = NULL; pad = NULL; reader = NULL; data = NULL; dvalue = NULL; vecs = NULL; eval_in_progress = NULL; randomequal = NULL; randomatom = NULL; // customize by assigning a precedence level precedence[DONE] = 0; precedence[OR] = precedence[XOR] = 1; precedence[AND] = 2; precedence[EQ] = precedence[NE] = 3; precedence[LT] = precedence[LE] = precedence[GT] = precedence[GE] = 4; precedence[ADD] = precedence[SUBTRACT] = 5; precedence[MULTIPLY] = precedence[DIVIDE] = precedence[MODULO] = 6; precedence[CARAT] = 7; precedence[UNARY] = precedence[NOT] = 8; } /* ---------------------------------------------------------------------- */ Variable::~Variable() { for (int i = 0; i < nvar; i++) { delete [] names[i]; delete reader[i]; if (style[i] == LOOP || style[i] == ULOOP) delete [] data[i][0]; else for (int j = 0; j < num[i]; j++) delete [] data[i][j]; delete [] data[i]; if (style[i] == VECTOR) memory->destroy(vecs[i].values); } memory->sfree(names); memory->destroy(style); memory->destroy(num); memory->destroy(which); memory->destroy(pad); memory->sfree(reader); memory->sfree(data); memory->sfree(dvalue); memory->sfree(vecs); memory->destroy(eval_in_progress); delete randomequal; delete randomatom; } /* ---------------------------------------------------------------------- called by variable command in input script ------------------------------------------------------------------------- */ void Variable::set(int narg, char **arg) { if (narg < 2) error->all(FLERR,"Illegal variable command"); int replaceflag = 0; // DELETE // doesn't matter if variable no longer exists if (strcmp(arg[1],"delete") == 0) { if (narg != 2) error->all(FLERR,"Illegal variable command"); if (find(arg[0]) >= 0) remove(find(arg[0])); return; // INDEX // num = listed args, which = 1st value, data = copied args } else if (strcmp(arg[1],"index") == 0) { if (narg < 3) error->all(FLERR,"Illegal variable command"); if (find(arg[0]) >= 0) return; if (nvar == maxvar) grow(); style[nvar] = INDEX; num[nvar] = narg - 2; which[nvar] = 0; pad[nvar] = 0; data[nvar] = new char*[num[nvar]]; copy(num[nvar],&arg[2],data[nvar]); // LOOP // 1 arg + pad: num = N, which = 1st value, data = single string // 2 args + pad: num = N2, which = N1, data = single string } else if (strcmp(arg[1],"loop") == 0) { if (find(arg[0]) >= 0) return; if (nvar == maxvar) grow(); style[nvar] = LOOP; int nfirst,nlast; if (narg == 3 || (narg == 4 && strcmp(arg[3],"pad") == 0)) { nfirst = 1; nlast = force->inumeric(FLERR,arg[2]); if (nlast <= 0) error->all(FLERR,"Illegal variable command"); if (narg == 4 && strcmp(arg[3],"pad") == 0) { char digits[12]; sprintf(digits,"%d",nlast); pad[nvar] = strlen(digits); } else pad[nvar] = 0; } else if (narg == 4 || (narg == 5 && strcmp(arg[4],"pad") == 0)) { nfirst = force->inumeric(FLERR,arg[2]); nlast = force->inumeric(FLERR,arg[3]); if (nfirst > nlast || nlast < 0) error->all(FLERR,"Illegal variable command"); if (narg == 5 && strcmp(arg[4],"pad") == 0) { char digits[12]; sprintf(digits,"%d",nlast); pad[nvar] = strlen(digits); } else pad[nvar] = 0; } else error->all(FLERR,"Illegal variable command"); num[nvar] = nlast; which[nvar] = nfirst-1; data[nvar] = new char*[1]; data[nvar][0] = NULL; // WORLD // num = listed args, which = partition this proc is in, data = copied args // error check that num = # of worlds in universe } else if (strcmp(arg[1],"world") == 0) { if (narg < 3) error->all(FLERR,"Illegal variable command"); if (find(arg[0]) >= 0) return; if (nvar == maxvar) grow(); style[nvar] = WORLD; num[nvar] = narg - 2; if (num[nvar] != universe->nworlds) error->all(FLERR,"World variable count doesn't match # of partitions"); which[nvar] = universe->iworld; pad[nvar] = 0; data[nvar] = new char*[num[nvar]]; copy(num[nvar],&arg[2],data[nvar]); // UNIVERSE and ULOOP // for UNIVERSE: num = listed args, data = copied args // for ULOOP: num = N, data = single string // which = partition this proc is in // universe proc 0 creates lock file // error check that all other universe/uloop variables are same length } else if (strcmp(arg[1],"universe") == 0 || strcmp(arg[1],"uloop") == 0) { if (strcmp(arg[1],"universe") == 0) { if (narg < 3) error->all(FLERR,"Illegal variable command"); if (find(arg[0]) >= 0) return; if (nvar == maxvar) grow(); style[nvar] = UNIVERSE; num[nvar] = narg - 2; pad[nvar] = 0; data[nvar] = new char*[num[nvar]]; copy(num[nvar],&arg[2],data[nvar]); } else if (strcmp(arg[1],"uloop") == 0) { if (narg < 3 || narg > 4 || (narg == 4 && strcmp(arg[3],"pad") != 0)) error->all(FLERR,"Illegal variable command"); if (find(arg[0]) >= 0) return; if (nvar == maxvar) grow(); style[nvar] = ULOOP; num[nvar] = force->inumeric(FLERR,arg[2]); data[nvar] = new char*[1]; data[nvar][0] = NULL; if (narg == 4) { char digits[12]; sprintf(digits,"%d",num[nvar]); pad[nvar] = strlen(digits); } else pad[nvar] = 0; } if (num[nvar] < universe->nworlds) error->all(FLERR,"Universe/uloop variable count < # of partitions"); which[nvar] = universe->iworld; if (universe->me == 0) { FILE *fp = fopen("tmp.lammps.variable","w"); if (fp == NULL) error->one(FLERR,"Cannot open temporary file for world counter."); fprintf(fp,"%d\n",universe->nworlds); fclose(fp); fp = NULL; } for (int jvar = 0; jvar < nvar; jvar++) if (num[jvar] && (style[jvar] == UNIVERSE || style[jvar] == ULOOP) && num[nvar] != num[jvar]) error->all(FLERR, "All universe/uloop variables must have same # of values"); // STRING // replace pre-existing var if also style STRING (allows it to be reset) // num = 1, which = 1st value // data = 1 value, string to eval } else if (strcmp(arg[1],"string") == 0) { if (narg != 3) error->all(FLERR,"Illegal variable command"); int ivar = find(arg[0]); if (ivar >= 0) { if (style[ivar] != STRING) error->all(FLERR,"Cannot redefine variable as a different style"); delete [] data[ivar][0]; copy(1,&arg[2],data[ivar]); replaceflag = 1; } else { if (nvar == maxvar) grow(); style[nvar] = STRING; num[nvar] = 1; which[nvar] = 0; pad[nvar] = 0; data[nvar] = new char*[num[nvar]]; copy(1,&arg[2],data[nvar]); } // GETENV // remove pre-existing var if also style GETENV (allows it to be reset) // num = 1, which = 1st value // data = 1 value, string to eval } else if (strcmp(arg[1],"getenv") == 0) { if (narg != 3) error->all(FLERR,"Illegal variable command"); if (find(arg[0]) >= 0) { if (style[find(arg[0])] != GETENV) error->all(FLERR,"Cannot redefine variable as a different style"); remove(find(arg[0])); } if (nvar == maxvar) grow(); style[nvar] = GETENV; num[nvar] = 1; which[nvar] = 0; pad[nvar] = 0; data[nvar] = new char*[num[nvar]]; copy(1,&arg[2],data[nvar]); data[nvar][1] = new char[VALUELENGTH]; strcpy(data[nvar][1],"(undefined)"); // SCALARFILE for strings or numbers // which = 1st value // data = 1 value, string to eval } else if (strcmp(arg[1],"file") == 0) { if (narg != 3) error->all(FLERR,"Illegal variable command"); if (find(arg[0]) >= 0) return; if (nvar == maxvar) grow(); style[nvar] = SCALARFILE; num[nvar] = 1; which[nvar] = 0; pad[nvar] = 0; data[nvar] = new char*[num[nvar]]; data[nvar][0] = new char[MAXLINE]; reader[nvar] = new VarReader(lmp,arg[0],arg[2],SCALARFILE); int flag = reader[nvar]->read_scalar(data[nvar][0]); if (flag) error->all(FLERR,"File variable could not read value"); // ATOMFILE for numbers // which = 1st value // data = NULL } else if (strcmp(arg[1],"atomfile") == 0) { if (narg != 3) error->all(FLERR,"Illegal variable command"); if (find(arg[0]) >= 0) return; if (nvar == maxvar) grow(); style[nvar] = ATOMFILE; num[nvar] = 1; which[nvar] = 0; pad[nvar] = 0; data[nvar] = new char*[num[nvar]]; data[nvar][0] = NULL; reader[nvar] = new VarReader(lmp,arg[0],arg[2],ATOMFILE); int flag = reader[nvar]->read_peratom(); if (flag) error->all(FLERR,"Atomfile variable could not read values"); // FORMAT // num = 3, which = 1st value // data = 3 values // 1st is name of variable to eval, 2nd is format string, // 3rd is filled on retrieval } else if (strcmp(arg[1],"format") == 0) { if (narg != 4) error->all(FLERR,"Illegal variable command"); if (find(arg[0]) >= 0) return; if (nvar == maxvar) grow(); style[nvar] = FORMAT; num[nvar] = 3; which[nvar] = 0; pad[nvar] = 0; data[nvar] = new char*[num[nvar]]; copy(2,&arg[2],data[nvar]); data[nvar][2] = new char[VALUELENGTH]; strcpy(data[nvar][2],"(undefined)"); // EQUAL // replace pre-existing var if also style EQUAL (allows it to be reset) // num = 2, which = 1st value // data = 2 values, 1st is string to eval, 2nd is filled on retrieval } else if (strcmp(arg[1],"equal") == 0) { if (narg != 3) error->all(FLERR,"Illegal variable command"); int ivar = find(arg[0]); if (ivar >= 0) { if (style[ivar] != EQUAL) error->all(FLERR,"Cannot redefine variable as a different style"); delete [] data[ivar][0]; copy(1,&arg[2],data[ivar]); replaceflag = 1; } else { if (nvar == maxvar) grow(); style[nvar] = EQUAL; num[nvar] = 2; which[nvar] = 0; pad[nvar] = 0; data[nvar] = new char*[num[nvar]]; copy(1,&arg[2],data[nvar]); data[nvar][1] = new char[VALUELENGTH]; strcpy(data[nvar][1],"(undefined)"); } // ATOM // replace pre-existing var if also style ATOM (allows it to be reset) // num = 1, which = 1st value // data = 1 value, string to eval } else if (strcmp(arg[1],"atom") == 0) { if (narg != 3) error->all(FLERR,"Illegal variable command"); int ivar = find(arg[0]); if (ivar >= 0) { if (style[ivar] != ATOM) error->all(FLERR,"Cannot redefine variable as a different style"); delete [] data[ivar][0]; copy(1,&arg[2],data[ivar]); replaceflag = 1; } else { if (nvar == maxvar) grow(); style[nvar] = ATOM; num[nvar] = 1; which[nvar] = 0; pad[nvar] = 0; data[nvar] = new char*[num[nvar]]; copy(1,&arg[2],data[nvar]); } // VECTOR // replace pre-existing var if also style VECTOR (allows it to be reset) // num = 1, which = 1st value // data = 1 value, string to eval } else if (strcmp(arg[1],"vector") == 0) { if (narg != 3) error->all(FLERR,"Illegal variable command"); int ivar = find(arg[0]); if (ivar >= 0) { if (style[ivar] != VECTOR) error->all(FLERR,"Cannot redefine variable as a different style"); delete [] data[ivar][0]; copy(1,&arg[2],data[ivar]); replaceflag = 1; } else { if (nvar == maxvar) grow(); style[nvar] = VECTOR; num[nvar] = 1; which[nvar] = 0; pad[nvar] = 0; data[nvar] = new char*[num[nvar]]; copy(1,&arg[2],data[nvar]); } // PYTHON // replace pre-existing var if also style PYTHON (allows it to be reset) // num = 2, which = 1st value // data = 2 values, 1st is Python func to invoke, 2nd is filled by invoke } else if (strcmp(arg[1],"python") == 0) { if (narg != 3) error->all(FLERR,"Illegal variable command"); if (!python->is_enabled()) error->all(FLERR,"LAMMPS is not built with Python embedded"); int ivar = find(arg[0]); if (ivar >= 0) { if (style[ivar] != PYTHON) error->all(FLERR,"Cannot redefine variable as a different style"); delete [] data[ivar][0]; copy(1,&arg[2],data[ivar]); replaceflag = 1; } else { if (nvar == maxvar) grow(); style[nvar] = PYTHON; num[nvar] = 2; which[nvar] = 1; pad[nvar] = 0; data[nvar] = new char*[num[nvar]]; copy(1,&arg[2],data[nvar]); data[nvar][1] = new char[VALUELENGTH]; strcpy(data[nvar][1],"(undefined)"); } // INTERNAL // replace pre-existing var if also style INTERNAL (allows it to be reset) // num = 1, for string representation of dvalue, set by retrieve() // dvalue = numeric initialization from 2nd arg, reset by internal_set() } else if (strcmp(arg[1],"internal") == 0) { if (narg != 3) error->all(FLERR,"Illegal variable command"); int ivar = find(arg[0]); if (ivar >= 0) { if (style[ivar] != INTERNAL) error->all(FLERR,"Cannot redefine variable as a different style"); dvalue[nvar] = force->numeric(FLERR,arg[2]); replaceflag = 1; } else { if (nvar == maxvar) grow(); style[nvar] = INTERNAL; num[nvar] = 1; which[nvar] = 0; pad[nvar] = 0; data[nvar] = new char*[num[nvar]]; data[nvar][0] = new char[VALUELENGTH]; dvalue[nvar] = force->numeric(FLERR,arg[2]); } } else error->all(FLERR,"Illegal variable command"); // set name of variable, if not replacing one flagged with replaceflag // name must be all alphanumeric chars or underscores if (replaceflag) return; int n = strlen(arg[0]) + 1; names[nvar] = new char[n]; strcpy(names[nvar],arg[0]); for (int i = 0; i < n-1; i++) if (!isalnum(names[nvar][i]) && names[nvar][i] != '_') error->all(FLERR,"Variable name must be alphanumeric or " "underscore characters"); nvar++; } /* ---------------------------------------------------------------------- INDEX variable created by command-line argument make it INDEX rather than STRING so cannot be re-defined in input script ------------------------------------------------------------------------- */ void Variable::set(char *name, int narg, char **arg) { char **newarg = new char*[2+narg]; newarg[0] = name; newarg[1] = (char *) "index"; for (int i = 0; i < narg; i++) newarg[2+i] = arg[i]; set(2+narg,newarg); delete [] newarg; } /* ---------------------------------------------------------------------- set existing STRING variable to str return 0 if successful return -1 if variable doesn't exist or isn't a STRING variable called via library interface, so external programs can set variables ------------------------------------------------------------------------- */ int Variable::set_string(char *name, char *str) { int ivar = find(name); if (ivar < 0) return -1; if (style[ivar] != STRING) return -1; delete [] data[ivar][0]; copy(1,&str,data[ivar]); return 0; } /* ---------------------------------------------------------------------- increment variable(s) return 0 if OK if successfully incremented return 1 if any variable is exhausted, free the variable to allow re-use ------------------------------------------------------------------------- */ int Variable::next(int narg, char **arg) { int ivar; if (narg == 0) error->all(FLERR,"Illegal next command"); // check that variables exist and are all the same style // exception: UNIVERSE and ULOOP variables can be mixed in same next command for (int iarg = 0; iarg < narg; iarg++) { ivar = find(arg[iarg]); if (ivar < 0) error->all(FLERR,"Invalid variable in next command"); if (style[ivar] == ULOOP && style[find(arg[0])] == UNIVERSE) continue; else if (style[ivar] == UNIVERSE && style[find(arg[0])] == ULOOP) continue; else if (style[ivar] != style[find(arg[0])]) error->all(FLERR,"All variables in next command must be same style"); } // invalid styles: STRING, EQUAL, WORLD, ATOM, VECTOR, GETENV, // FORMAT, PYTHON, INTERNAL int istyle = style[find(arg[0])]; if (istyle == STRING || istyle == EQUAL || istyle == WORLD || istyle == GETENV || istyle == ATOM || istyle == VECTOR || istyle == FORMAT || istyle == PYTHON || istyle == INTERNAL) error->all(FLERR,"Invalid variable style with next command"); // if istyle = UNIVERSE or ULOOP, insure all such variables are incremented if (istyle == UNIVERSE || istyle == ULOOP) for (int i = 0; i < nvar; i++) { if (style[i] != UNIVERSE && style[i] != ULOOP) continue; int iarg = 0; for (iarg = 0; iarg < narg; iarg++) if (strcmp(arg[iarg],names[i]) == 0) break; if (iarg == narg) error->universe_one(FLERR,"Next command must list all " "universe and uloop variables"); } // increment all variables in list // if any variable is exhausted, set flag = 1 and remove var to allow re-use int flag = 0; if (istyle == INDEX || istyle == LOOP) { for (int iarg = 0; iarg < narg; iarg++) { ivar = find(arg[iarg]); which[ivar]++; if (which[ivar] >= num[ivar]) { flag = 1; remove(ivar); } } } else if (istyle == SCALARFILE) { for (int iarg = 0; iarg < narg; iarg++) { ivar = find(arg[iarg]); int done = reader[ivar]->read_scalar(data[ivar][0]); if (done) { flag = 1; remove(ivar); } } } else if (istyle == ATOMFILE) { for (int iarg = 0; iarg < narg; iarg++) { ivar = find(arg[iarg]); int done = reader[ivar]->read_peratom(); if (done) { flag = 1; remove(ivar); } } } else if (istyle == UNIVERSE || istyle == ULOOP) { // wait until lock file can be created and owned by proc 0 of this world // rename() is not atomic in practice, but no known simple fix // means multiple procs can read/write file at the same time (bad!) // random delays help // delay for random fraction of 1 second before first rename() call // delay for random fraction of 1 second before subsequent tries // when successful, read next available index and Bcast it within my world int nextindex; if (me == 0) { int seed = 12345 + universe->me + which[find(arg[0])]; RanMars *random = new RanMars(lmp,seed); int delay = (int) (1000000*random->uniform()); usleep(delay); while (1) { if (!rename("tmp.lammps.variable","tmp.lammps.variable.lock")) break; delay = (int) (1000000*random->uniform()); usleep(delay); } delete random; FILE *fp = fopen("tmp.lammps.variable.lock","r"); fscanf(fp,"%d",&nextindex); //printf("READ %d %d\n",universe->me,nextindex); fclose(fp); fp = fopen("tmp.lammps.variable.lock","w"); fprintf(fp,"%d\n",nextindex+1); //printf("WRITE %d %d\n",universe->me,nextindex+1); fclose(fp); fp = NULL; rename("tmp.lammps.variable.lock","tmp.lammps.variable"); if (universe->uscreen) fprintf(universe->uscreen, "Increment via next: value %d on partition %d\n", nextindex+1,universe->iworld); if (universe->ulogfile) fprintf(universe->ulogfile, "Increment via next: value %d on partition %d\n", nextindex+1,universe->iworld); } MPI_Bcast(&nextindex,1,MPI_INT,0,world); // set all variables in list to nextindex // must increment all UNIVERSE and ULOOP variables here // error check above tested for this for (int iarg = 0; iarg < narg; iarg++) { ivar = find(arg[iarg]); which[ivar] = nextindex; if (which[ivar] >= num[ivar]) { flag = 1; remove(ivar); } } } return flag; } /* ---------------------------------------------------------------------- search for name in list of variables names return index or -1 if not found ------------------------------------------------------------------------- */ int Variable::find(char *name) { if(name==NULL) return -1; for (int i = 0; i < nvar; i++) if (strcmp(name,names[i]) == 0) return i; return -1; } /* ---------------------------------------------------------------------- initialize one atom's storage values in all VarReaders via fix STORE called when atom is created ------------------------------------------------------------------------- */ void Variable::set_arrays(int i) { for (int i = 0; i < nvar; i++) if (reader[i] && style[i] == ATOMFILE) reader[i]->fixstore->vstore[i] = 0.0; } /* ---------------------------------------------------------------------- called by python command in input script simply pass input script line args to Python class ------------------------------------------------------------------------- */ void Variable::python_command(int narg, char **arg) { if (!python->is_enabled()) error->all(FLERR,"LAMMPS is not built with Python embedded"); python->command(narg,arg); } /* ---------------------------------------------------------------------- return 1 if variable is EQUAL or INTERNAL or PYTHON numeric style, 0 if not this is checked before call to compute_equal() to return a double ------------------------------------------------------------------------- */ int Variable::equalstyle(int ivar) { if (style[ivar] == EQUAL || style[ivar] == INTERNAL) return 1; if (style[ivar] == PYTHON) { int ifunc = python->variable_match(data[ivar][0],names[ivar],1); if (ifunc < 0) return 0; else return 1; } return 0; } /* ---------------------------------------------------------------------- return 1 if variable is ATOM or ATOMFILE style, 0 if not this is checked before call to compute_atom() to return a vector of doubles ------------------------------------------------------------------------- */ int Variable::atomstyle(int ivar) { if (style[ivar] == ATOM || style[ivar] == ATOMFILE) return 1; return 0; } /* ---------------------------------------------------------------------- return 1 if variable is VECTOR style, 0 if not this is checked before call to compute_vector() to return a vector of doubles ------------------------------------------------------------------------- */ int Variable::vectorstyle(int ivar) { if (style[ivar] == VECTOR) return 1; return 0; } /* ---------------------------------------------------------------------- check if variable with name is PYTHON and matches funcname called by Python class before it invokes a Python function return data storage so Python function can return a value for this variable return NULL if not a match ------------------------------------------------------------------------- */ char *Variable::pythonstyle(char *name, char *funcname) { int ivar = find(name); if (ivar < 0) return NULL; if (style[ivar] != PYTHON) return NULL; if (strcmp(data[ivar][0],funcname) != 0) return NULL; return data[ivar][1]; } /* ---------------------------------------------------------------------- return 1 if variable is INTERNAL style, 0 if not this is checked before call to set_internal() to assure it can be set ------------------------------------------------------------------------- */ int Variable::internalstyle(int ivar) { if (style[ivar] == INTERNAL) return 1; return 0; } /* ---------------------------------------------------------------------- return ptr to the data text associated with a variable if INDEX or WORLD or UNIVERSE or STRING or SCALARFILE, return ptr to stored string if LOOP or ULOOP, write int to data[0] and return ptr to string if EQUAL, evaluate variable and put result in str if FORMAT, evaluate its variable and put formatted result in str if GETENV, query environment and put result in str if PYTHON, evaluate Python function, it will put result in str if INTERNAL, convert dvalue and put result in str if ATOM or ATOMFILE or VECTOR, return NULL return NULL if no variable with name, or which value is bad, caller must respond ------------------------------------------------------------------------- */ char *Variable::retrieve(char *name) { int ivar = find(name); if (ivar < 0) return NULL; if (which[ivar] >= num[ivar]) return NULL; if (eval_in_progress[ivar]) error->all(FLERR,"Variable has circular dependency"); eval_in_progress[ivar] = 1; char *str = NULL; if (style[ivar] == INDEX || style[ivar] == WORLD || style[ivar] == UNIVERSE || style[ivar] == STRING || style[ivar] == SCALARFILE) { str = data[ivar][which[ivar]]; } else if (style[ivar] == LOOP || style[ivar] == ULOOP) { char result[16]; if (pad[ivar] == 0) sprintf(result,"%d",which[ivar]+1); else { char padstr[16]; sprintf(padstr,"%%0%dd",pad[ivar]); sprintf(result,padstr,which[ivar]+1); } int n = strlen(result) + 1; delete [] data[ivar][0]; data[ivar][0] = new char[n]; strcpy(data[ivar][0],result); str = data[ivar][0]; } else if (style[ivar] == EQUAL) { double answer = evaluate(data[ivar][0],NULL); sprintf(data[ivar][1],"%.15g",answer); str = data[ivar][1]; } else if (style[ivar] == FORMAT) { int jvar = find(data[ivar][0]); if (jvar == -1) return NULL; if (!equalstyle(jvar)) return NULL; double answer = compute_equal(jvar); sprintf(data[ivar][2],data[ivar][1],answer); str = data[ivar][2]; } else if (style[ivar] == GETENV) { const char *result = getenv(data[ivar][0]); if (result == NULL) result = (const char *) ""; int n = strlen(result) + 1; if (n > VALUELENGTH) { delete [] data[ivar][1]; data[ivar][1] = new char[n]; } strcpy(data[ivar][1],result); str = data[ivar][1]; } else if (style[ivar] == PYTHON) { int ifunc = python->variable_match(data[ivar][0],names[ivar],0); if (ifunc < 0) error->all(FLERR,"Python variable does not match Python function"); python->invoke_function(ifunc,data[ivar][1]); str = data[ivar][1]; // if Python func returns a string longer than VALUELENGTH // then the Python class stores the result, query it via long_string() char *strlong = python->long_string(ifunc); if (strlong) str = strlong; } else if (style[ivar] == INTERNAL) { sprintf(data[ivar][0],"%.15g",dvalue[ivar]); str = data[ivar][0]; } else if (style[ivar] == ATOM || style[ivar] == ATOMFILE || style[ivar] == VECTOR) return NULL; eval_in_progress[ivar] = 0; return str; } /* ---------------------------------------------------------------------- return result of equal-style variable evaluation can be EQUAL or INTERNAL style or PYTHON numeric style for PYTHON, don't need to check python->variable_match() error return, since caller will have already checked via equalstyle() ------------------------------------------------------------------------- */ double Variable::compute_equal(int ivar) { if (eval_in_progress[ivar]) error->all(FLERR,"Variable has circular dependency"); eval_in_progress[ivar] = 1; double value = 0.0; if (style[ivar] == EQUAL) value = evaluate(data[ivar][0],NULL); else if (style[ivar] == INTERNAL) value = dvalue[ivar]; else if (style[ivar] == PYTHON) { int ifunc = python->find(data[ivar][0]); if (ifunc < 0) error->all(FLERR,"Python variable has no function"); python->invoke_function(ifunc,data[ivar][1]); value = atof(data[ivar][1]); } eval_in_progress[ivar] = 0; return value; } /* ---------------------------------------------------------------------- return result of immediate equal-style variable evaluation called from Input::substitute() don't need to flag eval_in_progress since is an immediate variable ------------------------------------------------------------------------- */ double Variable::compute_equal(char *str) { return evaluate(str,NULL); } /* ---------------------------------------------------------------------- compute result of atom-style and atomfile-style variable evaluation only computed for atoms in igroup, else result is 0.0 answers are placed every stride locations into result if sumflag, add variable values to existing result ------------------------------------------------------------------------- */ void Variable::compute_atom(int ivar, int igroup, double *result, int stride, int sumflag) { Tree *tree; double *vstore; if (eval_in_progress[ivar]) error->all(FLERR,"Variable has circular dependency"); eval_in_progress[ivar] = 1; if (style[ivar] == ATOM) { treetype = ATOM; evaluate(data[ivar][0],&tree); collapse_tree(tree); } else vstore = reader[ivar]->fixstore->vstore; if (result == NULL) { eval_in_progress[ivar] = 0; return; } int groupbit = group->bitmask[igroup]; int *mask = atom->mask; int nlocal = atom->nlocal; if (style[ivar] == ATOM) { if (sumflag == 0) { int m = 0; for (int i = 0; i < nlocal; i++) { if (mask[i] & groupbit) result[m] = eval_tree(tree,i); else result[m] = 0.0; m += stride; } } else { int m = 0; for (int i = 0; i < nlocal; i++) { if (mask[i] & groupbit) result[m] += eval_tree(tree,i); m += stride; } } } else { if (sumflag == 0) { int m = 0; for (int i = 0; i < nlocal; i++) { if (mask[i] & groupbit) result[m] = vstore[i]; else result[m] = 0.0; m += stride; } } else { int m = 0; for (int i = 0; i < nlocal; i++) { if (mask[i] & groupbit) result[m] += vstore[i]; m += stride; } } } if (style[ivar] == ATOM) free_tree(tree); eval_in_progress[ivar] = 0; } /* ---------------------------------------------------------------------- compute result of vector-style variable evaluation return length of vector and result pointer to vector values if length == 0 or -1 (mismatch), generate an error if variable already computed on this timestep, just return else evaluate the formula and its length, store results in VecVar entry ------------------------------------------------------------------------- */ int Variable::compute_vector(int ivar, double **result) { Tree *tree; if (vecs[ivar].currentstep == update->ntimestep) { *result = vecs[ivar].values; return vecs[ivar].n; } if (eval_in_progress[ivar]) error->all(FLERR,"Variable has circular dependency"); eval_in_progress[ivar] = 1; treetype = VECTOR; evaluate(data[ivar][0],&tree); collapse_tree(tree); int nlen = size_tree_vector(tree); if (nlen == 0) error->all(FLERR,"Vector-style variable has zero length"); if (nlen < 0) error->all(FLERR, "Inconsistent lengths in vector-style variable"); // (re)allocate space for results if necessary if (nlen > vecs[ivar].nmax) { memory->destroy(vecs[ivar].values); vecs[ivar].nmax = nlen; memory->create(vecs[ivar].values,vecs[ivar].nmax,"variable:values"); } vecs[ivar].n = nlen; vecs[ivar].currentstep = update->ntimestep; double *vec = vecs[ivar].values; for (int i = 0; i < nlen; i++) vec[i] = eval_tree(tree,i); free_tree(tree); eval_in_progress[ivar] = 0; *result = vec; return nlen; } /* ---------------------------------------------------------------------- set value stored by INTERNAL style ivar ------------------------------------------------------------------------- */ void Variable::internal_set(int ivar, double value) { dvalue[ivar] = value; } /* ---------------------------------------------------------------------- remove Nth variable from list and compact list delete reader explicitly if it exists ------------------------------------------------------------------------- */ void Variable::remove(int n) { delete [] names[n]; if (style[n] == LOOP || style[n] == ULOOP) delete [] data[n][0]; else for (int i = 0; i < num[n]; i++) delete [] data[n][i]; delete [] data[n]; delete reader[n]; for (int i = n+1; i < nvar; i++) { names[i-1] = names[i]; style[i-1] = style[i]; num[i-1] = num[i]; which[i-1] = which[i]; pad[i-1] = pad[i]; reader[i-1] = reader[i]; data[i-1] = data[i]; } nvar--; } /* ---------------------------------------------------------------------- make space in arrays for new variable ------------------------------------------------------------------------- */ void Variable::grow() { int old = maxvar; maxvar += VARDELTA; names = (char **) memory->srealloc(names,maxvar*sizeof(char *),"var:names"); memory->grow(style,maxvar,"var:style"); memory->grow(num,maxvar,"var:num"); memory->grow(which,maxvar,"var:which"); memory->grow(pad,maxvar,"var:pad"); reader = (VarReader **) memory->srealloc(reader,maxvar*sizeof(VarReader *),"var:reader"); for (int i = old; i < maxvar; i++) reader[i] = NULL; data = (char ***) memory->srealloc(data,maxvar*sizeof(char **),"var:data"); memory->grow(dvalue,maxvar,"var:dvalue"); vecs = (VecVar *) memory->srealloc(vecs,maxvar*sizeof(VecVar),"var:vecvar"); for (int i = old; i < maxvar; i++) { vecs[i].nmax = 0; vecs[i].currentstep = -1; vecs[i].values = NULL; } memory->grow(eval_in_progress,maxvar,"var:eval_in_progress"); for (int i = 0; i < maxvar; i++) eval_in_progress[i] = 0; } /* ---------------------------------------------------------------------- copy narg strings from **from to **to, and allocate space for them ------------------------------------------------------------------------- */ void Variable::copy(int narg, char **from, char **to) { int n; for (int i = 0; i < narg; i++) { n = strlen(from[i]) + 1; to[i] = new char[n]; strcpy(to[i],from[i]); } } /* ---------------------------------------------------------------------- recursive evaluation of a string str str is an equal-style or atom-style or vector-style formula containing one or more items: number = 0.0, -5.45, 2.8e-4, ... constant = PI, version, yes, no, on, off thermo keyword = ke, vol, atoms, ... math operation = (),-x,x+y,x-y,x*y,x/y,x^y, x==y,x!=y,xy,x>=y,x&&y,x||y, sqrt(x),exp(x),ln(x),log(x),abs(x), sin(x),cos(x),tan(x),asin(x),atan2(y,x),... group function = count(group), mass(group), xcm(group,x), ... special function = sum(x),min(x), ... atom value = x[i], y[i], vx[i], ... atom vector = x, y, vx, ... compute = c_ID, c_ID[i], c_ID[i][j] fix = f_ID, f_ID[i], f_ID[i][j] variable = v_name, v_name[i] equal-style variables passes in tree = NULL: evaluate the formula, return result as a double atom-style and vector-style variables pass in tree = non-NULL: parse the formula but do not evaluate it create a parse tree and return it ------------------------------------------------------------------------- */ double Variable::evaluate(char *str, Tree **tree) { int op,opprevious; double value1,value2; char onechar; char *ptr; double argstack[MAXLEVEL]; Tree *treestack[MAXLEVEL]; int opstack[MAXLEVEL]; int nargstack = 0; int ntreestack = 0; int nopstack = 0; int i = 0; int expect = ARG; while (1) { onechar = str[i]; // whitespace: just skip if (isspace(onechar)) i++; // ---------------- // parentheses: recursively evaluate contents of parens // ---------------- else if (onechar == '(') { if (expect == OP) error->all(FLERR,"Invalid syntax in variable formula"); expect = OP; char *contents; i = find_matching_paren(str,i,contents); i++; // evaluate contents and push on stack if (tree) { Tree *newtree; evaluate(contents,&newtree); treestack[ntreestack++] = newtree; } else argstack[nargstack++] = evaluate(contents,NULL); delete [] contents; // ---------------- // number: push value onto stack // ---------------- } else if (isdigit(onechar) || onechar == '.') { if (expect == OP) error->all(FLERR,"Invalid syntax in variable formula"); expect = OP; // istop = end of number, including scientific notation int istart = i; while (isdigit(str[i]) || str[i] == '.') i++; if (str[i] == 'e' || str[i] == 'E') { i++; if (str[i] == '+' || str[i] == '-') i++; while (isdigit(str[i])) i++; } int istop = i - 1; int n = istop - istart + 1; char *number = new char[n+1]; strncpy(number,&str[istart],n); number[n] = '\0'; if (tree) { Tree *newtree = new Tree(); newtree->type = VALUE; newtree->value = atof(number); newtree->first = newtree->second = NULL; newtree->extra = 0; treestack[ntreestack++] = newtree; } else argstack[nargstack++] = atof(number); delete [] number; // ---------------- // letter: c_ID, c_ID[], c_ID[][], f_ID, f_ID[], f_ID[][], // v_name, v_name[], exp(), xcm(,), x, x[], PI, vol // ---------------- } else if (isalpha(onechar)) { if (expect == OP) error->all(FLERR,"Invalid syntax in variable formula"); expect = OP; // istop = end of word // word = all alphanumeric or underscore int istart = i; while (isalnum(str[i]) || str[i] == '_') i++; int istop = i-1; int n = istop - istart + 1; char *word = new char[n+1]; strncpy(word,&str[istart],n); word[n] = '\0'; // ---------------- // compute // ---------------- if (strncmp(word,"c_",2) == 0 || strncmp(word,"C_",2) == 0) { if (domain->box_exist == 0) error->all(FLERR, "Variable evaluation before simulation box is defined"); // uppercase used to force access of // global vector vs global scalar, and global array vs global vector int lowercase = 1; if (word[0] == 'C') lowercase = 0; int icompute = modify->find_compute(word+2); if (icompute < 0) error->all(FLERR,"Invalid compute ID in variable formula"); Compute *compute = modify->compute[icompute]; // parse zero or one or two trailing brackets // point i beyond last bracket // nbracket = # of bracket pairs // index1,index2 = int inside each bracket pair, possibly an atom ID int nbracket; tagint index1,index2; if (str[i] != '[') nbracket = 0; else { nbracket = 1; ptr = &str[i]; index1 = int_between_brackets(ptr,1); i = ptr-str+1; if (str[i] == '[') { nbracket = 2; ptr = &str[i]; index2 = int_between_brackets(ptr,1); i = ptr-str+1; } } // c_ID = scalar from global scalar, must be lowercase if (nbracket == 0 && compute->scalar_flag && lowercase) { if (update->whichflag == 0) { if (compute->invoked_scalar != update->ntimestep) error->all(FLERR,"Compute used in variable between runs " "is not current"); } else if (!(compute->invoked_flag & INVOKED_SCALAR)) { compute->compute_scalar(); compute->invoked_flag |= INVOKED_SCALAR; } value1 = compute->scalar; if (tree) { Tree *newtree = new Tree(); newtree->type = VALUE; newtree->value = value1; newtree->first = newtree->second = NULL; newtree->nextra = 0; treestack[ntreestack++] = newtree; } else argstack[nargstack++] = value1; // c_ID[i] = scalar from global vector, must be lowercase } else if (nbracket == 1 && compute->vector_flag && lowercase) { if (index1 > compute->size_vector && compute->size_vector_variable == 0) error->all(FLERR,"Variable formula compute vector " "is accessed out-of-range"); if (update->whichflag == 0) { if (compute->invoked_vector != update->ntimestep) error->all(FLERR,"Compute used in variable between runs " "is not current"); } else if (!(compute->invoked_flag & INVOKED_VECTOR)) { compute->compute_vector(); compute->invoked_flag |= INVOKED_VECTOR; } if (compute->size_vector_variable && index1 > compute->size_vector) value1 = 0.0; else value1 = compute->vector[index1-1]; if (tree) { Tree *newtree = new Tree(); newtree->type = VALUE; newtree->value = value1; newtree->first = newtree->second = NULL; newtree->nextra = 0; treestack[ntreestack++] = newtree; } else argstack[nargstack++] = value1; // c_ID[i][j] = scalar from global array, must be lowercase } else if (nbracket == 2 && compute->array_flag && lowercase) { if (index1 > compute->size_array_rows && compute->size_array_rows_variable == 0) error->all(FLERR,"Variable formula compute array " "is accessed out-of-range"); if (index2 > compute->size_array_cols) error->all(FLERR,"Variable formula compute array " "is accessed out-of-range"); if (update->whichflag == 0) { if (compute->invoked_array != update->ntimestep) error->all(FLERR,"Compute used in variable between runs " "is not current"); } else if (!(compute->invoked_flag & INVOKED_ARRAY)) { compute->compute_array(); compute->invoked_flag |= INVOKED_ARRAY; } if (compute->size_array_rows_variable && index1 > compute->size_array_rows) value1 = 0.0; else value1 = compute->array[index1-1][index2-1]; if (tree) { Tree *newtree = new Tree(); newtree->type = VALUE; newtree->value = value1; newtree->first = newtree->second = NULL; newtree->nextra = 0; treestack[ntreestack++] = newtree; } else argstack[nargstack++] = value1; // c_ID = vector from global vector, lowercase or uppercase } else if (nbracket == 0 && compute->vector_flag) { if (tree == NULL) error->all(FLERR, "Compute global vector in equal-style variable formula"); if (treetype == ATOM) error->all(FLERR, "Compute global vector in atom-style variable formula"); if (compute->size_vector == 0) error->all(FLERR,"Variable formula compute vector is zero length"); if (update->whichflag == 0) { if (compute->invoked_vector != update->ntimestep) error->all(FLERR,"Compute used in variable between runs " "is not current"); } else if (!(compute->invoked_flag & INVOKED_VECTOR)) { compute->compute_vector(); compute->invoked_flag |= INVOKED_VECTOR; } Tree *newtree = new Tree(); newtree->type = VECTORARRAY; newtree->array = compute->vector; newtree->nvector = compute->size_vector; newtree->nstride = 1; newtree->selfalloc = 0; newtree->first = newtree->second = NULL; newtree->nextra = 0; treestack[ntreestack++] = newtree; // c_ID[i] = vector from global array, lowercase or uppercase } else if (nbracket == 1 && compute->array_flag) { if (tree == NULL) error->all(FLERR, "Compute global vector in equal-style variable formula"); if (treetype == ATOM) error->all(FLERR, "Compute global vector in atom-style variable formula"); if (compute->size_array_rows == 0) error->all(FLERR,"Variable formula compute array is zero length"); if (update->whichflag == 0) { if (compute->invoked_array != update->ntimestep) error->all(FLERR,"Compute used in variable between runs " "is not current"); } else if (!(compute->invoked_flag & INVOKED_ARRAY)) { compute->compute_array(); compute->invoked_flag |= INVOKED_ARRAY; } Tree *newtree = new Tree(); newtree->type = VECTORARRAY; newtree->array = &compute->array[0][index1-1]; newtree->nvector = compute->size_array_rows; newtree->nstride = compute->size_array_cols; newtree->selfalloc = 0; newtree->first = newtree->second = NULL; newtree->nextra = 0; treestack[ntreestack++] = newtree; // c_ID[i] = scalar from per-atom vector } else if (nbracket == 1 && compute->peratom_flag && compute->size_peratom_cols == 0) { if (update->whichflag == 0) { if (compute->invoked_peratom != update->ntimestep) error->all(FLERR,"Compute used in variable between runs " "is not current"); } else if (!(compute->invoked_flag & INVOKED_PERATOM)) { compute->compute_peratom(); compute->invoked_flag |= INVOKED_PERATOM; } peratom2global(1,NULL,compute->vector_atom,1,index1, tree,treestack,ntreestack,argstack,nargstack); // c_ID[i][j] = scalar from per-atom array } else if (nbracket == 2 && compute->peratom_flag && compute->size_peratom_cols > 0) { if (index2 > compute->size_peratom_cols) error->all(FLERR,"Variable formula compute array " "is accessed out-of-range"); if (update->whichflag == 0) { if (compute->invoked_peratom != update->ntimestep) error->all(FLERR,"Compute used in variable between runs " "is not current"); } else if (!(compute->invoked_flag & INVOKED_PERATOM)) { compute->compute_peratom(); compute->invoked_flag |= INVOKED_PERATOM; } if (compute->array_atom) peratom2global(1,NULL,&compute->array_atom[0][index2-1], compute->size_peratom_cols,index1, tree,treestack,ntreestack,argstack,nargstack); else peratom2global(1,NULL,NULL, compute->size_peratom_cols,index1, tree,treestack,ntreestack,argstack,nargstack); // c_ID = vector from per-atom vector } else if (nbracket == 0 && compute->peratom_flag && compute->size_peratom_cols == 0) { if (tree == NULL) error->all(FLERR, "Per-atom compute in equal-style variable formula"); if (treetype == VECTOR) error->all(FLERR, "Per-atom compute in vector-style variable formula"); if (update->whichflag == 0) { if (compute->invoked_peratom != update->ntimestep) error->all(FLERR,"Compute used in variable between runs " "is not current"); } else if (!(compute->invoked_flag & INVOKED_PERATOM)) { compute->compute_peratom(); compute->invoked_flag |= INVOKED_PERATOM; } Tree *newtree = new Tree(); newtree->type = ATOMARRAY; newtree->array = compute->vector_atom; newtree->nstride = 1; newtree->selfalloc = 0; newtree->first = newtree->second = NULL; newtree->nextra = 0; treestack[ntreestack++] = newtree; // c_ID[i] = vector from per-atom array } else if (nbracket == 1 && compute->peratom_flag && compute->size_peratom_cols > 0) { if (tree == NULL) error->all(FLERR, "Per-atom compute in equal-style variable formula"); if (treetype == VECTOR) error->all(FLERR, "Per-atom compute in vector-style variable formula"); if (index1 > compute->size_peratom_cols) error->all(FLERR,"Variable formula compute array " "is accessed out-of-range"); if (update->whichflag == 0) { if (compute->invoked_peratom != update->ntimestep) error->all(FLERR,"Compute used in variable between runs " "is not current"); } else if (!(compute->invoked_flag & INVOKED_PERATOM)) { compute->compute_peratom(); compute->invoked_flag |= INVOKED_PERATOM; } Tree *newtree = new Tree(); newtree->type = ATOMARRAY; if (compute->array_atom) newtree->array = &compute->array_atom[0][index1-1]; else newtree->array = NULL; newtree->nstride = compute->size_peratom_cols; newtree->selfalloc = 0; newtree->first = newtree->second = NULL; newtree->nextra = 0; treestack[ntreestack++] = newtree; } else error->all(FLERR,"Mismatched compute in variable formula"); // ---------------- // fix // ---------------- } else if (strncmp(word,"f_",2) == 0 || strncmp(word,"F_",2) == 0) { if (domain->box_exist == 0) error->all(FLERR, "Variable evaluation before simulation box is defined"); // uppercase used to force access of // global vector vs global scalar, and global array vs global vector int lowercase = 1; if (word[0] == 'F') lowercase = 0; int ifix = modify->find_fix(word+2); if (ifix < 0) error->all(FLERR,"Invalid fix ID in variable formula"); Fix *fix = modify->fix[ifix]; // parse zero or one or two trailing brackets // point i beyond last bracket // nbracket = # of bracket pairs // index1,index2 = int inside each bracket pair, possibly an atom ID int nbracket; tagint index1,index2; if (str[i] != '[') nbracket = 0; else { nbracket = 1; ptr = &str[i]; index1 = int_between_brackets(ptr,1); i = ptr-str+1; if (str[i] == '[') { nbracket = 2; ptr = &str[i]; index2 = int_between_brackets(ptr,1); i = ptr-str+1; } } // f_ID = scalar from global scalar, must be lowercase if (nbracket == 0 && fix->scalar_flag && lowercase) { if (update->whichflag > 0 && update->ntimestep % fix->global_freq) error->all(FLERR,"Fix in variable not computed at compatible time"); value1 = fix->compute_scalar(); if (tree) { Tree *newtree = new Tree(); newtree->type = VALUE; newtree->value = value1; newtree->first = newtree->second = NULL; newtree->nextra = 0; treestack[ntreestack++] = newtree; } else argstack[nargstack++] = value1; // f_ID[i] = scalar from global vector, must be lowercase } else if (nbracket == 1 && fix->vector_flag && lowercase) { if (index1 > fix->size_vector && fix->size_vector_variable == 0) error->all(FLERR,"Variable formula fix vector is " "accessed out-of-range"); if (update->whichflag > 0 && update->ntimestep % fix->global_freq) error->all(FLERR,"Fix in variable not computed at compatible time"); value1 = fix->compute_vector(index1-1); if (tree) { Tree *newtree = new Tree(); newtree->type = VALUE; newtree->value = value1; newtree->first = newtree->second = NULL; newtree->nextra = 0; treestack[ntreestack++] = newtree; } else argstack[nargstack++] = value1; // f_ID[i][j] = scalar from global array, must be lowercase } else if (nbracket == 2 && fix->array_flag && lowercase) { if (index1 > fix->size_array_rows && fix->size_array_rows_variable == 0) error->all(FLERR, "Variable formula fix array is accessed out-of-range"); if (index2 > fix->size_array_cols) error->all(FLERR, "Variable formula fix array is accessed out-of-range"); if (update->whichflag > 0 && update->ntimestep % fix->global_freq) error->all(FLERR,"Fix in variable not computed at compatible time"); value1 = fix->compute_array(index1-1,index2-1); if (tree) { Tree *newtree = new Tree(); newtree->type = VALUE; newtree->value = value1; newtree->first = newtree->second = NULL; newtree->nextra = 0; treestack[ntreestack++] = newtree; } else argstack[nargstack++] = value1; // f_ID = vector from global vector, lowercase or uppercase } else if (nbracket == 0 && fix->vector_flag) { if (update->whichflag > 0 && update->ntimestep % fix->global_freq) error->all(FLERR,"Fix in variable not computed at compatible time"); if (tree == NULL) error->all(FLERR,"Fix global vector in " "equal-style variable formula"); if (treetype == ATOM) error->all(FLERR,"Fix global vector in " "atom-style variable formula"); if (fix->size_vector == 0) error->all(FLERR,"Variable formula fix vector is zero length"); int nvec = fix->size_vector; double *vec; memory->create(vec,nvec,"variable:values"); for (int m = 0; m < nvec; m++) vec[m] = fix->compute_vector(m); Tree *newtree = new Tree(); newtree->type = VECTORARRAY; newtree->array = vec; newtree->nvector = nvec; newtree->nstride = 1; newtree->selfalloc = 1; newtree->first = newtree->second = NULL; newtree->nextra = 0; treestack[ntreestack++] = newtree; // f_ID[i] = vector from global array, lowercase or uppercase } else if (nbracket == 1 && fix->array_flag) { if (update->whichflag > 0 && update->ntimestep % fix->global_freq) error->all(FLERR,"Fix in variable not computed at compatible time"); if (tree == NULL) error->all(FLERR,"Fix global vector in " "equal-style variable formula"); if (treetype == ATOM) error->all(FLERR,"Fix global vector in " "atom-style variable formula"); if (fix->size_array_rows == 0) error->all(FLERR,"Variable formula fix array is zero length"); int nvec = fix->size_array_rows; double *vec; memory->create(vec,nvec,"variable:values"); for (int m = 0; m < nvec; m++) vec[m] = fix->compute_array(m,index1-1); Tree *newtree = new Tree(); newtree->type = VECTORARRAY; newtree->array = vec; newtree->nvector = nvec; newtree->nstride = 1; newtree->selfalloc = 1; newtree->first = newtree->second = NULL; newtree->nextra = 0; treestack[ntreestack++] = newtree; // f_ID[i] = scalar from per-atom vector } else if (nbracket == 1 && fix->peratom_flag && fix->size_peratom_cols == 0) { if (update->whichflag > 0 && update->ntimestep % fix->peratom_freq) error->all(FLERR, "Fix in variable not computed at compatible time"); peratom2global(1,NULL,fix->vector_atom,1,index1, tree,treestack,ntreestack,argstack,nargstack); // f_ID[i][j] = scalar from per-atom array } else if (nbracket == 2 && fix->peratom_flag && fix->size_peratom_cols > 0) { if (index2 > fix->size_peratom_cols) error->all(FLERR, "Variable formula fix array is accessed out-of-range"); if (update->whichflag > 0 && update->ntimestep % fix->peratom_freq) error->all(FLERR,"Fix in variable not computed at compatible time"); if (fix->array_atom) peratom2global(1,NULL,&fix->array_atom[0][index2-1], fix->size_peratom_cols,index1, tree,treestack,ntreestack,argstack,nargstack); else peratom2global(1,NULL,NULL, fix->size_peratom_cols,index1, tree,treestack,ntreestack,argstack,nargstack); // f_ID = vector from per-atom vector } else if (nbracket == 0 && fix->peratom_flag && fix->size_peratom_cols == 0) { if (tree == NULL) error->all(FLERR,"Per-atom fix in equal-style variable formula"); if (update->whichflag > 0 && update->ntimestep % fix->peratom_freq) error->all(FLERR,"Fix in variable not computed at compatible time"); Tree *newtree = new Tree(); newtree->type = ATOMARRAY; newtree->array = fix->vector_atom; newtree->nstride = 1; newtree->selfalloc = 0; newtree->first = newtree->second = NULL; newtree->nextra = 0; treestack[ntreestack++] = newtree; // f_ID[i] = vector from per-atom array } else if (nbracket == 1 && fix->peratom_flag && fix->size_peratom_cols > 0) { if (tree == NULL) error->all(FLERR,"Per-atom fix in equal-style variable formula"); if (index1 > fix->size_peratom_cols) error->all(FLERR, "Variable formula fix array is accessed out-of-range"); if (update->whichflag > 0 && update->ntimestep % fix->peratom_freq) error->all(FLERR,"Fix in variable not computed at compatible time"); Tree *newtree = new Tree(); newtree->type = ATOMARRAY; if (fix->array_atom) newtree->array = &fix->array_atom[0][index1-1]; else newtree->array = NULL; newtree->nstride = fix->size_peratom_cols; newtree->selfalloc = 0; newtree->first = newtree->second = NULL; newtree->nextra = 0; treestack[ntreestack++] = newtree; } else error->all(FLERR,"Mismatched fix in variable formula"); // ---------------- // variable // ---------------- } else if (strncmp(word,"v_",2) == 0) { int ivar = find(word+2); if (ivar < 0) error->all(FLERR,"Invalid variable name in variable formula"); if (eval_in_progress[ivar]) error->all(FLERR,"Variable has circular dependency"); // parse zero or one trailing brackets // point i beyond last bracket // nbracket = # of bracket pairs // index = int inside bracket, possibly an atom ID int nbracket; tagint index; if (str[i] != '[') nbracket = 0; else { nbracket = 1; ptr = &str[i]; index = int_between_brackets(ptr,1); i = ptr-str+1; } // v_name = scalar from internal-style variable // access value directly if (nbracket == 0 && style[ivar] == INTERNAL) { value1 = dvalue[ivar]; if (tree) { Tree *newtree = new Tree(); newtree->type = VALUE; newtree->value = value1; newtree->first = newtree->second = NULL; newtree->nextra = 0; treestack[ntreestack++] = newtree; } else argstack[nargstack++] = value1; // v_name = scalar from non atom/atomfile & non vector-style variable // access value via retrieve() } else if (nbracket == 0 && style[ivar] != ATOM && style[ivar] != ATOMFILE && style[ivar] != VECTOR) { char *var = retrieve(word+2); if (var == NULL) error->all(FLERR,"Invalid variable evaluation in variable formula"); if (tree) { Tree *newtree = new Tree(); newtree->type = VALUE; newtree->value = atof(var); newtree->first = newtree->second = NULL; newtree->nextra = 0; treestack[ntreestack++] = newtree; } else argstack[nargstack++] = atof(var); // v_name = per-atom vector from atom-style variable // evaluate the atom-style variable as newtree } else if (nbracket == 0 && style[ivar] == ATOM) { if (tree == NULL) error->all(FLERR, "Atom-style variable in equal-style variable formula"); if (treetype == VECTOR) error->all(FLERR, "Atom-style variable in vector-style variable formula"); Tree *newtree; evaluate(data[ivar][0],&newtree); treestack[ntreestack++] = newtree; // v_name = per-atom vector from atomfile-style variable } else if (nbracket == 0 && style[ivar] == ATOMFILE) { if (tree == NULL) error->all(FLERR,"Atomfile-style variable in " "equal-style variable formula"); if (treetype == VECTOR) error->all(FLERR,"Atomfile-style variable in " "vector-style variable formula"); Tree *newtree = new Tree(); newtree->type = ATOMARRAY; newtree->array = reader[ivar]->fixstore->vstore; newtree->nstride = 1; newtree->selfalloc = 0; newtree->first = newtree->second = NULL; newtree->nextra = 0; treestack[ntreestack++] = newtree; // v_name = vector from vector-style variable // evaluate the vector-style variable, put result in newtree } else if (nbracket == 0 && style[ivar] == VECTOR) { if (tree == NULL) error->all(FLERR, "Vector-style variable in equal-style variable formula"); if (treetype == ATOM) error->all(FLERR, "Vector-style variable in atom-style variable formula"); double *vec; int nvec = compute_vector(ivar,&vec); Tree *newtree = new Tree(); newtree->type = VECTORARRAY; newtree->array = vec; newtree->nvector = nvec; newtree->nstride = 1; newtree->selfalloc = 0; newtree->first = newtree->second = NULL; newtree->nextra = 0; treestack[ntreestack++] = newtree; // v_name[N] = scalar from atom-style variable // compute the per-atom variable in result // use peratom2global to extract single value from result } else if (nbracket && style[ivar] == ATOM) { double *result; memory->create(result,atom->nlocal,"variable:result"); compute_atom(ivar,0,result,1,0); peratom2global(1,NULL,result,1,index, tree,treestack,ntreestack,argstack,nargstack); memory->destroy(result); // v_name[N] = scalar from atomfile-style variable } else if (nbracket && style[ivar] == ATOMFILE) { peratom2global(1,NULL,reader[ivar]->fixstore->vstore,1,index, tree,treestack,ntreestack,argstack,nargstack); // v_name[N] = scalar from vector-style variable // compute the vector-style variable, extract single value } else if (nbracket && style[ivar] == VECTOR) { double *vec; int nvec = compute_vector(ivar,&vec); if (index <= 0 || index > nvec) error->all(FLERR,"Invalid index into vector-style variable"); int m = index; // convert from tagint to int if (tree) { Tree *newtree = new Tree(); newtree->type = VALUE; newtree->value = vec[m-1]; newtree->first = newtree->second = NULL; newtree->nextra = 0; treestack[ntreestack++] = newtree; } else argstack[nargstack++] = vec[m-1]; } else error->all(FLERR,"Mismatched variable in variable formula"); // ---------------- // math/group/special function or atom value/vector or // constant or thermo keyword // ---------------- } else { // ---------------- // math or group or special function // ---------------- if (str[i] == '(') { char *contents; i = find_matching_paren(str,i,contents); i++; if (math_function(word,contents,tree, treestack,ntreestack,argstack,nargstack)); else if (group_function(word,contents,tree, treestack,ntreestack,argstack,nargstack)); else if (special_function(word,contents,tree, treestack,ntreestack,argstack,nargstack)); else error->all(FLERR,"Invalid math/group/special function " "in variable formula"); delete [] contents; // ---------------- // atom value // ---------------- } else if (str[i] == '[') { if (domain->box_exist == 0) error->all(FLERR, "Variable evaluation before simulation box is defined"); ptr = &str[i]; tagint id = int_between_brackets(ptr,1); i = ptr-str+1; peratom2global(0,word,NULL,0,id, tree,treestack,ntreestack,argstack,nargstack); // ---------------- // atom vector // ---------------- } else if (is_atom_vector(word)) { if (domain->box_exist == 0) error->all(FLERR, "Variable evaluation before simulation box is defined"); atom_vector(word,tree,treestack,ntreestack); // ---------------- // constant // ---------------- } else if (is_constant(word)) { value1 = constant(word); if (tree) { Tree *newtree = new Tree(); newtree->type = VALUE; newtree->value = value1; newtree->first = newtree->second = NULL; newtree->nextra = 0; treestack[ntreestack++] = newtree; } else argstack[nargstack++] = value1; // ---------------- // thermo keyword // ---------------- } else { if (domain->box_exist == 0) error->all(FLERR, "Variable evaluation before simulation box is defined"); int flag = output->thermo->evaluate_keyword(word,&value1); if (flag) error->all(FLERR,"Invalid thermo keyword in variable formula"); if (tree) { Tree *newtree = new Tree(); newtree->type = VALUE; newtree->value = value1; newtree->first = newtree->second = NULL; newtree->nextra = 0; treestack[ntreestack++] = newtree; } else argstack[nargstack++] = value1; } } delete [] word; // ---------------- // math operator, including end-of-string // ---------------- } else if (strchr("+-*/^<>=!&|%\0",onechar)) { if (onechar == '+') op = ADD; else if (onechar == '-') op = SUBTRACT; else if (onechar == '*') op = MULTIPLY; else if (onechar == '/') op = DIVIDE; else if (onechar == '%') op = MODULO; else if (onechar == '^') op = CARAT; else if (onechar == '=') { if (str[i+1] != '=') error->all(FLERR,"Invalid syntax in variable formula"); op = EQ; i++; } else if (onechar == '!') { if (str[i+1] == '=') { op = NE; i++; } else op = NOT; } else if (onechar == '<') { if (str[i+1] != '=') op = LT; else { op = LE; i++; } } else if (onechar == '>') { if (str[i+1] != '=') op = GT; else { op = GE; i++; } } else if (onechar == '&') { if (str[i+1] != '&') error->all(FLERR,"Invalid syntax in variable formula"); op = AND; i++; } else if (onechar == '|') { if (str[i+1] == '|') op = OR; else if (str[i+1] == '^') op = XOR; else error->all(FLERR,"Invalid syntax in variable formula"); i++; } else op = DONE; i++; if (op == SUBTRACT && expect == ARG) { opstack[nopstack++] = UNARY; continue; } if (op == NOT && expect == ARG) { opstack[nopstack++] = op; continue; } if (expect == ARG) error->all(FLERR,"Invalid syntax in variable formula"); expect = ARG; // evaluate stack as deep as possible while respecting precedence // before pushing current op onto stack while (nopstack && precedence[opstack[nopstack-1]] >= precedence[op]) { opprevious = opstack[--nopstack]; if (tree) { Tree *newtree = new Tree(); newtree->type = opprevious; if (opprevious == UNARY) { newtree->first = treestack[--ntreestack]; newtree->second = NULL; newtree->nextra = 0; } else { newtree->second = treestack[--ntreestack]; newtree->first = treestack[--ntreestack]; newtree->nextra = 0; } treestack[ntreestack++] = newtree; } else { value2 = argstack[--nargstack]; if (opprevious != UNARY && opprevious != NOT) value1 = argstack[--nargstack]; if (opprevious == ADD) argstack[nargstack++] = value1 + value2; else if (opprevious == SUBTRACT) argstack[nargstack++] = value1 - value2; else if (opprevious == MULTIPLY) argstack[nargstack++] = value1 * value2; else if (opprevious == DIVIDE) { if (value2 == 0.0) error->all(FLERR,"Divide by 0 in variable formula"); argstack[nargstack++] = value1 / value2; } else if (opprevious == MODULO) { if (value2 == 0.0) error->all(FLERR,"Modulo 0 in variable formula"); argstack[nargstack++] = fmod(value1,value2); } else if (opprevious == CARAT) { if (value2 == 0.0) - error->all(FLERR,"Power by 0 in variable formula"); - argstack[nargstack++] = pow(value1,value2); + argstack[nargstack++] = 1.0; + else if ((value1 == 0.0) && (value2 < 0.0)) + error->all(FLERR,"Invalid power expression in variable formula"); + else argstack[nargstack++] = pow(value1,value2); } else if (opprevious == UNARY) { argstack[nargstack++] = -value2; } else if (opprevious == NOT) { if (value2 == 0.0) argstack[nargstack++] = 1.0; else argstack[nargstack++] = 0.0; } else if (opprevious == EQ) { if (value1 == value2) argstack[nargstack++] = 1.0; else argstack[nargstack++] = 0.0; } else if (opprevious == NE) { if (value1 != value2) argstack[nargstack++] = 1.0; else argstack[nargstack++] = 0.0; } else if (opprevious == LT) { if (value1 < value2) argstack[nargstack++] = 1.0; else argstack[nargstack++] = 0.0; } else if (opprevious == LE) { if (value1 <= value2) argstack[nargstack++] = 1.0; else argstack[nargstack++] = 0.0; } else if (opprevious == GT) { if (value1 > value2) argstack[nargstack++] = 1.0; else argstack[nargstack++] = 0.0; } else if (opprevious == GE) { if (value1 >= value2) argstack[nargstack++] = 1.0; else argstack[nargstack++] = 0.0; } else if (opprevious == AND) { if (value1 != 0.0 && value2 != 0.0) argstack[nargstack++] = 1.0; else argstack[nargstack++] = 0.0; } else if (opprevious == OR) { if (value1 != 0.0 || value2 != 0.0) argstack[nargstack++] = 1.0; else argstack[nargstack++] = 0.0; } else if (opprevious == XOR) { if ((value1 == 0.0 && value2 != 0.0) || (value1 != 0.0 && value2 == 0.0)) argstack[nargstack++] = 1.0; else argstack[nargstack++] = 0.0; } } } // if end-of-string, break out of entire formula evaluation loop if (op == DONE) break; // push current operation onto stack opstack[nopstack++] = op; } else error->all(FLERR,"Invalid syntax in variable formula"); } if (nopstack) error->all(FLERR,"Invalid syntax in variable formula"); // for atom-style variable, return remaining tree // for equal-style variable, return remaining arg if (tree) { if (ntreestack != 1) error->all(FLERR,"Invalid syntax in variable formula"); *tree = treestack[0]; return 0.0; } else { if (nargstack != 1) error->all(FLERR,"Invalid syntax in variable formula"); return argstack[0]; } } /* ---------------------------------------------------------------------- one-time collapse of an atom-style variable parse tree tree was created by one-time parsing of formula string via evaluate() only keep tree nodes that depend on ATOMARRAY, TYPEARRAY, INTARRAY, BIGINTARRAY, VECTOR remainder is converted to single VALUE this enables optimal eval_tree loop over atoms customize by adding a function: sqrt(),exp(),ln(),log(),abs(),sin(),cos(),tan(),asin(),acos(),atan(), atan2(y,x),random(x,y,z),normal(x,y,z),ceil(),floor(),round(), ramp(x,y),stagger(x,y),logfreq(x,y,z),logfreq2(x,y,z), stride(x,y,z),vdisplace(x,y),swiggle(x,y,z),cwiggle(x,y,z), gmask(x),rmask(x),grmask(x,y) ---------------------------------------------------------------------- */ double Variable::collapse_tree(Tree *tree) { double arg1,arg2; if (tree->type == VALUE) return tree->value; if (tree->type == ATOMARRAY) return 0.0; if (tree->type == TYPEARRAY) return 0.0; if (tree->type == INTARRAY) return 0.0; if (tree->type == BIGINTARRAY) return 0.0; if (tree->type == VECTORARRAY) return 0.0; if (tree->type == ADD) { arg1 = collapse_tree(tree->first); arg2 = collapse_tree(tree->second); if (tree->first->type != VALUE || tree->second->type != VALUE) return 0.0; tree->type = VALUE; tree->value = arg1 + arg2; return tree->value; } if (tree->type == SUBTRACT) { arg1 = collapse_tree(tree->first); arg2 = collapse_tree(tree->second); if (tree->first->type != VALUE || tree->second->type != VALUE) return 0.0; tree->type = VALUE; tree->value = arg1 - arg2; return tree->value; } if (tree->type == MULTIPLY) { arg1 = collapse_tree(tree->first); arg2 = collapse_tree(tree->second); if (tree->first->type != VALUE || tree->second->type != VALUE) return 0.0; tree->type = VALUE; tree->value = arg1 * arg2; return tree->value; } if (tree->type == DIVIDE) { arg1 = collapse_tree(tree->first); arg2 = collapse_tree(tree->second); if (tree->first->type != VALUE || tree->second->type != VALUE) return 0.0; tree->type = VALUE; if (arg2 == 0.0) error->one(FLERR,"Divide by 0 in variable formula"); tree->value = arg1 / arg2; return tree->value; } if (tree->type == MODULO) { arg1 = collapse_tree(tree->first); arg2 = collapse_tree(tree->second); if (tree->first->type != VALUE || tree->second->type != VALUE) return 0.0; tree->type = VALUE; if (arg2 == 0.0) error->one(FLERR,"Modulo 0 in variable formula"); tree->value = fmod(arg1,arg2); return tree->value; } if (tree->type == CARAT) { arg1 = collapse_tree(tree->first); arg2 = collapse_tree(tree->second); if (tree->first->type != VALUE || tree->second->type != VALUE) return 0.0; tree->type = VALUE; if (arg2 == 0.0) error->one(FLERR,"Power by 0 in variable formula"); tree->value = pow(arg1,arg2); return tree->value; } if (tree->type == UNARY) { arg1 = collapse_tree(tree->first); if (tree->first->type != VALUE) return 0.0; tree->type = VALUE; tree->value = -arg1; return tree->value; } if (tree->type == NOT) { arg1 = collapse_tree(tree->first); if (tree->first->type != VALUE) return 0.0; tree->type = VALUE; if (arg1 == 0.0) tree->value = 1.0; else tree->value = 0.0; return tree->value; } if (tree->type == EQ) { arg1 = collapse_tree(tree->first); arg2 = collapse_tree(tree->second); if (tree->first->type != VALUE || tree->second->type != VALUE) return 0.0; tree->type = VALUE; if (arg1 == arg2) tree->value = 1.0; else tree->value = 0.0; return tree->value; } if (tree->type == NE) { arg1 = collapse_tree(tree->first); arg2 = collapse_tree(tree->second); if (tree->first->type != VALUE || tree->second->type != VALUE) return 0.0; tree->type = VALUE; if (arg1 != arg2) tree->value = 1.0; else tree->value = 0.0; return tree->value; } if (tree->type == LT) { arg1 = collapse_tree(tree->first); arg2 = collapse_tree(tree->second); if (tree->first->type != VALUE || tree->second->type != VALUE) return 0.0; tree->type = VALUE; if (arg1 < arg2) tree->value = 1.0; else tree->value = 0.0; return tree->value; } if (tree->type == LE) { arg1 = collapse_tree(tree->first); arg2 = collapse_tree(tree->second); if (tree->first->type != VALUE || tree->second->type != VALUE) return 0.0; tree->type = VALUE; if (arg1 <= arg2) tree->value = 1.0; else tree->value = 0.0; return tree->value; } if (tree->type == GT) { arg1 = collapse_tree(tree->first); arg2 = collapse_tree(tree->second); if (tree->first->type != VALUE || tree->second->type != VALUE) return 0.0; tree->type = VALUE; if (arg1 > arg2) tree->value = 1.0; else tree->value = 0.0; return tree->value; } if (tree->type == GE) { arg1 = collapse_tree(tree->first); arg2 = collapse_tree(tree->second); if (tree->first->type != VALUE || tree->second->type != VALUE) return 0.0; tree->type = VALUE; if (arg1 >= arg2) tree->value = 1.0; else tree->value = 0.0; return tree->value; } if (tree->type == AND) { arg1 = collapse_tree(tree->first); arg2 = collapse_tree(tree->second); if (tree->first->type != VALUE || tree->second->type != VALUE) return 0.0; tree->type = VALUE; if (arg1 != 0.0 && arg2 != 0.0) tree->value = 1.0; else tree->value = 0.0; return tree->value; } if (tree->type == OR) { arg1 = collapse_tree(tree->first); arg2 = collapse_tree(tree->second); if (tree->first->type != VALUE || tree->second->type != VALUE) return 0.0; tree->type = VALUE; if (arg1 != 0.0 || arg2 != 0.0) tree->value = 1.0; else tree->value = 0.0; return tree->value; } if (tree->type == XOR) { arg1 = collapse_tree(tree->first); arg2 = collapse_tree(tree->second); if (tree->first->type != VALUE || tree->second->type != VALUE) return 0.0; tree->type = VALUE; if ((arg1 == 0.0 && arg2 != 0.0) || (arg1 != 0.0 && arg2 == 0.0)) tree->value = 1.0; else tree->value = 0.0; return tree->value; } if (tree->type == SQRT) { arg1 = collapse_tree(tree->first); if (tree->first->type != VALUE) return 0.0; tree->type = VALUE; if (arg1 < 0.0) error->one(FLERR,"Sqrt of negative value in variable formula"); tree->value = sqrt(arg1); return tree->value; } if (tree->type == EXP) { arg1 = collapse_tree(tree->first); if (tree->first->type != VALUE) return 0.0; tree->type = VALUE; tree->value = exp(arg1); return tree->value; } if (tree->type == LN) { arg1 = collapse_tree(tree->first); if (tree->first->type != VALUE) return 0.0; tree->type = VALUE; if (arg1 <= 0.0) error->one(FLERR,"Log of zero/negative value in variable formula"); tree->value = log(arg1); return tree->value; } if (tree->type == LOG) { arg1 = collapse_tree(tree->first); if (tree->first->type != VALUE) return 0.0; tree->type = VALUE; if (arg1 <= 0.0) error->one(FLERR,"Log of zero/negative value in variable formula"); tree->value = log10(arg1); return tree->value; } if (tree->type == ABS) { arg1 = collapse_tree(tree->first); if (tree->first->type != VALUE) return 0.0; tree->type = VALUE; tree->value = fabs(arg1); return tree->value; } if (tree->type == SIN) { arg1 = collapse_tree(tree->first); if (tree->first->type != VALUE) return 0.0; tree->type = VALUE; tree->value = sin(arg1); return tree->value; } if (tree->type == COS) { arg1 = collapse_tree(tree->first); if (tree->first->type != VALUE) return 0.0; tree->type = VALUE; tree->value = cos(arg1); return tree->value; } if (tree->type == TAN) { arg1 = collapse_tree(tree->first); if (tree->first->type != VALUE) return 0.0; tree->type = VALUE; tree->value = tan(arg1); return tree->value; } if (tree->type == ASIN) { arg1 = collapse_tree(tree->first); if (tree->first->type != VALUE) return 0.0; tree->type = VALUE; if (arg1 < -1.0 || arg1 > 1.0) error->one(FLERR,"Arcsin of invalid value in variable formula"); tree->value = asin(arg1); return tree->value; } if (tree->type == ACOS) { arg1 = collapse_tree(tree->first); if (tree->first->type != VALUE) return 0.0; tree->type = VALUE; if (arg1 < -1.0 || arg1 > 1.0) error->one(FLERR,"Arccos of invalid value in variable formula"); tree->value = acos(arg1); return tree->value; } if (tree->type == ATAN) { arg1 = collapse_tree(tree->first); if (tree->first->type != VALUE) return 0.0; tree->type = VALUE; tree->value = atan(arg1); return tree->value; } if (tree->type == ATAN2) { arg1 = collapse_tree(tree->first); arg2 = collapse_tree(tree->second); if (tree->first->type != VALUE || tree->second->type != VALUE) return 0.0; tree->type = VALUE; tree->value = atan2(arg1,arg2); return tree->value; } // random() or normal() do not become a single collapsed value if (tree->type == RANDOM) { collapse_tree(tree->first); collapse_tree(tree->second); if (randomatom == NULL) { int seed = static_cast (collapse_tree(tree->extra[0])); if (seed <= 0) error->one(FLERR,"Invalid math function in variable formula"); randomatom = new RanMars(lmp,seed+me); } return 0.0; } if (tree->type == NORMAL) { collapse_tree(tree->first); double sigma = collapse_tree(tree->second); if (sigma < 0.0) error->one(FLERR,"Invalid math function in variable formula"); if (randomatom == NULL) { int seed = static_cast (collapse_tree(tree->extra[0])); if (seed <= 0) error->one(FLERR,"Invalid math function in variable formula"); randomatom = new RanMars(lmp,seed+me); } return 0.0; } if (tree->type == CEIL) { arg1 = collapse_tree(tree->first); if (tree->first->type != VALUE) return 0.0; tree->type = VALUE; tree->value = ceil(arg1); return tree->value; } if (tree->type == FLOOR) { arg1 = collapse_tree(tree->first); if (tree->first->type != VALUE) return 0.0; tree->type = VALUE; tree->value = floor(arg1); return tree->value; } if (tree->type == ROUND) { arg1 = collapse_tree(tree->first); if (tree->first->type != VALUE) return 0.0; tree->type = VALUE; tree->value = MYROUND(arg1); return tree->value; } if (tree->type == RAMP) { arg1 = collapse_tree(tree->first); arg2 = collapse_tree(tree->second); if (tree->first->type != VALUE || tree->second->type != VALUE) return 0.0; tree->type = VALUE; double delta = update->ntimestep - update->beginstep; if (delta != 0.0) delta /= update->endstep - update->beginstep; tree->value = arg1 + delta*(arg2-arg1); return tree->value; } if (tree->type == STAGGER) { int ivalue1 = static_cast (collapse_tree(tree->first)); int ivalue2 = static_cast (collapse_tree(tree->second)); if (tree->first->type != VALUE || tree->second->type != VALUE) return 0.0; tree->type = VALUE; if (ivalue1 <= 0 || ivalue2 <= 0 || ivalue1 <= ivalue2) error->one(FLERR,"Invalid math function in variable formula"); int lower = update->ntimestep/ivalue1 * ivalue1; int delta = update->ntimestep - lower; if (delta < ivalue2) tree->value = lower+ivalue2; else tree->value = lower+ivalue1; return tree->value; } if (tree->type == LOGFREQ) { int ivalue1 = static_cast (collapse_tree(tree->first)); int ivalue2 = static_cast (collapse_tree(tree->second)); int ivalue3 = static_cast (collapse_tree(tree->extra[0])); if (tree->first->type != VALUE || tree->second->type != VALUE || tree->extra[0]->type != VALUE) return 0.0; tree->type = VALUE; if (ivalue1 <= 0 || ivalue2 <= 0 || ivalue3 <= 0 || ivalue2 >= ivalue3) error->one(FLERR,"Invalid math function in variable formula"); if (update->ntimestep < ivalue1) tree->value = ivalue1; else { int lower = ivalue1; while (update->ntimestep >= ivalue3*lower) lower *= ivalue3; int multiple = update->ntimestep/lower; if (multiple < ivalue2) tree->value = (multiple+1)*lower; else tree->value = lower*ivalue3; } return tree->value; } if (tree->type == LOGFREQ2) { int ivalue1 = static_cast (collapse_tree(tree->first)); int ivalue2 = static_cast (collapse_tree(tree->second)); int ivalue3 = static_cast (collapse_tree(tree->extra[0])); if (tree->first->type != VALUE || tree->second->type != VALUE || tree->extra[0]->type != VALUE) return 0.0; tree->type = VALUE; if (ivalue1 <= 0 || ivalue2 <= 0 || ivalue3 <= 0 ) error->all(FLERR,"Invalid math function in variable formula"); if (update->ntimestep < ivalue1) tree->value = ivalue1; else { tree->value = ivalue1; double delta = ivalue1*(ivalue3-1.0)/ivalue2; int count = 0; while (update->ntimestep >= tree->value) { tree->value += delta; count++; if (count % ivalue2 == 0) delta *= ivalue3; } } tree->value = ceil(tree->value); return tree->value; } if (tree->type == STRIDE) { int ivalue1 = static_cast (collapse_tree(tree->first)); int ivalue2 = static_cast (collapse_tree(tree->second)); int ivalue3 = static_cast (collapse_tree(tree->extra[0])); if (tree->first->type != VALUE || tree->second->type != VALUE || tree->extra[0]->type != VALUE) return 0.0; tree->type = VALUE; if (ivalue1 < 0 || ivalue2 < 0 || ivalue3 <= 0 || ivalue1 > ivalue2) error->one(FLERR,"Invalid math function in variable formula"); if (update->ntimestep < ivalue1) tree->value = ivalue1; else if (update->ntimestep < ivalue2) { int offset = update->ntimestep - ivalue1; tree->value = ivalue1 + (offset/ivalue3)*ivalue3 + ivalue3; if (tree->value > ivalue2) tree->value = MAXBIGINT; } else tree->value = MAXBIGINT; return tree->value; } if (tree->type == STRIDE2) { int ivalue1 = static_cast (collapse_tree(tree->first)); int ivalue2 = static_cast (collapse_tree(tree->second)); int ivalue3 = static_cast (collapse_tree(tree->extra[0])); int ivalue4 = static_cast (collapse_tree(tree->extra[1])); int ivalue5 = static_cast (collapse_tree(tree->extra[2])); int ivalue6 = static_cast (collapse_tree(tree->extra[3])); if (tree->first->type != VALUE || tree->second->type != VALUE || tree->extra[0]->type != VALUE || tree->extra[1]->type != VALUE || tree->extra[2]->type != VALUE || tree->extra[3]->type != VALUE) return 0.0; tree->type = VALUE; if (ivalue1 < 0 || ivalue2 < 0 || ivalue3 <= 0 || ivalue1 > ivalue2) error->one(FLERR,"Invalid math function in variable formula"); if (ivalue4 < 0 || ivalue5 < 0 || ivalue6 <= 0 || ivalue4 > ivalue5) error->one(FLERR,"Invalid math function in variable formula"); if (ivalue4 < ivalue1 || ivalue5 > ivalue2) error->one(FLERR,"Invalid math function in variable formula"); bigint istep; if (update->ntimestep < ivalue1) istep = ivalue1; else if (update->ntimestep < ivalue2) { if (update->ntimestep < ivalue4 || update->ntimestep > ivalue5) { int offset = update->ntimestep - ivalue1; istep = ivalue1 + (offset/ivalue3)*ivalue3 + ivalue3; if (update->ntimestep < ivalue2 && istep > ivalue4) tree->value = ivalue4; } else { int offset = update->ntimestep - ivalue4; istep = ivalue4 + (offset/ivalue6)*ivalue6 + ivalue6; if (istep > ivalue5) { int offset = ivalue5 - ivalue1; istep = ivalue1 + (offset/ivalue3)*ivalue3 + ivalue3; if (istep > ivalue2) istep = MAXBIGINT; } } } else istep = MAXBIGINT; tree->value = istep; return tree->value; } if (tree->type == VDISPLACE) { double arg1 = collapse_tree(tree->first); double arg2 = collapse_tree(tree->second); if (tree->first->type != VALUE || tree->second->type != VALUE) return 0.0; tree->type = VALUE; double delta = update->ntimestep - update->beginstep; tree->value = arg1 + arg2*delta*update->dt; return tree->value; } if (tree->type == SWIGGLE) { double arg1 = collapse_tree(tree->first); double arg2 = collapse_tree(tree->second); double arg3 = collapse_tree(tree->extra[0]); if (tree->first->type != VALUE || tree->second->type != VALUE || tree->extra[0]->type != VALUE) return 0.0; tree->type = VALUE; if (arg3 == 0.0) error->one(FLERR,"Invalid math function in variable formula"); double delta = update->ntimestep - update->beginstep; double omega = 2.0*MY_PI/arg3; tree->value = arg1 + arg2*sin(omega*delta*update->dt); return tree->value; } if (tree->type == CWIGGLE) { double arg1 = collapse_tree(tree->first); double arg2 = collapse_tree(tree->second); double arg3 = collapse_tree(tree->extra[0]); if (tree->first->type != VALUE || tree->second->type != VALUE || tree->extra[0]->type != VALUE) return 0.0; tree->type = VALUE; if (arg3 == 0.0) error->one(FLERR,"Invalid math function in variable formula"); double delta = update->ntimestep - update->beginstep; double omega = 2.0*MY_PI/arg3; tree->value = arg1 + arg2*(1.0-cos(omega*delta*update->dt)); return tree->value; } // mask functions do not become a single collapsed value if (tree->type == GMASK) return 0.0; if (tree->type == RMASK) return 0.0; if (tree->type == GRMASK) return 0.0; return 0.0; } /* ---------------------------------------------------------------------- evaluate an atom-style or vector-style variable parse tree index I = atom I or vector index I tree was created by one-time parsing of formula string via evaluate() customize by adding a function: sqrt(),exp(),ln(),log(),sin(),cos(),tan(),asin(),acos(),atan(), atan2(y,x),random(x,y,z),normal(x,y,z),ceil(),floor(),round(), ramp(x,y),stagger(x,y),logfreq(x,y,z),logfreq2(x,y,z), stride(x,y,z),stride2(x,y,z),vdisplace(x,y),swiggle(x,y,z), cwiggle(x,y,z),gmask(x),rmask(x),grmask(x,y) ---------------------------------------------------------------------- */ double Variable::eval_tree(Tree *tree, int i) { double arg,arg1,arg2,arg3; if (tree->type == VALUE) return tree->value; if (tree->type == ATOMARRAY) return tree->array[i*tree->nstride]; if (tree->type == TYPEARRAY) return tree->array[atom->type[i]]; if (tree->type == INTARRAY) return (double) tree->iarray[i*tree->nstride]; if (tree->type == BIGINTARRAY) return (double) tree->barray[i*tree->nstride]; if (tree->type == VECTORARRAY) return tree->array[i*tree->nstride]; if (tree->type == ADD) return eval_tree(tree->first,i) + eval_tree(tree->second,i); if (tree->type == SUBTRACT) return eval_tree(tree->first,i) - eval_tree(tree->second,i); if (tree->type == MULTIPLY) return eval_tree(tree->first,i) * eval_tree(tree->second,i); if (tree->type == DIVIDE) { double denom = eval_tree(tree->second,i); if (denom == 0.0) error->one(FLERR,"Divide by 0 in variable formula"); return eval_tree(tree->first,i) / denom; } if (tree->type == MODULO) { double denom = eval_tree(tree->second,i); if (denom == 0.0) error->one(FLERR,"Modulo 0 in variable formula"); return fmod(eval_tree(tree->first,i),denom); } if (tree->type == CARAT) { double exponent = eval_tree(tree->second,i); if (exponent == 0.0) error->one(FLERR,"Power by 0 in variable formula"); return pow(eval_tree(tree->first,i),exponent); } if (tree->type == UNARY) return -eval_tree(tree->first,i); if (tree->type == NOT) { if (eval_tree(tree->first,i) == 0.0) return 1.0; else return 0.0; } if (tree->type == EQ) { if (eval_tree(tree->first,i) == eval_tree(tree->second,i)) return 1.0; else return 0.0; } if (tree->type == NE) { if (eval_tree(tree->first,i) != eval_tree(tree->second,i)) return 1.0; else return 0.0; } if (tree->type == LT) { if (eval_tree(tree->first,i) < eval_tree(tree->second,i)) return 1.0; else return 0.0; } if (tree->type == LE) { if (eval_tree(tree->first,i) <= eval_tree(tree->second,i)) return 1.0; else return 0.0; } if (tree->type == GT) { if (eval_tree(tree->first,i) > eval_tree(tree->second,i)) return 1.0; else return 0.0; } if (tree->type == GE) { if (eval_tree(tree->first,i) >= eval_tree(tree->second,i)) return 1.0; else return 0.0; } if (tree->type == AND) { if (eval_tree(tree->first,i) != 0.0 && eval_tree(tree->second,i) != 0.0) return 1.0; else return 0.0; } if (tree->type == OR) { if (eval_tree(tree->first,i) != 0.0 || eval_tree(tree->second,i) != 0.0) return 1.0; else return 0.0; } if (tree->type == XOR) { if ((eval_tree(tree->first,i) == 0.0 && eval_tree(tree->second,i) != 0.0) || (eval_tree(tree->first,i) != 0.0 && eval_tree(tree->second,i) == 0.0)) return 1.0; else return 0.0; } if (tree->type == SQRT) { arg1 = eval_tree(tree->first,i); if (arg1 < 0.0) error->one(FLERR,"Sqrt of negative value in variable formula"); return sqrt(arg1); } if (tree->type == EXP) return exp(eval_tree(tree->first,i)); if (tree->type == LN) { arg1 = eval_tree(tree->first,i); if (arg1 <= 0.0) error->one(FLERR,"Log of zero/negative value in variable formula"); return log(arg1); } if (tree->type == LOG) { arg1 = eval_tree(tree->first,i); if (arg1 <= 0.0) error->one(FLERR,"Log of zero/negative value in variable formula"); return log10(arg1); } if (tree->type == ABS) return fabs(eval_tree(tree->first,i)); if (tree->type == SIN) return sin(eval_tree(tree->first,i)); if (tree->type == COS) return cos(eval_tree(tree->first,i)); if (tree->type == TAN) return tan(eval_tree(tree->first,i)); if (tree->type == ASIN) { arg1 = eval_tree(tree->first,i); if (arg1 < -1.0 || arg1 > 1.0) error->one(FLERR,"Arcsin of invalid value in variable formula"); return asin(arg1); } if (tree->type == ACOS) { arg1 = eval_tree(tree->first,i); if (arg1 < -1.0 || arg1 > 1.0) error->one(FLERR,"Arccos of invalid value in variable formula"); return acos(arg1); } if (tree->type == ATAN) return atan(eval_tree(tree->first,i)); if (tree->type == ATAN2) return atan2(eval_tree(tree->first,i),eval_tree(tree->second,i)); if (tree->type == RANDOM) { double lower = eval_tree(tree->first,i); double upper = eval_tree(tree->second,i); if (randomatom == NULL) { int seed = static_cast (eval_tree(tree->extra[0],i)); if (seed <= 0) error->one(FLERR,"Invalid math function in variable formula"); randomatom = new RanMars(lmp,seed+me); } return randomatom->uniform()*(upper-lower)+lower; } if (tree->type == NORMAL) { double mu = eval_tree(tree->first,i); double sigma = eval_tree(tree->second,i); if (sigma < 0.0) error->one(FLERR,"Invalid math function in variable formula"); if (randomatom == NULL) { int seed = static_cast (eval_tree(tree->extra[0],i)); if (seed <= 0) error->one(FLERR,"Invalid math function in variable formula"); randomatom = new RanMars(lmp,seed+me); } return mu + sigma*randomatom->gaussian(); } if (tree->type == CEIL) return ceil(eval_tree(tree->first,i)); if (tree->type == FLOOR) return floor(eval_tree(tree->first,i)); if (tree->type == ROUND) return MYROUND(eval_tree(tree->first,i)); if (tree->type == RAMP) { arg1 = eval_tree(tree->first,i); arg2 = eval_tree(tree->second,i); double delta = update->ntimestep - update->beginstep; if (delta != 0.0) delta /= update->endstep - update->beginstep; arg = arg1 + delta*(arg2-arg1); return arg; } if (tree->type == STAGGER) { int ivalue1 = static_cast (eval_tree(tree->first,i)); int ivalue2 = static_cast (eval_tree(tree->second,i)); if (ivalue1 <= 0 || ivalue2 <= 0 || ivalue1 <= ivalue2) error->one(FLERR,"Invalid math function in variable formula"); int lower = update->ntimestep/ivalue1 * ivalue1; int delta = update->ntimestep - lower; if (delta < ivalue2) arg = lower+ivalue2; else arg = lower+ivalue1; return arg; } if (tree->type == LOGFREQ) { int ivalue1 = static_cast (eval_tree(tree->first,i)); int ivalue2 = static_cast (eval_tree(tree->second,i)); int ivalue3 = static_cast (eval_tree(tree->extra[0],i)); if (ivalue1 <= 0 || ivalue2 <= 0 || ivalue3 <= 0 || ivalue2 >= ivalue3) error->one(FLERR,"Invalid math function in variable formula"); if (update->ntimestep < ivalue1) arg = ivalue1; else { int lower = ivalue1; while (update->ntimestep >= ivalue3*lower) lower *= ivalue3; int multiple = update->ntimestep/lower; if (multiple < ivalue2) arg = (multiple+1)*lower; else arg = lower*ivalue3; } return arg; } if (tree->type == LOGFREQ2) { int ivalue1 = static_cast (eval_tree(tree->first,i)); int ivalue2 = static_cast (eval_tree(tree->second,i)); int ivalue3 = static_cast (eval_tree(tree->extra[0],i)); if (ivalue1 <= 0 || ivalue2 <= 0 || ivalue3 <= 0 ) error->all(FLERR,"Invalid math function in variable formula"); if (update->ntimestep < ivalue1) arg = ivalue1; else { arg = ivalue1; double delta = ivalue1*(ivalue3-1.0)/ivalue2; int count = 0; while (update->ntimestep >= arg) { arg += delta; count++; if (count % ivalue2 == 0) delta *= ivalue3; } } arg = ceil(arg); return arg; } if (tree->type == STRIDE) { int ivalue1 = static_cast (eval_tree(tree->first,i)); int ivalue2 = static_cast (eval_tree(tree->second,i)); int ivalue3 = static_cast (eval_tree(tree->extra[0],i)); if (ivalue1 < 0 || ivalue2 < 0 || ivalue3 <= 0 || ivalue1 > ivalue2) error->one(FLERR,"Invalid math function in variable formula"); if (update->ntimestep < ivalue1) arg = ivalue1; else if (update->ntimestep < ivalue2) { int offset = update->ntimestep - ivalue1; arg = ivalue1 + (offset/ivalue3)*ivalue3 + ivalue3; if (arg > ivalue2) arg = MAXBIGINT; } else arg = MAXBIGINT; return arg; } if (tree->type == STRIDE2) { int ivalue1 = static_cast (eval_tree(tree->first,i)); int ivalue2 = static_cast (eval_tree(tree->second,i)); int ivalue3 = static_cast (eval_tree(tree->extra[0],i)); int ivalue4 = static_cast (eval_tree(tree->extra[1],i)); int ivalue5 = static_cast (eval_tree(tree->extra[2],i)); int ivalue6 = static_cast (eval_tree(tree->extra[3],i)); if (ivalue1 < 0 || ivalue2 < 0 || ivalue3 <= 0 || ivalue1 > ivalue2) error->one(FLERR,"Invalid math function in variable formula"); if (ivalue4 < 0 || ivalue5 < 0 || ivalue6 <= 0 || ivalue4 > ivalue5) error->one(FLERR,"Invalid math function in variable formula"); if (ivalue4 < ivalue1 || ivalue5 > ivalue2) error->one(FLERR,"Invalid math function in variable formula"); bigint istep; if (update->ntimestep < ivalue1) istep = ivalue1; else if (update->ntimestep < ivalue2) { if (update->ntimestep < ivalue4 || update->ntimestep > ivalue5) { int offset = update->ntimestep - ivalue1; istep = ivalue1 + (offset/ivalue3)*ivalue3 + ivalue3; if (update->ntimestep < ivalue2 && istep > ivalue4) tree->value = ivalue4; } else { int offset = update->ntimestep - ivalue4; istep = ivalue4 + (offset/ivalue6)*ivalue6 + ivalue6; if (istep > ivalue5) { int offset = ivalue5 - ivalue1; istep = ivalue1 + (offset/ivalue3)*ivalue3 + ivalue3; if (istep > ivalue2) istep = MAXBIGINT; } } } else istep = MAXBIGINT; arg = istep; return arg; } if (tree->type == VDISPLACE) { arg1 = eval_tree(tree->first,i); arg2 = eval_tree(tree->second,i); double delta = update->ntimestep - update->beginstep; arg = arg1 + arg2*delta*update->dt; return arg; } if (tree->type == SWIGGLE) { arg1 = eval_tree(tree->first,i); arg2 = eval_tree(tree->second,i); arg3 = eval_tree(tree->extra[0],i); if (arg3 == 0.0) error->one(FLERR,"Invalid math function in variable formula"); double delta = update->ntimestep - update->beginstep; double omega = 2.0*MY_PI/arg3; arg = arg1 + arg2*sin(omega*delta*update->dt); return arg; } if (tree->type == CWIGGLE) { arg1 = eval_tree(tree->first,i); arg2 = eval_tree(tree->second,i); arg3 = eval_tree(tree->extra[0],i); if (arg3 == 0.0) error->one(FLERR,"Invalid math function in variable formula"); double delta = update->ntimestep - update->beginstep; double omega = 2.0*MY_PI/arg3; arg = arg1 + arg2*(1.0-cos(omega*delta*update->dt)); return arg; } if (tree->type == GMASK) { if (atom->mask[i] & tree->ivalue1) return 1.0; else return 0.0; } if (tree->type == RMASK) { if (domain->regions[tree->ivalue1]->match(atom->x[i][0], atom->x[i][1], atom->x[i][2])) return 1.0; else return 0.0; } if (tree->type == GRMASK) { if ((atom->mask[i] & tree->ivalue1) && (domain->regions[tree->ivalue2]->match(atom->x[i][0], atom->x[i][1], atom->x[i][2]))) return 1.0; else return 0.0; } return 0.0; } /* ---------------------------------------------------------------------- scan entire tree, find size of vectors for vector-style variable return N for consistent vector size return 0 for no vector size, caller flags as error return -1 for inconsistent vector size, caller flags as error ------------------------------------------------------------------------- */ int Variable::size_tree_vector(Tree *tree) { int nsize = 0; if (tree->type == VECTORARRAY) nsize = tree->nvector; if (tree->first) nsize = compare_tree_vector(nsize, size_tree_vector(tree->first)); if (tree->second) nsize = compare_tree_vector(nsize, size_tree_vector(tree->second)); if (tree->nextra) { for (int i = 0; i < tree->nextra; i++) nsize = compare_tree_vector(nsize,size_tree_vector(tree->extra[i])); } return nsize; } /* ---------------------------------------------------------------------- compare size of two vectors for vector-style variable return positive size if same or one has no size 0 return -1 error if one is already error or not same positive size ------------------------------------------------------------------------- */ int Variable::compare_tree_vector(int i, int j) { if (i < 0 || j < 0) return -1; if (i == 0 || j == 0) return MAX(i,j); if (i != j) return -1; return i; } /* ---------------------------------------------------------------------- */ void Variable::free_tree(Tree *tree) { if (tree->first) free_tree(tree->first); if (tree->second) free_tree(tree->second); if (tree->nextra) { for (int i = 0; i < tree->nextra; i++) free_tree(tree->extra[i]); delete [] tree->extra; } if (tree->selfalloc) memory->destroy(tree->array); delete tree; } /* ---------------------------------------------------------------------- find matching parenthesis in str, allocate contents = str between parens i = left paren return loc or right paren ------------------------------------------------------------------------- */ int Variable::find_matching_paren(char *str, int i,char *&contents) { // istop = matching ')' at same level, allowing for nested parens int istart = i; int ilevel = 0; while (1) { i++; if (!str[i]) break; if (str[i] == '(') ilevel++; else if (str[i] == ')' && ilevel) ilevel--; else if (str[i] == ')') break; } if (!str[i]) error->all(FLERR,"Invalid syntax in variable formula"); int istop = i; int n = istop - istart - 1; contents = new char[n+1]; strncpy(contents,&str[istart+1],n); contents[n] = '\0'; return istop; } /* ---------------------------------------------------------------------- find int between brackets and return it return a tagint, since value can be an atom ID ptr initially points to left bracket return it pointing to right bracket error if no right bracket or brackets are empty or index = 0 if varallow = 0: error if any between-bracket chars are non-digits if varallow = 1: also allow for v_name, where name is variable name ------------------------------------------------------------------------- */ tagint Variable::int_between_brackets(char *&ptr, int varallow) { int varflag; tagint index; char *start = ++ptr; if (varallow && strstr(ptr,"v_") == ptr) { varflag = 1; while (*ptr && *ptr != ']') { if (!isalnum(*ptr) && *ptr != '_') error->all(FLERR,"Variable name between brackets must be " "alphanumeric or underscore characters"); ptr++; } } else { varflag = 0; while (*ptr && *ptr != ']') { if (!isdigit(*ptr)) error->all(FLERR,"Non digit character between brackets in variable"); ptr++; } } if (*ptr != ']') error->all(FLERR,"Mismatched brackets in variable"); if (ptr == start) error->all(FLERR,"Empty brackets in variable"); *ptr = '\0'; // evaluate index as floating point variable or as tagint via ATOTAGINT() if (varflag) { char *id = start+2; int ivar = find(id); if (ivar < 0) error->all(FLERR,"Invalid variable name in variable formula"); char *var = retrieve(id); if (var == NULL) error->all(FLERR,"Invalid variable evaluation in variable formula"); index = static_cast (atof(var)); } else index = ATOTAGINT(start); *ptr = ']'; if (index == 0) error->all(FLERR,"Index between variable brackets must be positive"); return index; } /* ---------------------------------------------------------------------- process a math function in formula push result onto tree or arg stack word = math function contents = str between parentheses with comma-separated args return 0 if not a match, 1 if successfully processed customize by adding a math function: sqrt(),exp(),ln(),log(),abs(),sin(),cos(),tan(),asin(),acos(),atan(), atan2(y,x),random(x,y,z),normal(x,y,z),ceil(),floor(),round(), ramp(x,y),stagger(x,y),logfreq(x,y,z),logfreq2(x,y,z), stride(x,y,z),stride2(x,y,z,a,b,c),vdisplace(x,y),swiggle(x,y,z), cwiggle(x,y,z) ------------------------------------------------------------------------- */ int Variable::math_function(char *word, char *contents, Tree **tree, Tree **treestack, int &ntreestack, double *argstack, int &nargstack) { // word not a match to any math function if (strcmp(word,"sqrt") && strcmp(word,"exp") && strcmp(word,"ln") && strcmp(word,"log") && strcmp(word,"abs") && strcmp(word,"sin") && strcmp(word,"cos") && strcmp(word,"tan") && strcmp(word,"asin") && strcmp(word,"acos") && strcmp(word,"atan") && strcmp(word,"atan2") && strcmp(word,"random") && strcmp(word,"normal") && strcmp(word,"ceil") && strcmp(word,"floor") && strcmp(word,"round") && strcmp(word,"ramp") && strcmp(word,"stagger") && strcmp(word,"logfreq") && strcmp(word,"logfreq2") && strcmp(word,"stride") && strcmp(word,"stride2") && strcmp(word,"vdisplace") && strcmp(word,"swiggle") && strcmp(word,"cwiggle")) return 0; // parse contents for comma-separated args // narg = number of args, args = strings between commas char *args[MAXFUNCARG]; int narg = parse_args(contents,args); Tree *newtree; double value1,value2; double values[MAXFUNCARG-2]; if (tree) { newtree = new Tree(); newtree->first = newtree->second = NULL; newtree->nextra = 0; Tree *argtree; evaluate(args[0],&argtree); newtree->first = argtree; if (narg > 1) { evaluate(args[1],&argtree); newtree->second = argtree; if (narg > 2) { newtree->nextra = narg-2; newtree->extra = new Tree*[narg-2]; for (int i = 2; i < narg; i++) { evaluate(args[i],&argtree); newtree->extra[i-2] = argtree; } } } treestack[ntreestack++] = newtree; } else { value1 = evaluate(args[0],NULL); if (narg > 1) { value2 = evaluate(args[1],NULL); if (narg > 2) { for (int i = 2; i < narg; i++) values[i-2] = evaluate(args[i],NULL); } } } // individual math functions // customize by adding a function if (strcmp(word,"sqrt") == 0) { if (narg != 1) error->all(FLERR,"Invalid math function in variable formula"); if (tree) newtree->type = SQRT; else { if (value1 < 0.0) error->all(FLERR,"Sqrt of negative value in variable formula"); argstack[nargstack++] = sqrt(value1); } } else if (strcmp(word,"exp") == 0) { if (narg != 1) error->all(FLERR,"Invalid math function in variable formula"); if (tree) newtree->type = EXP; else argstack[nargstack++] = exp(value1); } else if (strcmp(word,"ln") == 0) { if (narg != 1) error->all(FLERR,"Invalid math function in variable formula"); if (tree) newtree->type = LN; else { if (value1 <= 0.0) error->all(FLERR,"Log of zero/negative value in variable formula"); argstack[nargstack++] = log(value1); } } else if (strcmp(word,"log") == 0) { if (narg != 1) error->all(FLERR,"Invalid math function in variable formula"); if (tree) newtree->type = LOG; else { if (value1 <= 0.0) error->all(FLERR,"Log of zero/negative value in variable formula"); argstack[nargstack++] = log10(value1); } } else if (strcmp(word,"abs") == 0) { if (narg != 1) error->all(FLERR,"Invalid math function in variable formula"); if (tree) newtree->type = ABS; else argstack[nargstack++] = fabs(value1); } else if (strcmp(word,"sin") == 0) { if (narg != 1) error->all(FLERR,"Invalid math function in variable formula"); if (tree) newtree->type = SIN; else argstack[nargstack++] = sin(value1); } else if (strcmp(word,"cos") == 0) { if (narg != 1) error->all(FLERR,"Invalid math function in variable formula"); if (tree) newtree->type = COS; else argstack[nargstack++] = cos(value1); } else if (strcmp(word,"tan") == 0) { if (narg != 1) error->all(FLERR,"Invalid math function in variable formula"); if (tree) newtree->type = TAN; else argstack[nargstack++] = tan(value1); } else if (strcmp(word,"asin") == 0) { if (narg != 1) error->all(FLERR,"Invalid math function in variable formula"); if (tree) newtree->type = ASIN; else { if (value1 < -1.0 || value1 > 1.0) error->all(FLERR,"Arcsin of invalid value in variable formula"); argstack[nargstack++] = asin(value1); } } else if (strcmp(word,"acos") == 0) { if (narg != 1) error->all(FLERR,"Invalid math function in variable formula"); if (tree) newtree->type = ACOS; else { if (value1 < -1.0 || value1 > 1.0) error->all(FLERR,"Arccos of invalid value in variable formula"); argstack[nargstack++] = acos(value1); } } else if (strcmp(word,"atan") == 0) { if (narg != 1) error->all(FLERR,"Invalid math function in variable formula"); if (tree) newtree->type = ATAN; else argstack[nargstack++] = atan(value1); } else if (strcmp(word,"atan2") == 0) { if (narg != 2) error->all(FLERR,"Invalid math function in variable formula"); if (tree) newtree->type = ATAN2; else argstack[nargstack++] = atan2(value1,value2); } else if (strcmp(word,"random") == 0) { if (narg != 3) error->all(FLERR,"Invalid math function in variable formula"); if (tree) newtree->type = RANDOM; else { if (randomequal == NULL) { int seed = static_cast (values[0]); if (seed <= 0) error->all(FLERR,"Invalid math function in variable formula"); randomequal = new RanMars(lmp,seed); } argstack[nargstack++] = randomequal->uniform()*(value2-value1) + value1; } } else if (strcmp(word,"normal") == 0) { if (narg != 3) error->all(FLERR,"Invalid math function in variable formula"); if (tree) newtree->type = NORMAL; else { if (value2 < 0.0) error->all(FLERR,"Invalid math function in variable formula"); if (randomequal == NULL) { int seed = static_cast (values[0]); if (seed <= 0) error->all(FLERR,"Invalid math function in variable formula"); randomequal = new RanMars(lmp,seed); } argstack[nargstack++] = value1 + value2*randomequal->gaussian(); } } else if (strcmp(word,"ceil") == 0) { if (narg != 1) error->all(FLERR,"Invalid math function in variable formula"); if (tree) newtree->type = CEIL; else argstack[nargstack++] = ceil(value1); } else if (strcmp(word,"floor") == 0) { if (narg != 1) error->all(FLERR,"Invalid math function in variable formula"); if (tree) newtree->type = FLOOR; else argstack[nargstack++] = floor(value1); } else if (strcmp(word,"round") == 0) { if (narg != 1) error->all(FLERR,"Invalid math function in variable formula"); if (tree) newtree->type = ROUND; else argstack[nargstack++] = MYROUND(value1); } else if (strcmp(word,"ramp") == 0) { if (narg != 2) error->all(FLERR,"Invalid math function in variable formula"); if (update->whichflag == 0) error->all(FLERR,"Cannot use ramp in variable formula between runs"); if (tree) newtree->type = RAMP; else { double delta = update->ntimestep - update->beginstep; if (delta != 0.0) delta /= update->endstep - update->beginstep; double value = value1 + delta*(value2-value1); argstack[nargstack++] = value; } } else if (strcmp(word,"stagger") == 0) { if (narg != 2) error->all(FLERR,"Invalid math function in variable formula"); if (tree) newtree->type = STAGGER; else { int ivalue1 = static_cast (value1); int ivalue2 = static_cast (value2); if (ivalue1 <= 0 || ivalue2 <= 0 || ivalue1 <= ivalue2) error->all(FLERR,"Invalid math function in variable formula"); int lower = update->ntimestep/ivalue1 * ivalue1; int delta = update->ntimestep - lower; double value; if (delta < ivalue2) value = lower+ivalue2; else value = lower+ivalue1; argstack[nargstack++] = value; } } else if (strcmp(word,"logfreq") == 0) { if (narg != 3) error->all(FLERR,"Invalid math function in variable formula"); if (tree) newtree->type = LOGFREQ; else { int ivalue1 = static_cast (value1); int ivalue2 = static_cast (value2); int ivalue3 = static_cast (values[0]); if (ivalue1 <= 0 || ivalue2 <= 0 || ivalue3 <= 0 || ivalue2 >= ivalue3) error->all(FLERR,"Invalid math function in variable formula"); double value; if (update->ntimestep < ivalue1) value = ivalue1; else { int lower = ivalue1; while (update->ntimestep >= ivalue3*lower) lower *= ivalue3; int multiple = update->ntimestep/lower; if (multiple < ivalue2) value = (multiple+1)*lower; else value = lower*ivalue3; } argstack[nargstack++] = value; } } else if (strcmp(word,"logfreq2") == 0) { if (narg != 3) error->all(FLERR,"Invalid math function in variable formula"); if (tree) newtree->type = LOGFREQ2; else { int ivalue1 = static_cast (value1); int ivalue2 = static_cast (value2); int ivalue3 = static_cast (values[0]); if (ivalue1 <= 0 || ivalue2 <= 0 || ivalue3 <= 0 ) error->all(FLERR,"Invalid math function in variable formula"); double value; if (update->ntimestep < ivalue1) value = ivalue1; else { value = ivalue1; double delta = ivalue1*(ivalue3-1.0)/ivalue2; int count = 0; while (update->ntimestep >= value) { value += delta; count++; if (count % ivalue2 == 0) delta *= ivalue3; } } argstack[nargstack++] = ceil(value); } } else if (strcmp(word,"stride") == 0) { if (narg != 3) error->all(FLERR,"Invalid math function in variable formula"); if (tree) newtree->type = STRIDE; else { int ivalue1 = static_cast (value1); int ivalue2 = static_cast (value2); int ivalue3 = static_cast (values[0]); if (ivalue1 < 0 || ivalue2 < 0 || ivalue3 <= 0 || ivalue1 > ivalue2) error->one(FLERR,"Invalid math function in variable formula"); double value; if (update->ntimestep < ivalue1) value = ivalue1; else if (update->ntimestep < ivalue2) { int offset = update->ntimestep - ivalue1; value = ivalue1 + (offset/ivalue3)*ivalue3 + ivalue3; if (value > ivalue2) value = MAXBIGINT; } else value = MAXBIGINT; argstack[nargstack++] = value; } } else if (strcmp(word,"stride2") == 0) { if (narg != 6) error->all(FLERR,"Invalid math function in variable formula"); if (tree) newtree->type = STRIDE2; else { int ivalue1 = static_cast (value1); int ivalue2 = static_cast (value2); int ivalue3 = static_cast (values[0]); int ivalue4 = static_cast (values[1]); int ivalue5 = static_cast (values[2]); int ivalue6 = static_cast (values[3]); if (ivalue1 < 0 || ivalue2 < 0 || ivalue3 <= 0 || ivalue1 > ivalue2) error->one(FLERR,"Invalid math function in variable formula"); if (ivalue4 < 0 || ivalue5 < 0 || ivalue6 <= 0 || ivalue4 > ivalue5) error->one(FLERR,"Invalid math function in variable formula"); if (ivalue4 < ivalue1 || ivalue5 > ivalue2) error->one(FLERR,"Invalid math function in variable formula"); bigint istep; if (update->ntimestep < ivalue1) istep = ivalue1; else if (update->ntimestep < ivalue2) { if (update->ntimestep < ivalue4 || update->ntimestep > ivalue5) { int offset = update->ntimestep - ivalue1; istep = ivalue1 + (offset/ivalue3)*ivalue3 + ivalue3; if (update->ntimestep < ivalue4 && istep > ivalue4) istep = ivalue4; } else { int offset = update->ntimestep - ivalue4; istep = ivalue4 + (offset/ivalue6)*ivalue6 + ivalue6; if (istep > ivalue5) { int offset = ivalue5 - ivalue1; istep = ivalue1 + (offset/ivalue3)*ivalue3 + ivalue3; if (istep > ivalue2) istep = MAXBIGINT; } } } else istep = MAXBIGINT; double value = istep; argstack[nargstack++] = value; } } else if (strcmp(word,"vdisplace") == 0) { if (narg != 2) error->all(FLERR,"Invalid math function in variable formula"); if (update->whichflag == 0) error->all(FLERR,"Cannot use vdisplace in variable formula between runs"); if (tree) newtree->type = VDISPLACE; else { double delta = update->ntimestep - update->beginstep; double value = value1 + value2*delta*update->dt; argstack[nargstack++] = value; } } else if (strcmp(word,"swiggle") == 0) { if (narg != 3) error->all(FLERR,"Invalid math function in variable formula"); if (update->whichflag == 0) error->all(FLERR,"Cannot use swiggle in variable formula between runs"); if (tree) newtree->type = CWIGGLE; else { if (values[0] == 0.0) error->all(FLERR,"Invalid math function in variable formula"); double delta = update->ntimestep - update->beginstep; double omega = 2.0*MY_PI/values[0]; double value = value1 + value2*sin(omega*delta*update->dt); argstack[nargstack++] = value; } } else if (strcmp(word,"cwiggle") == 0) { if (narg != 3) error->all(FLERR,"Invalid math function in variable formula"); if (update->whichflag == 0) error->all(FLERR,"Cannot use cwiggle in variable formula between runs"); if (tree) newtree->type = CWIGGLE; else { if (values[0] == 0.0) error->all(FLERR,"Invalid math function in variable formula"); double delta = update->ntimestep - update->beginstep; double omega = 2.0*MY_PI/values[0]; double value = value1 + value2*(1.0-cos(omega*delta*update->dt)); argstack[nargstack++] = value; } } // delete stored args for (int i = 0; i < narg; i++) delete [] args[i]; return 1; } /* ---------------------------------------------------------------------- process a group function in formula with optional region arg push result onto tree or arg stack word = group function contents = str between parentheses with one,two,three args return 0 if not a match, 1 if successfully processed customize by adding a group function with optional region arg: count(group),mass(group),charge(group), xcm(group,dim),vcm(group,dim),fcm(group,dim), bound(group,xmin),gyration(group),ke(group),angmom(group,dim), torque(group,dim),inertia(group,dim),omega(group,dim) ------------------------------------------------------------------------- */ int Variable::group_function(char *word, char *contents, Tree **tree, Tree **treestack, int &ntreestack, double *argstack, int &nargstack) { // word not a match to any group function if (strcmp(word,"count") && strcmp(word,"mass") && strcmp(word,"charge") && strcmp(word,"xcm") && strcmp(word,"vcm") && strcmp(word,"fcm") && strcmp(word,"bound") && strcmp(word,"gyration") && strcmp(word,"ke") && strcmp(word,"angmom") && strcmp(word,"torque") && strcmp(word,"inertia") && strcmp(word,"omega")) return 0; // parse contents for comma-separated args // narg = number of args, args = strings between commas char *args[MAXFUNCARG]; int narg = parse_args(contents,args); // group to operate on int igroup = group->find(args[0]); if (igroup == -1) error->all(FLERR,"Group ID in variable formula does not exist"); // match word to group function double value; if (strcmp(word,"count") == 0) { if (narg == 1) value = group->count(igroup); else if (narg == 2) value = group->count(igroup,region_function(args[1])); else error->all(FLERR,"Invalid group function in variable formula"); } else if (strcmp(word,"mass") == 0) { if (narg == 1) value = group->mass(igroup); else if (narg == 2) value = group->mass(igroup,region_function(args[1])); else error->all(FLERR,"Invalid group function in variable formula"); } else if (strcmp(word,"charge") == 0) { if (narg == 1) value = group->charge(igroup); else if (narg == 2) value = group->charge(igroup,region_function(args[1])); else error->all(FLERR,"Invalid group function in variable formula"); } else if (strcmp(word,"xcm") == 0) { atom->check_mass(FLERR); double xcm[3]; if (narg == 2) { double masstotal = group->mass(igroup); group->xcm(igroup,masstotal,xcm); } else if (narg == 3) { int iregion = region_function(args[2]); double masstotal = group->mass(igroup,iregion); group->xcm(igroup,masstotal,xcm,iregion); } else error->all(FLERR,"Invalid group function in variable formula"); if (strcmp(args[1],"x") == 0) value = xcm[0]; else if (strcmp(args[1],"y") == 0) value = xcm[1]; else if (strcmp(args[1],"z") == 0) value = xcm[2]; else error->all(FLERR,"Invalid group function in variable formula"); } else if (strcmp(word,"vcm") == 0) { atom->check_mass(FLERR); double vcm[3]; if (narg == 2) { double masstotal = group->mass(igroup); group->vcm(igroup,masstotal,vcm); } else if (narg == 3) { int iregion = region_function(args[2]); double masstotal = group->mass(igroup,iregion); group->vcm(igroup,masstotal,vcm,iregion); } else error->all(FLERR,"Invalid group function in variable formula"); if (strcmp(args[1],"x") == 0) value = vcm[0]; else if (strcmp(args[1],"y") == 0) value = vcm[1]; else if (strcmp(args[1],"z") == 0) value = vcm[2]; else error->all(FLERR,"Invalid group function in variable formula"); } else if (strcmp(word,"fcm") == 0) { double fcm[3]; if (narg == 2) group->fcm(igroup,fcm); else if (narg == 3) group->fcm(igroup,fcm,region_function(args[2])); else error->all(FLERR,"Invalid group function in variable formula"); if (strcmp(args[1],"x") == 0) value = fcm[0]; else if (strcmp(args[1],"y") == 0) value = fcm[1]; else if (strcmp(args[1],"z") == 0) value = fcm[2]; else error->all(FLERR,"Invalid group function in variable formula"); } else if (strcmp(word,"bound") == 0) { double minmax[6]; if (narg == 2) group->bounds(igroup,minmax); else if (narg == 3) group->bounds(igroup,minmax,region_function(args[2])); else error->all(FLERR,"Invalid group function in variable formula"); if (strcmp(args[1],"xmin") == 0) value = minmax[0]; else if (strcmp(args[1],"xmax") == 0) value = minmax[1]; else if (strcmp(args[1],"ymin") == 0) value = minmax[2]; else if (strcmp(args[1],"ymax") == 0) value = minmax[3]; else if (strcmp(args[1],"zmin") == 0) value = minmax[4]; else if (strcmp(args[1],"zmax") == 0) value = minmax[5]; else error->all(FLERR,"Invalid group function in variable formula"); } else if (strcmp(word,"gyration") == 0) { atom->check_mass(FLERR); double xcm[3]; if (narg == 1) { double masstotal = group->mass(igroup); group->xcm(igroup,masstotal,xcm); value = group->gyration(igroup,masstotal,xcm); } else if (narg == 2) { int iregion = region_function(args[1]); double masstotal = group->mass(igroup,iregion); group->xcm(igroup,masstotal,xcm,iregion); value = group->gyration(igroup,masstotal,xcm,iregion); } else error->all(FLERR,"Invalid group function in variable formula"); } else if (strcmp(word,"ke") == 0) { if (narg == 1) value = group->ke(igroup); else if (narg == 2) value = group->ke(igroup,region_function(args[1])); else error->all(FLERR,"Invalid group function in variable formula"); } else if (strcmp(word,"angmom") == 0) { atom->check_mass(FLERR); double xcm[3],lmom[3]; if (narg == 2) { double masstotal = group->mass(igroup); group->xcm(igroup,masstotal,xcm); group->angmom(igroup,xcm,lmom); } else if (narg == 3) { int iregion = region_function(args[2]); double masstotal = group->mass(igroup,iregion); group->xcm(igroup,masstotal,xcm,iregion); group->angmom(igroup,xcm,lmom,iregion); } else error->all(FLERR,"Invalid group function in variable formula"); if (strcmp(args[1],"x") == 0) value = lmom[0]; else if (strcmp(args[1],"y") == 0) value = lmom[1]; else if (strcmp(args[1],"z") == 0) value = lmom[2]; else error->all(FLERR,"Invalid group function in variable formula"); } else if (strcmp(word,"torque") == 0) { atom->check_mass(FLERR); double xcm[3],tq[3]; if (narg == 2) { double masstotal = group->mass(igroup); group->xcm(igroup,masstotal,xcm); group->torque(igroup,xcm,tq); } else if (narg == 3) { int iregion = region_function(args[2]); double masstotal = group->mass(igroup,iregion); group->xcm(igroup,masstotal,xcm,iregion); group->torque(igroup,xcm,tq,iregion); } else error->all(FLERR,"Invalid group function in variable formula"); if (strcmp(args[1],"x") == 0) value = tq[0]; else if (strcmp(args[1],"y") == 0) value = tq[1]; else if (strcmp(args[1],"z") == 0) value = tq[2]; else error->all(FLERR,"Invalid group function in variable formula"); } else if (strcmp(word,"inertia") == 0) { atom->check_mass(FLERR); double xcm[3],inertia[3][3]; if (narg == 2) { double masstotal = group->mass(igroup); group->xcm(igroup,masstotal,xcm); group->inertia(igroup,xcm,inertia); } else if (narg == 3) { int iregion = region_function(args[2]); double masstotal = group->mass(igroup,iregion); group->xcm(igroup,masstotal,xcm,iregion); group->inertia(igroup,xcm,inertia,iregion); } else error->all(FLERR,"Invalid group function in variable formula"); if (strcmp(args[1],"xx") == 0) value = inertia[0][0]; else if (strcmp(args[1],"yy") == 0) value = inertia[1][1]; else if (strcmp(args[1],"zz") == 0) value = inertia[2][2]; else if (strcmp(args[1],"xy") == 0) value = inertia[0][1]; else if (strcmp(args[1],"yz") == 0) value = inertia[1][2]; else if (strcmp(args[1],"xz") == 0) value = inertia[0][2]; else error->all(FLERR,"Invalid group function in variable formula"); } else if (strcmp(word,"omega") == 0) { atom->check_mass(FLERR); double xcm[3],angmom[3],inertia[3][3],omega[3]; if (narg == 2) { double masstotal = group->mass(igroup); group->xcm(igroup,masstotal,xcm); group->angmom(igroup,xcm,angmom); group->inertia(igroup,xcm,inertia); group->omega(angmom,inertia,omega); } else if (narg == 3) { int iregion = region_function(args[2]); double masstotal = group->mass(igroup,iregion); group->xcm(igroup,masstotal,xcm,iregion); group->angmom(igroup,xcm,angmom,iregion); group->inertia(igroup,xcm,inertia,iregion); group->omega(angmom,inertia,omega); } else error->all(FLERR,"Invalid group function in variable formula"); if (strcmp(args[1],"x") == 0) value = omega[0]; else if (strcmp(args[1],"y") == 0) value = omega[1]; else if (strcmp(args[1],"z") == 0) value = omega[2]; else error->all(FLERR,"Invalid group function in variable formula"); } // delete stored args for (int i = 0; i < narg; i++) delete [] args[i]; // save value in tree or on argstack if (tree) { Tree *newtree = new Tree(); newtree->type = VALUE; newtree->value = value; newtree->first = newtree->second = NULL; newtree->nextra = 0; treestack[ntreestack++] = newtree; } else argstack[nargstack++] = value; return 1; } /* ---------------------------------------------------------------------- */ int Variable::region_function(char *id) { int iregion = domain->find_region(id); if (iregion == -1) error->all(FLERR,"Region ID in variable formula does not exist"); // init region in case sub-regions have been deleted domain->regions[iregion]->init(); return iregion; } /* ---------------------------------------------------------------------- process a special function in formula push result onto tree or arg stack word = special function contents = str between parentheses with one,two,three args return 0 if not a match, 1 if successfully processed customize by adding a special function: sum(x),min(x),max(x),ave(x),trap(x),slope(x), gmask(x),rmask(x),grmask(x,y),next(x) ------------------------------------------------------------------------- */ int Variable::special_function(char *word, char *contents, Tree **tree, Tree **treestack, int &ntreestack, double *argstack, int &nargstack) { double value,xvalue,sx,sy,sxx,sxy; // word not a match to any special function if (strcmp(word,"sum") && strcmp(word,"min") && strcmp(word,"max") && strcmp(word,"ave") && strcmp(word,"trap") && strcmp(word,"slope") && strcmp(word,"gmask") && strcmp(word,"rmask") && strcmp(word,"grmask") && strcmp(word,"next") && strcmp(word,"is_active") && strcmp(word,"is_defined") && strcmp(word,"is_available")) return 0; // parse contents for comma-separated args // narg = number of args, args = strings between commas char *args[MAXFUNCARG]; int narg = parse_args(contents,args); // special functions that operate on global vectors if (strcmp(word,"sum") == 0 || strcmp(word,"min") == 0 || strcmp(word,"max") == 0 || strcmp(word,"ave") == 0 || strcmp(word,"trap") == 0 || strcmp(word,"slope") == 0) { int method; if (strcmp(word,"sum") == 0) method = SUM; else if (strcmp(word,"min") == 0) method = XMIN; else if (strcmp(word,"max") == 0) method = XMAX; else if (strcmp(word,"ave") == 0) method = AVE; else if (strcmp(word,"trap") == 0) method = TRAP; else if (strcmp(word,"slope") == 0) method = SLOPE; if (narg != 1) error->all(FLERR,"Invalid special function in variable formula"); Compute *compute = NULL; Fix *fix = NULL; int ivar = -1; int index,nvec,nstride; char *ptr1,*ptr2; // argument is compute if (strstr(args[0],"c_") == args[0]) { ptr1 = strchr(args[0],'['); if (ptr1) { ptr2 = ptr1; index = (int) int_between_brackets(ptr2,0); *ptr1 = '\0'; } else index = 0; int icompute = modify->find_compute(&args[0][2]); if (icompute < 0) error->all(FLERR,"Invalid compute ID in variable formula"); compute = modify->compute[icompute]; if (index == 0 && compute->vector_flag) { if (update->whichflag == 0) { if (compute->invoked_vector != update->ntimestep) error->all(FLERR, "Compute used in variable between runs is not current"); } else if (!(compute->invoked_flag & INVOKED_VECTOR)) { compute->compute_vector(); compute->invoked_flag |= INVOKED_VECTOR; } nvec = compute->size_vector; nstride = 1; } else if (index && compute->array_flag) { if (index > compute->size_array_cols) error->all(FLERR,"Variable formula compute array " "is accessed out-of-range"); if (update->whichflag == 0) { if (compute->invoked_array != update->ntimestep) error->all(FLERR, "Compute used in variable between runs is not current"); } else if (!(compute->invoked_flag & INVOKED_ARRAY)) { compute->compute_array(); compute->invoked_flag |= INVOKED_ARRAY; } nvec = compute->size_array_rows; nstride = compute->size_array_cols; } else error->all(FLERR,"Mismatched compute in variable formula"); // argument is fix } else if (strstr(args[0],"f_") == args[0]) { ptr1 = strchr(args[0],'['); if (ptr1) { ptr2 = ptr1; index = (int) int_between_brackets(ptr2,0); *ptr1 = '\0'; } else index = 0; int ifix = modify->find_fix(&args[0][2]); if (ifix < 0) error->all(FLERR,"Invalid fix ID in variable formula"); fix = modify->fix[ifix]; if (index == 0 && fix->vector_flag) { if (update->whichflag > 0 && update->ntimestep % fix->global_freq) error->all(FLERR,"Fix in variable not computed at compatible time"); nvec = fix->size_vector; nstride = 1; } else if (index && fix->array_flag) { if (index > fix->size_array_cols) error->all(FLERR, "Variable formula fix array is accessed out-of-range"); if (update->whichflag > 0 && update->ntimestep % fix->global_freq) error->all(FLERR,"Fix in variable not computed at compatible time"); nvec = fix->size_array_rows; nstride = fix->size_array_cols; } else error->all(FLERR,"Mismatched fix in variable formula"); // argument is vector-style variable } else if (strstr(args[0],"v_") == args[0]) { ptr1 = strchr(args[0],'['); if (ptr1) { ptr2 = ptr1; index = (int) int_between_brackets(ptr2,0); *ptr1 = '\0'; } else index = 0; if (index) error->all(FLERR,"Invalid special function in variable formula"); ivar = find(&args[0][2]); if (ivar < 0) error->all(FLERR,"Invalid special function in variable formula"); if (style[ivar] != VECTOR) error->all(FLERR, "Mis-matched special function variable in variable formula"); if (eval_in_progress[ivar]) error->all(FLERR,"Variable has circular dependency"); double *vec; nvec = compute_vector(ivar,&vec); nstride = 1; } else error->all(FLERR,"Invalid special function in variable formula"); value = 0.0; if (method == SLOPE) sx = sy = sxx = sxy = 0.0; if (method == XMIN) value = BIG; if (method == XMAX) value = -BIG; if (compute) { double *vec; if (index) { if (compute->array) vec = &compute->array[0][index-1]; else vec = NULL; } else vec = compute->vector; int j = 0; for (int i = 0; i < nvec; i++) { if (method == SUM) value += vec[j]; else if (method == XMIN) value = MIN(value,vec[j]); else if (method == XMAX) value = MAX(value,vec[j]); else if (method == AVE) value += vec[j]; else if (method == TRAP) value += vec[j]; else if (method == SLOPE) { if (nvec > 1) xvalue = (double) i / (nvec-1); else xvalue = 0.0; sx += xvalue; sy += vec[j]; sxx += xvalue*xvalue; sxy += xvalue*vec[j]; } j += nstride; } if (method == TRAP) value -= 0.5*vec[0] + 0.5*vec[nvec-1]; } if (fix) { double one; for (int i = 0; i < nvec; i++) { if (index) one = fix->compute_array(i,index-1); else one = fix->compute_vector(i); if (method == SUM) value += one; else if (method == XMIN) value = MIN(value,one); else if (method == XMAX) value = MAX(value,one); else if (method == AVE) value += one; else if (method == TRAP) value += one; else if (method == SLOPE) { if (nvec > 1) xvalue = (double) i / (nvec-1); else xvalue = 0.0; sx += xvalue; sy += one; sxx += xvalue*xvalue; sxy += xvalue*one; } } if (method == TRAP) { if (index) value -= 0.5*fix->compute_array(0,index-1) + 0.5*fix->compute_array(nvec-1,index-1); else value -= 0.5*fix->compute_vector(0) + 0.5*fix->compute_vector(nvec-1); } } if (ivar >= 0) { double one; double *vec = vecs[ivar].values; for (int i = 0; i < nvec; i++) { one = vec[i]; if (method == SUM) value += one; else if (method == XMIN) value = MIN(value,one); else if (method == XMAX) value = MAX(value,one); else if (method == AVE) value += one; else if (method == TRAP) value += one; else if (method == SLOPE) { if (nvec > 1) xvalue = (double) i / (nvec-1); else xvalue = 0.0; sx += xvalue; sy += one; sxx += xvalue*xvalue; sxy += xvalue*one; } } if (method == TRAP) value -= 0.5*vec[0] + 0.5*vec[nvec-1]; } if (method == AVE) value /= nvec; if (method == SLOPE) { double numerator = sxy - sx*sy; double denominator = sxx - sx*sx; if (denominator != 0.0) value = numerator/denominator / nvec; else value = BIG; } // save value in tree or on argstack if (tree) { Tree *newtree = new Tree(); newtree->type = VALUE; newtree->value = value; newtree->first = newtree->second = NULL; newtree->nextra = 0; treestack[ntreestack++] = newtree; } else argstack[nargstack++] = value; // mask special functions } else if (strcmp(word,"gmask") == 0) { if (tree == NULL) error->all(FLERR,"Gmask function in equal-style variable formula"); if (narg != 1) error->all(FLERR,"Invalid special function in variable formula"); int igroup = group->find(args[0]); if (igroup == -1) error->all(FLERR,"Group ID in variable formula does not exist"); Tree *newtree = new Tree(); newtree->type = GMASK; newtree->ivalue1 = group->bitmask[igroup]; newtree->first = newtree->second = NULL; newtree->nextra = 0; treestack[ntreestack++] = newtree; } else if (strcmp(word,"rmask") == 0) { if (tree == NULL) error->all(FLERR,"Rmask function in equal-style variable formula"); if (narg != 1) error->all(FLERR,"Invalid special function in variable formula"); int iregion = region_function(args[0]); domain->regions[iregion]->prematch(); Tree *newtree = new Tree(); newtree->type = RMASK; newtree->ivalue1 = iregion; newtree->first = newtree->second = NULL; newtree->nextra = 0; treestack[ntreestack++] = newtree; } else if (strcmp(word,"grmask") == 0) { if (tree == NULL) error->all(FLERR,"Grmask function in equal-style variable formula"); if (narg != 2) error->all(FLERR,"Invalid special function in variable formula"); int igroup = group->find(args[0]); if (igroup == -1) error->all(FLERR,"Group ID in variable formula does not exist"); int iregion = region_function(args[1]); domain->regions[iregion]->prematch(); Tree *newtree = new Tree(); newtree->type = GRMASK; newtree->ivalue1 = group->bitmask[igroup]; newtree->ivalue2 = iregion; newtree->first = newtree->second = NULL; newtree->nextra = 0; treestack[ntreestack++] = newtree; // special function for file-style or atomfile-style variables } else if (strcmp(word,"next") == 0) { if (narg != 1) error->all(FLERR,"Invalid special function in variable formula"); int ivar = find(args[0]); if (ivar < 0) error->all(FLERR,"Variable ID in variable formula does not exist"); // SCALARFILE has single current value, read next one // save value in tree or on argstack if (style[ivar] == SCALARFILE) { double value = atof(data[ivar][0]); int done = reader[ivar]->read_scalar(data[ivar][0]); if (done) remove(ivar); if (tree) { Tree *newtree = new Tree(); newtree->type = VALUE; newtree->value = value; newtree->first = newtree->second = NULL; newtree->nextra = 0; treestack[ntreestack++] = newtree; } else argstack[nargstack++] = value; // ATOMFILE has per-atom values, save values in tree // copy current per-atom values into result so can read next ones // set selfalloc = 1 so result will be deleted by free_tree() after eval } else if (style[ivar] == ATOMFILE) { if (tree == NULL) error->all(FLERR,"Atomfile variable in equal-style variable formula"); double *result; memory->create(result,atom->nlocal,"variable:result"); memcpy(result,reader[ivar]->fixstore->vstore,atom->nlocal*sizeof(double)); int done = reader[ivar]->read_peratom(); if (done) remove(ivar); Tree *newtree = new Tree(); newtree->type = ATOMARRAY; newtree->array = result; newtree->nstride = 1; newtree->selfalloc = 1; newtree->first = newtree->second = NULL; newtree->nextra = 0; treestack[ntreestack++] = newtree; } else error->all(FLERR,"Invalid variable style in special function next"); } else if (strcmp(word,"is_active") == 0) { if (narg != 2) error->all(FLERR,"Invalid is_active() function in variable formula"); Info info(lmp); value = (info.is_active(args[0],args[1])) ? 1.0 : 0.0; // save value in tree or on argstack if (tree) { Tree *newtree = new Tree(); newtree->type = VALUE; newtree->value = value; newtree->first = newtree->second = NULL; newtree->nextra = 0; treestack[ntreestack++] = newtree; } else argstack[nargstack++] = value; } else if (strcmp(word,"is_available") == 0) { if (narg != 2) error->all(FLERR,"Invalid is_available() function in variable formula"); Info info(lmp); value = (info.is_available(args[0],args[1])) ? 1.0 : 0.0; // save value in tree or on argstack if (tree) { Tree *newtree = new Tree(); newtree->type = VALUE; newtree->value = value; newtree->first = newtree->second = NULL; newtree->nextra = 0; treestack[ntreestack++] = newtree; } else argstack[nargstack++] = value; } else if (strcmp(word,"is_defined") == 0) { if (narg != 2) error->all(FLERR,"Invalid is_defined() function in variable formula"); Info info(lmp); value = (info.is_defined(args[0],args[1])) ? 1.0 : 0.0; // save value in tree or on argstack if (tree) { Tree *newtree = new Tree(); newtree->type = VALUE; newtree->value = value; newtree->first = newtree->second = NULL; newtree->nextra = 0; treestack[ntreestack++] = newtree; } else argstack[nargstack++] = value; } // delete stored args for (int i = 0; i < narg; i++) delete [] args[i]; return 1; } /* ---------------------------------------------------------------------- extract a global value from a per-atom quantity in a formula flag = 0 -> word is an atom vector flag = 1 -> vector is a per-atom compute or fix quantity with nstride id = global ID of atom, converted to local index push result onto tree or arg stack customize by adding an atom vector: id,mass,type,mol,x,y,z,vx,vy,vz,fx,fy,fz,q ------------------------------------------------------------------------- */ void Variable::peratom2global(int flag, char *word, double *vector, int nstride, tagint id, Tree **tree, Tree **treestack, int &ntreestack, double *argstack, int &nargstack) { // error check for ID larger than any atom // int_between_brackets() already checked for ID <= 0 if (atom->map_style == 0) error->all(FLERR, "Indexed per-atom vector in variable formula without atom map"); if (id > atom->map_tag_max) error->all(FLERR,"Variable atom ID is too large"); // if ID does not exist, index will be -1 for all procs, // and mine will be set to 0.0 int index = atom->map(id); double mine; if (index >= 0 && index < atom->nlocal) { if (flag == 0) { if (strcmp(word,"id") == 0) mine = atom->tag[index]; else if (strcmp(word,"mass") == 0) { if (atom->rmass) mine = atom->rmass[index]; else mine = atom->mass[atom->type[index]]; } else if (strcmp(word,"type") == 0) mine = atom->type[index]; else if (strcmp(word,"mol") == 0) { if (!atom->molecule_flag) error->one(FLERR,"Variable uses atom property that isn't allocated"); mine = atom->molecule[index]; } else if (strcmp(word,"x") == 0) mine = atom->x[index][0]; else if (strcmp(word,"y") == 0) mine = atom->x[index][1]; else if (strcmp(word,"z") == 0) mine = atom->x[index][2]; else if (strcmp(word,"vx") == 0) mine = atom->v[index][0]; else if (strcmp(word,"vy") == 0) mine = atom->v[index][1]; else if (strcmp(word,"vz") == 0) mine = atom->v[index][2]; else if (strcmp(word,"fx") == 0) mine = atom->f[index][0]; else if (strcmp(word,"fy") == 0) mine = atom->f[index][1]; else if (strcmp(word,"fz") == 0) mine = atom->f[index][2]; else if (strcmp(word,"q") == 0) { if (!atom->q_flag) error->one(FLERR,"Variable uses atom property that isn't allocated"); mine = atom->q[index]; } else error->one(FLERR,"Invalid atom vector in variable formula"); } else mine = vector[index*nstride]; } else mine = 0.0; double value; MPI_Allreduce(&mine,&value,1,MPI_DOUBLE,MPI_SUM,world); if (tree) { Tree *newtree = new Tree(); newtree->type = VALUE; newtree->value = value; newtree->first = newtree->second = NULL; newtree->nextra = 0; treestack[ntreestack++] = newtree; } else argstack[nargstack++] = value; } /* ---------------------------------------------------------------------- check if word matches an atom vector return 1 if yes, else 0 customize by adding an atom vector: id,mass,type,mol,x,y,z,vx,vy,vz,fx,fy,fz,q ------------------------------------------------------------------------- */ int Variable::is_atom_vector(char *word) { if (strcmp(word,"id") == 0) return 1; if (strcmp(word,"mass") == 0) return 1; if (strcmp(word,"type") == 0) return 1; if (strcmp(word,"mol") == 0) return 1; if (strcmp(word,"x") == 0) return 1; if (strcmp(word,"y") == 0) return 1; if (strcmp(word,"z") == 0) return 1; if (strcmp(word,"vx") == 0) return 1; if (strcmp(word,"vy") == 0) return 1; if (strcmp(word,"vz") == 0) return 1; if (strcmp(word,"fx") == 0) return 1; if (strcmp(word,"fy") == 0) return 1; if (strcmp(word,"fz") == 0) return 1; if (strcmp(word,"q") == 0) return 1; return 0; } /* ---------------------------------------------------------------------- process an atom vector in formula push result onto tree word = atom vector customize by adding an atom vector: id,mass,type,mol,x,y,z,vx,vy,vz,fx,fy,fz,q ------------------------------------------------------------------------- */ void Variable::atom_vector(char *word, Tree **tree, Tree **treestack, int &ntreestack) { if (tree == NULL) error->all(FLERR,"Atom vector in equal-style variable formula"); Tree *newtree = new Tree(); newtree->type = ATOMARRAY; newtree->nstride = 3; newtree->selfalloc = 0; newtree->first = newtree->second = NULL; newtree->nextra = 0; treestack[ntreestack++] = newtree; if (strcmp(word,"id") == 0) { if (sizeof(tagint) == sizeof(smallint)) { newtree->type = INTARRAY; newtree->iarray = (int *) atom->tag; } else { newtree->type = BIGINTARRAY; newtree->barray = (bigint *) atom->tag; } newtree->nstride = 1; } else if (strcmp(word,"mass") == 0) { if (atom->rmass) { newtree->nstride = 1; newtree->array = atom->rmass; } else { newtree->type = TYPEARRAY; newtree->array = atom->mass; } } else if (strcmp(word,"type") == 0) { newtree->type = INTARRAY; newtree->nstride = 1; newtree->iarray = atom->type; } else if (strcmp(word,"mol") == 0) { if (!atom->molecule_flag) error->one(FLERR,"Variable uses atom property that isn't allocated"); if (sizeof(tagint) == sizeof(smallint)) { newtree->type = INTARRAY; newtree->iarray = (int *) atom->molecule; } else { newtree->type = BIGINTARRAY; newtree->barray = (bigint *) atom->molecule; } newtree->nstride = 1; } else if (strcmp(word,"x") == 0) newtree->array = &atom->x[0][0]; else if (strcmp(word,"y") == 0) newtree->array = &atom->x[0][1]; else if (strcmp(word,"z") == 0) newtree->array = &atom->x[0][2]; else if (strcmp(word,"vx") == 0) newtree->array = &atom->v[0][0]; else if (strcmp(word,"vy") == 0) newtree->array = &atom->v[0][1]; else if (strcmp(word,"vz") == 0) newtree->array = &atom->v[0][2]; else if (strcmp(word,"fx") == 0) newtree->array = &atom->f[0][0]; else if (strcmp(word,"fy") == 0) newtree->array = &atom->f[0][1]; else if (strcmp(word,"fz") == 0) newtree->array = &atom->f[0][2]; else if (strcmp(word,"q") == 0) { newtree->nstride = 1; newtree->array = atom->q; } } /* ---------------------------------------------------------------------- check if word matches a constant return 1 if yes, else 0 customize by adding a constant: PI, version ------------------------------------------------------------------------- */ int Variable::is_constant(char *word) { if (strcmp(word,"PI") == 0) return 1; if (strcmp(word,"version") == 0) return 1; if (strcmp(word,"yes") == 0) return 1; if (strcmp(word,"no") == 0) return 1; if (strcmp(word,"on") == 0) return 1; if (strcmp(word,"off") == 0) return 1; if (strcmp(word,"true") == 0) return 1; if (strcmp(word,"false") == 0) return 1; return 0; } /* ---------------------------------------------------------------------- process a constant in formula customize by adding a constant: PI, version ------------------------------------------------------------------------- */ double Variable::constant(char *word) { if (strcmp(word,"PI") == 0) return MY_PI; if (strcmp(word,"version") == 0) return atof(universe->num_ver); if (strcmp(word,"yes") == 0) return 1.0; if (strcmp(word,"no") == 0) return 0.0; if (strcmp(word,"on") == 0) return 1.0; if (strcmp(word,"off") == 0) return 0.0; if (strcmp(word,"true") == 0) return 1.0; if (strcmp(word,"false") == 0) return 0.0; return 0.0; } /* ---------------------------------------------------------------------- parse string for comma-separated args store copy of each arg in args array max allowed # of args = MAXFUNCARG ------------------------------------------------------------------------- */ int Variable::parse_args(char *str, char **args) { int n; char *ptrnext; int narg = 0; char *ptr = str; while (ptr && narg < MAXFUNCARG) { ptrnext = find_next_comma(ptr); if (ptrnext) *ptrnext = '\0'; n = strlen(ptr) + 1; args[narg] = new char[n]; strcpy(args[narg],ptr); narg++; ptr = ptrnext; if (ptr) ptr++; } if (ptr) error->all(FLERR,"Too many args in variable function"); return narg; } /* ---------------------------------------------------------------------- find next comma in str skip commas inside one or more nested parenthesis only return ptr to comma at level 0, else NULL if not found ------------------------------------------------------------------------- */ char *Variable::find_next_comma(char *str) { int level = 0; for (char *p = str; *p; ++p) { if ('(' == *p) level++; else if (')' == *p) level--; else if (',' == *p && !level) return p; } return NULL; } /* ---------------------------------------------------------------------- debug routine for printing formula tree recursively ------------------------------------------------------------------------- */ void Variable::print_tree(Tree *tree, int level) { printf("TREE %d: %d %g\n",level,tree->type,tree->value); if (tree->first) print_tree(tree->first,level+1); if (tree->second) print_tree(tree->second,level+1); if (tree->nextra) for (int i = 0; i < tree->nextra; i++) print_tree(tree->extra[i],level+1); return; } /* ---------------------------------------------------------------------- recursive evaluation of string str called from "if" command in input script str is a boolean expression containing one or more items: number = 0.0, -5.45, 2.8e-4, ... math operation = (),x==y,x!=y,xy,x>=y,x&&y,x||y ------------------------------------------------------------------------- */ double Variable::evaluate_boolean(char *str) { int op,opprevious,flag1,flag2; double value1,value2; char onechar; char *str1,*str2; struct Arg { int flag; // 0 for numeric value, 1 for string double value; // stored numeric value char *str; // stored string }; Arg argstack[MAXLEVEL]; int opstack[MAXLEVEL]; int nargstack = 0; int nopstack = 0; int i = 0; int expect = ARG; while (1) { onechar = str[i]; // whitespace: just skip if (isspace(onechar)) i++; // ---------------- // parentheses: recursively evaluate contents of parens // ---------------- else if (onechar == '(') { if (expect == OP) error->all(FLERR,"Invalid Boolean syntax in if command"); expect = OP; char *contents; i = find_matching_paren(str,i,contents); i++; // evaluate contents and push on stack argstack[nargstack].value = evaluate_boolean(contents); argstack[nargstack].flag = 0; nargstack++; delete [] contents; // ---------------- // number: push value onto stack // ---------------- } else if (isdigit(onechar) || onechar == '.' || onechar == '-') { if (expect == OP) error->all(FLERR,"Invalid Boolean syntax in if command"); expect = OP; // set I to end of number, including scientific notation int istart = i++; while (isdigit(str[i]) || str[i] == '.') i++; if (str[i] == 'e' || str[i] == 'E') { i++; if (str[i] == '+' || str[i] == '-') i++; while (isdigit(str[i])) i++; } onechar = str[i]; str[i] = '\0'; argstack[nargstack].value = atof(&str[istart]); str[i] = onechar; argstack[nargstack++].flag = 0; // ---------------- // string: push string onto stack // ---------------- } else if (isalpha(onechar)) { if (expect == OP) error->all(FLERR,"Invalid Boolean syntax in if command"); expect = OP; // set I to end of string int istart = i++; while (isalnum(str[i]) || str[i] == '_') i++; int n = i - istart + 1; argstack[nargstack].str = new char[n]; onechar = str[i]; str[i] = '\0'; strcpy(argstack[nargstack].str,&str[istart]); str[i] = onechar; argstack[nargstack++].flag = 1; // ---------------- // Boolean operator, including end-of-string // ---------------- } else if (strchr("<>=!&|\0",onechar)) { if (onechar == '=') { if (str[i+1] != '=') error->all(FLERR,"Invalid Boolean syntax in if command"); op = EQ; i++; } else if (onechar == '!') { if (str[i+1] == '=') { op = NE; i++; } else op = NOT; } else if (onechar == '<') { if (str[i+1] != '=') op = LT; else { op = LE; i++; } } else if (onechar == '>') { if (str[i+1] != '=') op = GT; else { op = GE; i++; } } else if (onechar == '&') { if (str[i+1] != '&') error->all(FLERR,"Invalid Boolean syntax in if command"); op = AND; i++; } else if (onechar == '|') { if (str[i+1] == '|') op = OR; else if (str[i+1] == '^') op = XOR; else error->all(FLERR,"Invalid Boolean syntax in if command"); i++; } else op = DONE; i++; if (op == NOT && expect == ARG) { opstack[nopstack++] = op; continue; } if (expect == ARG) error->all(FLERR,"Invalid Boolean syntax in if command"); expect = ARG; // evaluate stack as deep as possible while respecting precedence // before pushing current op onto stack while (nopstack && precedence[opstack[nopstack-1]] >= precedence[op]) { opprevious = opstack[--nopstack]; nargstack--; flag2 = argstack[nargstack].flag; value2 = argstack[nargstack].value; str2 = argstack[nargstack].str; if (opprevious != NOT) { nargstack--; flag1 = argstack[nargstack].flag; value1 = argstack[nargstack].value; str1 = argstack[nargstack].str; } if (opprevious == NOT) { if (flag2) error->all(FLERR,"Invalid Boolean syntax in if command"); if (value2 == 0.0) argstack[nargstack].value = 1.0; else argstack[nargstack].value = 0.0; } else if (opprevious == EQ) { if (flag1 != flag2) error->all(FLERR,"Invalid Boolean syntax in if command"); if (flag2 == 0) { if (value1 == value2) argstack[nargstack].value = 1.0; else argstack[nargstack].value = 0.0; } else { if (strcmp(str1,str2) == 0) argstack[nargstack].value = 1.0; else argstack[nargstack].value = 0.0; delete [] str1; delete [] str2; } } else if (opprevious == NE) { if (flag1 != flag2) error->all(FLERR,"Invalid Boolean syntax in if command"); if (flag2 == 0) { if (value1 != value2) argstack[nargstack].value = 1.0; else argstack[nargstack].value = 0.0; } else { if (strcmp(str1,str2) != 0) argstack[nargstack].value = 1.0; else argstack[nargstack].value = 0.0; delete [] str1; delete [] str2; } } else if (opprevious == LT) { if (flag2) error->all(FLERR,"Invalid Boolean syntax in if command"); if (value1 < value2) argstack[nargstack].value = 1.0; else argstack[nargstack].value = 0.0; } else if (opprevious == LE) { if (flag2) error->all(FLERR,"Invalid Boolean syntax in if command"); if (value1 <= value2) argstack[nargstack].value = 1.0; else argstack[nargstack].value = 0.0; } else if (opprevious == GT) { if (flag2) error->all(FLERR,"Invalid Boolean syntax in if command"); if (value1 > value2) argstack[nargstack].value = 1.0; else argstack[nargstack].value = 0.0; } else if (opprevious == GE) { if (flag2) error->all(FLERR,"Invalid Boolean syntax in if command"); if (value1 >= value2) argstack[nargstack].value = 1.0; else argstack[nargstack].value = 0.0; } else if (opprevious == AND) { if (flag2) error->all(FLERR,"Invalid Boolean syntax in if command"); if (value1 != 0.0 && value2 != 0.0) argstack[nargstack].value = 1.0; else argstack[nargstack].value = 0.0; } else if (opprevious == OR) { if (flag2) error->all(FLERR,"Invalid Boolean syntax in if command"); if (value1 != 0.0 || value2 != 0.0) argstack[nargstack].value = 1.0; else argstack[nargstack].value = 0.0; } else if (opprevious == XOR) { if (flag2) error->all(FLERR,"Invalid Boolean syntax in if command"); if ((value1 == 0.0 && value2 != 0.0) || (value1 != 0.0 && value2 == 0.0)) argstack[nargstack].value = 1.0; else argstack[nargstack].value = 0.0; } argstack[nargstack++].flag = 0; } // if end-of-string, break out of entire formula evaluation loop if (op == DONE) break; // push current operation onto stack opstack[nopstack++] = op; } else error->all(FLERR,"Invalid Boolean syntax in if command"); } if (nopstack) error->all(FLERR,"Invalid Boolean syntax in if command"); if (nargstack != 1) error->all(FLERR,"Invalid Boolean syntax in if command"); return argstack[0].value; } /* ---------------------------------------------------------------------- class to read variable values from a file for flag = SCALARFILE, reads one value per line for flag = ATOMFILE, reads set of one value per atom ------------------------------------------------------------------------- */ VarReader::VarReader(LAMMPS *lmp, char *name, char *file, int flag) : Pointers(lmp) { me = comm->me; style = flag; fp = NULL; if (me == 0) { fp = fopen(file,"r"); if (fp == NULL) { char str[128]; sprintf(str,"Cannot open file variable file %s",file); error->one(FLERR,str); } } // if atomfile-style variable, must store per-atom values read from file // allocate a new fix STORE, so they persist // id = variable-ID + VARIABLE_STORE, fix group = all fixstore = NULL; id_fix = NULL; buffer = NULL; if (style == ATOMFILE) { if (atom->map_style == 0) error->all(FLERR, "Cannot use atomfile-style variable unless atom map exists"); int n = strlen(name) + strlen("_VARIABLE_STORE") + 1; id_fix = new char[n]; strcpy(id_fix,name); strcat(id_fix,"_VARIABLE_STORE"); char **newarg = new char*[6]; newarg[0] = id_fix; newarg[1] = (char *) "all"; newarg[2] = (char *) "STORE"; newarg[3] = (char *) "peratom"; newarg[4] = (char *) "0"; newarg[5] = (char *) "1"; modify->add_fix(6,newarg); fixstore = (FixStore *) modify->fix[modify->nfix-1]; delete [] newarg; buffer = new char[CHUNK*MAXLINE]; } } /* ---------------------------------------------------------------------- */ VarReader::~VarReader() { if (me == 0) { fclose(fp); fp = NULL; } // check modify in case all fixes have already been deleted if (fixstore) { if (modify) modify->delete_fix(id_fix); delete [] id_fix; delete [] buffer; } } /* ---------------------------------------------------------------------- read for SCALARFILE style read next value from file into str for file-style variable strip comments, skip blank lines return 0 if successful, 1 if end-of-file ------------------------------------------------------------------------- */ int VarReader::read_scalar(char *str) { int n; char *ptr; // read one string from file if (me == 0) { while (1) { if (fgets(str,MAXLINE,fp) == NULL) n = 0; else n = strlen(str); if (n == 0) break; // end of file str[n-1] = '\0'; // strip newline if ((ptr = strchr(str,'#'))) *ptr = '\0'; // strip comment if (strtok(str," \t\n\r\f") == NULL) continue; // skip if blank n = strlen(str) + 1; break; } } MPI_Bcast(&n,1,MPI_INT,0,world); if (n == 0) return 1; MPI_Bcast(str,n,MPI_CHAR,0,world); return 0; } /* ---------------------------------------------------------------------- read snapshot of per-atom values from file into str for atomfile-style variable return 0 if successful, 1 if end-of-file ------------------------------------------------------------------------- */ int VarReader::read_peratom() { int i,m,n,nchunk,eof; tagint tag; char *ptr,*next; double value; // set all per-atom values to 0.0 // values that appear in file will overwrite this double *vstore = fixstore->vstore; int nlocal = atom->nlocal; for (i = 0; i < nlocal; i++) vstore[i] = 0.0; // read one string from file, convert to Nlines char str[MAXLINE]; if (me == 0) { while (1) { if (fgets(str,MAXLINE,fp) == NULL) n = 0; else n = strlen(str); if (n == 0) break; // end of file str[n-1] = '\0'; // strip newline if ((ptr = strchr(str,'#'))) *ptr = '\0'; // strip comment if (strtok(str," \t\n\r\f") == NULL) continue; // skip if blank n = strlen(str) + 1; break; } } MPI_Bcast(&n,1,MPI_INT,0,world); if (n == 0) return 1; MPI_Bcast(str,n,MPI_CHAR,0,world); bigint nlines = force->bnumeric(FLERR,str); tagint map_tag_max = atom->map_tag_max; bigint nread = 0; while (nread < nlines) { nchunk = MIN(nlines-nread,CHUNK); eof = comm->read_lines_from_file(fp,nchunk,MAXLINE,buffer); if (eof) return 1; char *buf = buffer; for (i = 0; i < nchunk; i++) { next = strchr(buf,'\n'); *next = '\0'; sscanf(buf,TAGINT_FORMAT " %lg",&tag,&value); if (tag <= 0 || tag > map_tag_max) error->one(FLERR,"Invalid atom ID in variable file"); if ((m = atom->map(tag)) >= 0) vstore[m] = value; buf = next + 1; } nread += nchunk; } return 0; }