diff --git a/doc/Section_start.html b/doc/Section_start.html index cc9106ebf..230c8644e 100644 --- a/doc/Section_start.html +++ b/doc/Section_start.html @@ -1,1409 +1,1417 @@
Previous Section - LAMMPS WWW Site - LAMMPS Documentation - LAMMPS Commands - Next Section

2. Getting Started

This section describes how to build and run LAMMPS, for both new and experienced users.

2.1 What's in the LAMMPS distribution
2.2 Making LAMMPS
2.3 Making LAMMPS with optional packages
2.4 Building LAMMPS via the Make.py script
2.5 Building LAMMPS as a library
2.6 Running LAMMPS
2.7 Command-line options
2.8 Screen output
2.9 Tips for users of previous versions


2.1 What's in the LAMMPS distribution

When you download LAMMPS you will need to unzip and untar the downloaded file with the following commands, after placing the file in an appropriate directory.

gunzip lammps*.tar.gz 
 tar xvf lammps*.tar 
 

This will create a LAMMPS directory containing two files and several sub-directories:

README text file
LICENSE the GNU General Public License (GPL)
bench benchmark problems
doc documentation
examples simple test problems
potentials embedded atom method (EAM) potential files
src source files
tools pre- and post-processing tools

If you download one of the Windows executables from the download page, then you just get a single file:

lmp_windows.exe 
 

Skip to the Running LAMMPS sections for info on how to launch these executables on a Windows box.

The Windows executables for serial or parallel only include certain packages and bug-fixes/upgrades listed on this page up to a certain date, as stated on the download page. If you want something with more packages or that is more current, you'll have to download the source tarball and build it yourself from source code using Microsoft Visual Studio, as described in the next section.


2.2 Making LAMMPS

This section has the following sub-sections:


Read this first:

Building LAMMPS can be non-trivial. You may need to edit a makefile, there are compiler options to consider, additional libraries can be used (MPI, FFT, JPEG, PNG), LAMMPS packages may be included or excluded, some of these packages use auxiliary libraries which need to be pre-built, etc.

Please read this section carefully. If you are not comfortable with makefiles, or building codes on a Unix platform, or running an MPI job on your machine, please find a local expert to help you. Many compiling, linking, and run problems that users have are often not LAMMPS issues - they are peculiar to the user's system, compilers, libraries, etc. Such questions are better answered by a local expert.

If you have a build problem that you are convinced is a LAMMPS issue (e.g. the compiler complains about a line of LAMMPS source code), then please post a question to the LAMMPS mail list.

If you succeed in building LAMMPS on a new kind of machine, for which there isn't a similar Makefile for in the src/MAKE directory, send it to the developers and we can include it in the LAMMPS distribution.


Steps to build a LAMMPS executable:

Step 0

The src directory contains the C++ source and header files for LAMMPS. It also contains a top-level Makefile and a MAKE sub-directory with low-level Makefile.* files for many machines. From within the src directory, type "make" or "gmake". You should see a list of available choices. If one of those is the machine and options you want, you can type a command like:

make linux
 or
 gmake mac 
 

Note that on a multi-processor or multi-core platform you can launch a parallel make, by using the "-j" switch with the make command, which will build LAMMPS more quickly.

If you get no errors and an executable like lmp_linux or lmp_mac is produced, you're done; it's your lucky day.

Note that by default only a few of LAMMPS optional packages are installed. To build LAMMPS with optional packages, see this section below.

Step 1

If Step 0 did not work, you will need to create a low-level Makefile for your machine, like Makefile.foo. You should make a copy of an existing src/MAKE/Makefile.* as a starting point. The only portions of the file you need to edit are the first line, the "compiler/linker settings" section, and the "LAMMPS-specific settings" section.

Step 2

Change the first line of src/MAKE/Makefile.foo to list the word "foo" after the "#", and whatever other options it will set. This is the line you will see if you just type "make".

Step 3

The "compiler/linker settings" section lists compiler and linker settings for your C++ compiler, including optimization flags. You can use g++, the open-source GNU compiler, which is available on all Unix systems. You can also use mpicc which will typically be available if MPI is installed on your system, though you should check which actual compiler it wraps. Vendor compilers often produce faster code. On boxes with Intel CPUs, we suggest using the commercial Intel icc compiler, which can be downloaded from Intel's compiler site.

If building a C++ code on your machine requires additional libraries, then you should list them as part of the LIB variable.

The DEPFLAGS setting is what triggers the C++ compiler to create a dependency list for a source file. This speeds re-compilation when source (*.cpp) or header (*.h) files are edited. Some compilers do not support dependency file creation, or may use a different switch than -D. GNU g++ works with -D. If your compiler can't create dependency files, then you'll need to create a Makefile.foo patterned after Makefile.storm, which uses different rules that do not involve dependency files. Note that when you build LAMMPS for the first time on a new platform, a long list of *.d files will be printed out rapidly. This is not an error; it is the Makefile doing its normal creation of dependencies.

Step 4

The "system-specific settings" section has several parts. Note that if you change any -D setting in this section, you should do a full re-compile, after typing "make clean" (which will describe different clean options).

The LMP_INC variable is used to include options that turn on ifdefs within the LAMMPS code. The options that are currently recogized are:

The read_data and dump commands will read/write gzipped files if you -compile with -DLAMMPS_GZIP. It requires that your Unix support the -"popen" command. +compile with -DLAMMPS_GZIP. It requires that your machine supports +the "popen" function in the standard runtime library and that a gzip +executable can be found by LAMMPS during a run.

-

If you use -DLAMMPS_JPEG, the dump image command will be -able to write out JPEG image files. For JPEG files, you must also link -LAMMPS with a JPEG library, as described below. If you use +

If you use -DLAMMPS_JPEG, the dump image command +will be able to write out JPEG image files. For JPEG files, you must +also link LAMMPS with a JPEG library, as described below. If you use -DLAMMPS_PNG, the dump image command will be able to write out PNG image files. For PNG files, you must also link LAMMPS with a PNG library, as described below. If neither of those two defines are -used, LAMMPS will only be able to write out text-based PPM image +used, LAMMPS will only be able to write out uncompressed PPM image files.

+

If you use -DLAMMPS_FFMPEG, the dump movie command +will be available to support on-the-fly generation of rendered movies +the need to store intermediate image files. It requires that your +machines supports the "popen" function in the standard runtime library +and that an FFmpeg executable can be found by LAMMPS during the run. +

Using -DLAMMPS_MEMALIGN= enables the use of the posix_memalign() call instead of malloc() when large chunks or memory are allocated by LAMMPS. This can help to make more efficient use of vector instructions of modern CPUS, since dynamically allocated memory has to be aligned on larger than default byte boundaries (e.g. 16 bytes instead of 8 bytes on x86 type platforms) for optimal performance.

If you use -DLAMMPS_XDR, the build will include XDR compatibility files for doing particle dumps in XTC format. This is only necessary if your platform does have its own XDR files available. See the Restrictions section of the dump command for details.

Use at most one of the -DLAMMPS_SMALLBIG, -DLAMMPS_BIGBIG, -D-DLAMMPS_SMALLSMALL settings. The default is -DLAMMPS_SMALLBIG. These settings refer to use of 4-byte (small) vs 8-byte (big) integers within LAMMPS, as specified in src/lmptype.h. The only reason to use the BIGBIG setting is to enable simulation of huge molecular systems with more than 2 billion atoms or to allow moving atoms to wrap back through a periodic box more than 512 times. The only reason to use the SMALLSMALL setting is if your machine does not support 64-bit integers. See the Additional build tips section below for more details.

The -DLAMMPS_LONGLONG_TO_LONG setting may be needed if your system or MPI version does not recognize "long long" data types. In this case a "long" data type is likely already 64-bits, in which case this setting will convert to that data type.

Using one of the -DPACK_ARRAY, -DPACK_POINTER, and -DPACK_MEMCPY options can make for faster parallel FFTs (in the PPPM solver) on some platforms. The -DPACK_ARRAY setting is the default. See the kspace_style command for info about PPPM. See Step 6 below for info about building LAMMPS with an FFT library.

Step 5

The 3 MPI variables are used to specify an MPI library to build LAMMPS with.

If you want LAMMPS to run in parallel, you must have an MPI library installed on your platform. If you use an MPI-wrapped compiler, such as "mpicc" to build LAMMPS, you should be able to leave these 3 variables blank; the MPI wrapper knows where to find the needed files. If not, and MPI is installed on your system in the usual place (under /usr/local), you also may not need to specify these 3 variables. On some large parallel machines which use "modules" for their compile/link environements, you may simply need to include the correct module in your build environment. Or the parallel machine may have a vendor-provided MPI which the compiler has no trouble finding.

Failing this, with these 3 variables you can specify where the mpi.h file (MPI_INC) and the MPI library file (MPI_PATH) are found and the name of the library file (MPI_LIB).

If you are installing MPI yourself, we recommend Argonne's MPICH2 or OpenMPI. MPICH can be downloaded from the Argonne MPI site. OpenMPI can be downloaded from the OpenMPI site. Other MPI packages should also work. If you are running on a big parallel platform, your system people or the vendor should have already installed a version of MPI, which is likely to be faster than a self-installed MPICH or OpenMPI, so find out how to build and link with it. If you use MPICH or OpenMPI, you will have to configure and build it for your platform. The MPI configure script should have compiler options to enable you to use the same compiler you are using for the LAMMPS build, which can avoid problems that can arise when linking LAMMPS to the MPI library.

If you just want to run LAMMPS on a single processor, you can use the dummy MPI library provided in src/STUBS, since you don't need a true MPI library installed on your system. See the src/MAKE/Makefile.serial file for how to specify the 3 MPI variables in this case. You will also need to build the STUBS library for your platform before making LAMMPS itself. To build from the src directory, type "make stubs", or from the STUBS dir, type "make". This should create a libmpi_stubs.a file suitable for linking to LAMMPS. If the build fails, you will need to edit the STUBS/Makefile for your platform.

The file STUBS/mpi.c provides a CPU timer function called MPI_Wtime() that calls gettimeofday() . If your system doesn't support gettimeofday() , you'll need to insert code to call another timer. Note that the ANSI-standard function clock() rolls over after an hour or so, and is therefore insufficient for timing long LAMMPS simulations.

Step 6

The 3 FFT variables allow you to specify an FFT library which LAMMPS uses (for performing 1d FFTs) when running the particle-particle particle-mesh (PPPM) option for long-range Coulombics via the kspace_style command.

LAMMPS supports various open-source or vendor-supplied FFT libraries for this purpose. If you leave these 3 variables blank, LAMMPS will use the open-source KISS FFT library, which is included in the LAMMPS distribution. This library is portable to all platforms and for typical LAMMPS simulations is almost as fast as FFTW or vendor optimized libraries. If you are not including the KSPACE package in your build, you can also leave the 3 variables blank.

Otherwise, select which kinds of FFTs to use as part of the FFT_INC setting by a switch of the form -DFFT_XXX. Recommended values for XXX are: MKL, SCSL, FFTW2, and FFTW3. Legacy options are: INTEL, SGI, ACML, and T3E. For backward compatability, using -DFFT_FFTW will use the FFTW2 library. Using -DFFT_NONE will use the KISS library described above.

You may also need to set the FFT_INC, FFT_PATH, and FFT_LIB variables, so the compiler and linker can find the needed FFT header and library files. Note that on some large parallel machines which use "modules" for their compile/link environements, you may simply need to include the correct module in your build environment. Or the parallel machine may have a vendor-provided FFT library which the compiler has no trouble finding.

FFTW is a fast, portable library that should also work on any platform. You can download it from www.fftw.org. Both the legacy version 2.1.X and the newer 3.X versions are supported as -DFFT_FFTW2 or -DFFT_FFTW3. Building FFTW for your box should be as simple as ./configure; make. Note that on some platforms FFTW2 has been pre-installed, and uses renamed files indicating the precision it was compiled with, e.g. sfftw.h, or dfftw.h instead of fftw.h. In this case, you can specify an additional define variable for FFT_INC called -DFFTW_SIZE, which will select the correct include file. In this case, for FFT_LIB you must also manually specify the correct library, namely -lsfftw or -ldfftw.

The FFT_INC variable also allows for a -DFFT_SINGLE setting that will use single-precision FFTs with PPPM, which can speed-up long-range calulations, particularly in parallel or on GPUs. Fourier transform and related PPPM operations are somewhat insensitive to floating point truncation errors and thus do not always need to be performed in double precision. Using the -DFFT_SINGLE setting trades off a little accuracy for reduced memory use and parallel communication costs for transposing 3d FFT data. Note that single precision FFTs have only been tested with the FFTW3, FFTW2, MKL, and KISS FFT options.

Step 7

The 3 JPG variables allow you to specify a JPEG and/or PNG library which LAMMPS uses when writing out JPEG or PNG files via the dump image command. These can be left blank if you do not use the -DLAMMPS_JPEG or -DLAMMPS_PNG switches discussed above in Step 4, since in that case JPEG/PNG output will be disabled.

A standard JPEG library usually goes by the name libjpeg.a or libjpeg.so and has an associated header file jpeglib.h. Whichever JPEG library you have on your platform, you'll need to set the appropriate JPG_INC, JPG_PATH, and JPG_LIB variables, so that the compiler and linker can find it.

A standard PNG library usually goes by the name libpng.a or libpng.so and has an associated header file png.h. Whichever PNG library you have on your platform, you'll need to set the appropriate JPG_INC, JPG_PATH, and JPG_LIB variables, so that the compiler and linker can find it.

As before, if these header and library files are in the usual place on your machine, you may not need to set these variables.

Step 8

Note that by default only a few of LAMMPS optional packages are installed. To build LAMMPS with optional packages, see this section below, before proceeding to Step 9.

Step 9

That's it. Once you have a correct Makefile.foo, you have installed the optional LAMMPS packages you want to include in your build, and you have pre-built any other needed libraries (e.g. MPI, FFT, package libraries), all you need to do from the src directory is type something like this:

make foo
 or
 gmake foo 
 

You should get the executable lmp_foo when the build is complete.


Errors that can occur when making LAMMPS:

IMPORTANT NOTE: If an error occurs when building LAMMPS, the compiler or linker will state very explicitly what the problem is. The error message should give you a hint as to which of the steps above has failed, and what you need to do in order to fix it. Building a code with a Makefile is a very logical process. The compiler and linker need to find the appropriate files and those files need to be compatible with LAMMPS source files. When a make fails, there is usually a very simple reason, which you or a local expert will need to fix.

Here are two non-obvious errors that can occur:

(1) If the make command breaks immediately with errors that indicate it can't find files with a "*" in their names, this can be because your machine's native make doesn't support wildcard expansion in a makefile. Try gmake instead of make. If that doesn't work, try using a -f switch with your make command to use a pre-generated Makefile.list which explicitly lists all the needed files, e.g.

make makelist
 make -f Makefile.list linux
 gmake -f Makefile.list mac 
 

The first "make" command will create a current Makefile.list with all the file names in your src dir. The 2nd "make" command (make or gmake) will use it to build LAMMPS. Note that you should include/exclude any desired optional packages before using the "make makelist" command.

(2) If you get an error that says something like 'identifier "atoll" is undefined', then your machine does not support "long long" integers. Try using the -DLAMMPS_LONGLONG_TO_LONG setting described above in Step 4.


Additional build tips:

(1) Building LAMMPS for multiple platforms.

You can make LAMMPS for multiple platforms from the same src directory. Each target creates its own object sub-directory called Obj_target where it stores the system-specific *.o files.

(2) Cleaning up.

Typing "make clean-all" or "make clean-machine" will delete *.o object files created when LAMMPS is built, for either all builds or for a particular machine.

(3) Changing the LAMMPS size limits via -DLAMMPS_SMALLBIG or -DLAMMPS_BIBIG or -DLAMMPS_SMALLSMALL

As explained above, any of these 3 settings can be specified on the LMP_INC line in your low-level src/MAKE/Makefile.foo.

The default is -DLAMMPS_SMALLBIG which allows for systems with up to 2^63 atoms and timesteps (about 9 billion billion). The atom limit is for atomic systems that do not require atom IDs. For molecular models, which require atom IDs, the limit is 2^31 atoms (about 2 billion). With this setting, image flags are stored in 32-bit integers, which means for 3 dimensions that atoms can only wrap around a periodic box at most 512 times. If atoms move through the periodic box more than this limit, the image flags will "roll over", e.g. from 511 to -512, which can cause diagnostics like the mean-squared displacement, as calculated by the compute msd command, to be faulty.

To allow for larger molecular systems or larger image flags, compile with -DLAMMPS_BIGBIG. This enables molecular systems with up to 2^63 atoms (about 9 billion billion). And image flags will not "roll over" until they reach 2^20 = 1048576.

IMPORTANT NOTE: As of 6/2012, the BIGBIG setting does not yet enable molecular systems to grow as large as 2^63. Only the image flag roll over is currently affected by this compile option.

If your system does not support 8-byte integers, you will need to compile with the -DLAMMPS_SMALLSMALL setting. This will restrict your total number of atoms (for atomic or molecular models) and timesteps to 2^31 (about 2 billion). Image flags will roll over at 2^9 = 512.

Note that in src/lmptype.h there are also settings for the MPI data types associated with the integers that store atom IDs and total system sizes. These need to be consistent with the associated C data types, or else LAMMPS will generate a run-time error.

In all cases, the size of problem that can be run on a per-processor basis is limited by 4-byte integer storage to 2^31 atoms per processor (about 2 billion). This should not normally be a restriction since such a problem would have a huge per-processor memory footprint due to neighbor lists and would run very slowly in terms of CPU secs/timestep.


Building for a Mac:

OS X is BSD Unix, so it should just work. See the src/MAKE/Makefile.mac file.


Building for Windows:

The LAMMPS download page has an option to download both a serial and parallel pre-built Windows exeutable. See the Running LAMMPS section for instructions for running these executables on a Windows box.

The pre-built executables are built with a subset of the available pacakges; see the download page for the list. If you want a Windows version with specific packages included and excluded, you can build it yourself.

One way to do this is install and use cygwin to build LAMMPS with a standard Linus make, just as you would on any Linux box; see src/MAKE/Makefile.cygwin.

The other way to do this is using Visual Studio and project files. See the src/WINDOWS directory and its README.txt file for instructions on both a basic build and a customized build with pacakges you select.


2.3 Making LAMMPS with optional packages

This section has the following sub-sections:


Package basics:

The source code for LAMMPS is structured as a set of core files which are always included, plus optional packages. Packages are groups of files that enable a specific set of features. For example, force fields for molecular systems or granular systems are in packages. You can see the list of all packages by typing "make package" from within the src directory of the LAMMPS distribution.

If you use a command in a LAMMPS input script that is specific to a particular package, you must have built LAMMPS with that package, else you will get an error that the style is invalid or the command is unknown. Every command's doc page specfies if it is part of a package. You can also type

lmp_machine -h 
 

to run your executable with the optional -h command-line switch for "help", which will list the styles and commands known to your executable.

There are two kinds of packages in LAMMPS, standard and user packages. More information about the contents of standard and user packages is given in Section_packages of the manual. The difference between standard and user packages is as follows:

Standard packages are supported by the LAMMPS developers and are written in a syntax and style consistent with the rest of LAMMPS. This means we will answer questions about them, debug and fix them if necessary, and keep them compatible with future changes to LAMMPS.

User packages have been contributed by users, and always begin with the user prefix. If they are a single command (single file), they are typically in the user-misc package. Otherwise, they are a a set of files grouped together which add a specific functionality to the code.

User packages don't necessarily meet the requirements of the standard packages. If you have problems using a feature provided in a user package, you will likely need to contact the contributor directly to get help. Information on how to submit additions you make to LAMMPS as a user-contributed package is given in this section of the documentation.

Some packages (both standard and user) require additional libraries. See more details below.


Including/excluding packages:

To use or not use a package you must include or exclude it before building LAMMPS. From the src directory, this is typically as simple as:

make yes-colloid
 make g++ 
 

or

make no-manybody
 make g++ 
 

IMPORTANT NOTE: You should NOT include/exclude packages and build LAMMPS in a single make command by using multiple targets, e.g. make yes-colloid g++. This is because the make procedure creates a list of source files that will be out-of-date for the build if the package configuration changes during the same command.

Some packages have individual files that depend on other packages being included. LAMMPS checks for this and does the right thing. I.e. individual files are only included if their dependencies are already included. Likewise, if a package is excluded, other files dependent on that package are also excluded.

The reason to exclude packages is if you will never run certain kinds of simulations. For some packages, this will keep you from having to build auxiliary libraries (see below), and will also produce a smaller executable which may run a bit faster.

When you download a LAMMPS tarball, these packages are pre-installed in the src directory: KSPACE, MANYBODY,MOLECULE. When you download LAMMPS source files from the SVN or Git repositories, no packages are pre-installed.

Packages are included or excluded by typing "make yes-name" or "make no-name", where "name" is the name of the package in lower-case, e.g. name = kspace for the KSPACE package or name = user-atc for the USER-ATC package. You can also type "make yes-standard", "make no-standard", "make yes-user", "make no-user", "make yes-all" or "make no-all" to include/exclude various sets of packages. Type "make package" to see the all of the package-related make options.

IMPORTANT NOTE: Inclusion/exclusion of a package works by simply moving files back and forth between the main src directory and sub-directories with the package name (e.g. src/KSPACE, src/USER-ATC), so that the files are seen or not seen when LAMMPS is built. After you have included or excluded a package, you must re-build LAMMPS.

Additional package-related make options exist to help manage LAMMPS files that exist in both the src directory and in package sub-directories. You do not normally need to use these commands unless you are editing LAMMPS files or have downloaded a patch from the LAMMPS WWW site.

Typing "make package-update" will overwrite src files with files from the package sub-directories if the package has been included. It should be used after a patch is installed, since patches only update the files in the package sub-directory, but not the src files. Typing "make package-overwrite" will overwrite files in the package sub-directories with src files.

Typing "make package-status" will show which packages are currently included. Of those that are included, it will list files that are different in the src directory and package sub-directory. Typing "make package-diff" lists all differences between these files. Again, type "make package" to see all of the package-related make options.


Packages that require extra libraries:

A few of the standard and user packages require additional auxiliary libraries. They must be compiled first, before LAMMPS is built. If you get a LAMMPS build error about a missing library, this is likely the reason. See the Section_packages doc page for a list of packages that have auxiliary libraries.

Code for some of these auxiliary libraries is included in the LAMMPS distribution under the lib directory. Examples are the USER-ATC and MEAM packages. Some auxiliary libraries are not included with LAMMPS; to use the associated package you must download and install the auxiliary library yourself. Examples are the KIM and VORONOI and USER-MOLFILE packages.

For libraries with provided source code, each lib directory has a README file (e.g. lib/reax/README) with instructions on how to build that library. Typically this is done by typing something like:

make -f Makefile.g++ 
 

If one of the provided Makefiles is not appropriate for your system you will need to edit or add one. Note that all the Makefiles have a setting for EXTRAMAKE at the top that names a Makefile.lammps.* file.

If successful, this will produce 2 files in the lib directory:

libpackage.a
 Makefile.lammps 
 

The Makefile.lammps file is a copy of the EXTRAMAKE file specified in the Makefile you used.

You MUST insure that the settings in Makefile.lammps are appropriate for your system. If they are not, the LAMMPS build will fail.

As explained in the lib/package/README files, they are used to specify additional system libraries and their locations so that LAMMPS can build with the auxiliary library. For example, if the MEAM or REAX packages are used, the auxiliary libraries consist of F90 code, build with a F90 complier. To link that library with LAMMPS (a C++ code) via whatever C++ compiler LAMMPS is built with, typically requires additional Fortran-to-C libraries be included in the link. Another example are the BLAS and LAPACK libraries needed to use the USER-ATC or USER-AWPMD packages.

For libraries without provided source code, see the src/package/Makefile.lammps file for information on where to find the library and how to build it. E.g. the file src/KIM/Makefile.lammps. This file serves the same purpose as the lib/package/Makefile.lammps file described above. It has settings needed when LAMMPS is built to link with the auxiliary library. Again, you MUST insure that the settings in src/package/Makefile.lammps are appropriate for your system and where you installed the auxiliary library. If they are not, the LAMMPS build will fail.


2.4 Building LAMMPS via the Make.py script

The src directory includes a Make.py script, written in Python, which can be used to automate various steps of the build process.

You can run the script from the src directory by typing either:

Make.py
 python Make.py 
 

which will give you info about the tool. For the former to work, you may need to edit the 1st line of the script to point to your local Python. And you may need to insure the script is executable:

chmod +x Make.py 
 

The following options are supported as switches:

Help on any switch can be listed by using -h, e.g.

Make.py -h -i -p 
 

At a hi-level, these are the kinds of package management and build tasks that can be performed easily, using the Make.py tool:

The last bullet can be useful when you wish to build a stripped-down version of LAMMPS to run a specific script(s). Or when you wish to move the minimal amount of files to another platform for a remote LAMMPS build.

Note that using Make.py is not a substitute for insuring you have a valid src/MAKE/Makefile.foo for your system, or that external library Makefiles in any lib/* directories you use are also valid for your system. But once you have done that, you can use Make.py to quickly include/exclude the packages and external libraries needed by your input scripts.


2.5 Building LAMMPS as a library

LAMMPS can be built as either a static or shared library, which can then be called from another application or a scripting language. See this section for more info on coupling LAMMPS to other codes. See this section for more info on wrapping and running LAMMPS from Python.

Static library:

To build LAMMPS as a static library (*.a file on Linux), type

make makelib
 make -f Makefile.lib foo 
 

where foo is the machine name. This kind of library is typically used to statically link a driver application to LAMMPS, so that you can insure all dependencies are satisfied at compile time. Note that inclusion or exclusion of any desired optional packages should be done before typing "make makelib". The first "make" command will create a current Makefile.lib with all the file names in your src dir. The second "make" command will use it to build LAMMPS as a static library, using the ARCHIVE and ARFLAGS settings in src/MAKE/Makefile.foo. The build will create the file liblammps_foo.a which another application can link to.

Shared library:

To build LAMMPS as a shared library (*.so file on Linux), which can be dynamically loaded, e.g. from Python, type

make makeshlib
 make -f Makefile.shlib foo 
 

where foo is the machine name. This kind of library is required when wrapping LAMMPS with Python; see Section_python for details. Again, note that inclusion or exclusion of any desired optional packages should be done before typing "make makelib". The first "make" command will create a current Makefile.shlib with all the file names in your src dir. The second "make" command will use it to build LAMMPS as a shared library, using the SHFLAGS and SHLIBFLAGS settings in src/MAKE/Makefile.foo. The build will create the file liblammps_foo.so which another application can link to dyamically. It will also create a soft link liblammps.so, which the Python wrapper uses by default.

Note that for a shared library to be usable by a calling program, all the auxiliary libraries it depends on must also exist as shared libraries. This will be the case for libraries included with LAMMPS, such as the dummy MPI library in src/STUBS or any package libraries in lib/packges, since they are always built as shared libraries with the -fPIC switch. However, if a library like MPI or FFTW does not exist as a shared library, the second make command will generate an error. This means you will need to install a shared library version of the package. The build instructions for the library should tell you how to do this.

As an example, here is how to build and install the MPICH library, a popular open-source version of MPI, distributed by Argonne National Labs, as a shared library in the default /usr/local/lib location:

./configure --enable-shared
 make
 make install 
 

You may need to use "sudo make install" in place of the last line if you do not have write privileges for /usr/local/lib. The end result should be the file /usr/local/lib/libmpich.so.

Additional requirement for using a shared library:

The operating system finds shared libraries to load at run-time using the environment variable LD_LIBRARY_PATH. So you may wish to copy the file src/liblammps.so or src/liblammps_g++.so (for example) to a place the system can find it by default, such as /usr/local/lib, or you may wish to add the LAMMPS src directory to LD_LIBRARY_PATH, so that the current version of the shared library is always available to programs that use it.

For the csh or tcsh shells, you would add something like this to your ~/.cshrc file:

setenv LD_LIBRARY_PATH $LD_LIBRARY_PATH:/home/sjplimp/lammps/src 
 
Calling the LAMMPS library:

Either flavor of library (static or shared0 allows one or more LAMMPS objects to be instantiated from the calling program.

When used from a C++ program, all of LAMMPS is wrapped in a LAMMPS_NS namespace; you can safely use any of its classes and methods from within the calling code, as needed.

When used from a C or Fortran program or a scripting language like Python, the library has a simple function-style interface, provided in src/library.cpp and src/library.h.

See the sample codes in examples/COUPLE/simple for examples of C++ and C and Fortran codes that invoke LAMMPS thru its library interface. There are other examples as well in the COUPLE directory which are discussed in Section_howto 10 of the manual. See Section_python of the manual for a description of the Python wrapper provided with LAMMPS that operates through the LAMMPS library interface.

The files src/library.cpp and library.h define the C-style API for using LAMMPS as a library. See Section_howto 19 of the manual for a description of the interface and how to extend it for your needs.


2.6 Running LAMMPS

By default, LAMMPS runs by reading commands from stdin; e.g. lmp_linux < in.file. This means you first create an input script (e.g. in.file) containing the desired commands. This section describes how input scripts are structured and what commands they contain.

You can test LAMMPS on any of the sample inputs provided in the examples or bench directory. Input scripts are named in.* and sample outputs are named log.*.name.P where name is a machine and P is the number of processors it was run on.

Here is how you might run a standard Lennard-Jones benchmark on a Linux box, using mpirun to launch a parallel job:

cd src
 make linux
 cp lmp_linux ../bench
 cd ../bench
 mpirun -np 4 lmp_linux < in.lj 
 

See this page for timings for this and the other benchmarks on various platforms.


On a Windows box, you can skip making LAMMPS and simply download an executable, as described above, though the pre-packaged executables include only certain packages.

To run a LAMMPS executable on a Windows machine, first decide whether you want to download the non-MPI (serial) or the MPI (parallel) version of the executable. Download and save the version you have chosen.

For the non-MPI version, follow these steps:

For the MPI version, which allows you to run LAMMPS under Windows on multiple processors, follow these steps:


The screen output from LAMMPS is described in the next section. As it runs, LAMMPS also writes a log.lammps file with the same information.

Note that this sequence of commands copies the LAMMPS executable (lmp_linux) to the directory with the input files. This may not be necessary, but some versions of MPI reset the working directory to where the executable is, rather than leave it as the directory where you launch mpirun from (if you launch lmp_linux on its own and not under mpirun). If that happens, LAMMPS will look for additional input files and write its output files to the executable directory, rather than your working directory, which is probably not what you want.

If LAMMPS encounters errors in the input script or while running a simulation it will print an ERROR message and stop or a WARNING message and continue. See Section_errors for a discussion of the various kinds of errors LAMMPS can or can't detect, a list of all ERROR and WARNING messages, and what to do about them.

LAMMPS can run a problem on any number of processors, including a single processor. In theory you should get identical answers on any number of processors and on any machine. In practice, numerical round-off can cause slight differences and eventual divergence of molecular dynamics phase space trajectories.

LAMMPS can run as large a problem as will fit in the physical memory of one or more processors. If you run out of memory, you must run on more processors or setup a smaller problem.


2.7 Command-line options

At run time, LAMMPS recognizes several optional command-line switches which may be used in any order. Either the full word or a one-or-two letter abbreviation can be used:

For example, lmp_ibm might be launched as follows:

mpirun -np 16 lmp_ibm -v f tmp.out -l my.log -sc none < in.alloy
 mpirun -np 16 lmp_ibm -var f tmp.out -log my.log -screen none < in.alloy 
 

Here are the details on the options:

-cuda on/off 
 

Explicitly enable or disable CUDA support, as provided by the USER-CUDA package. If LAMMPS is built with this package, as described above in Section 2.3, then by default LAMMPS will run in CUDA mode. If this switch is set to "off", then it will not, even if it was built with the USER-CUDA package, which means you can run standard LAMMPS or with the GPU package for testing or benchmarking purposes. The only reason to set the switch to "on", is to check if LAMMPS was built with the USER-CUDA package, since an error will be generated if it was not.

-echo style 
 

Set the style of command echoing. The style can be none or screen or log or both. Depending on the style, each command read from the input script will be echoed to the screen and/or logfile. This can be useful to figure out which line of your script is causing an input error. The default value is log. The echo style can also be set by using the echo command in the input script itself.

-in file 
 

Specify a file to use as an input script. This is an optional switch when running LAMMPS in one-partition mode. If it is not specified, LAMMPS reads its input script from stdin - e.g. lmp_linux < in.run. This is a required switch when running LAMMPS in multi-partition mode, since multiple processors cannot all read from stdin.

-help 
 

Print a list of options compiled into this executable for each LAMMPS style (atom_style, fix, compute, pair_style, bond_style, etc). This can help you know if the command you want to use was included via the appropriate package. LAMMPS will print the info and immediately exit if this switch is used.

-log file 
 

Specify a log file for LAMMPS to write status information to. In one-partition mode, if the switch is not used, LAMMPS writes to the file log.lammps. If this switch is used, LAMMPS writes to the specified file. In multi-partition mode, if the switch is not used, a log.lammps file is created with hi-level status information. Each partition also writes to a log.lammps.N file where N is the partition ID. If the switch is specified in multi-partition mode, the hi-level logfile is named "file" and each partition also logs information to a file.N. For both one-partition and multi-partition mode, if the specified file is "none", then no log files are created. Using a log command in the input script will override this setting. Option -plog will override the name of the partition log files file.N.

-nocite 
 

Disable writing the log.cite file which is normally written to list references for specific cite-able features used during a LAMMPS run. See the citation page for more details.

-partition 8x2 4 5 ... 
 

Invoke LAMMPS in multi-partition mode. When LAMMPS is run on P processors and this switch is not used, LAMMPS runs in one partition, i.e. all P processors run a single simulation. If this switch is used, the P processors are split into separate partitions and each partition runs its own simulation. The arguments to the switch specify the number of processors in each partition. Arguments of the form MxN mean M partitions, each with N processors. Arguments of the form N mean a single partition with N processors. The sum of processors in all partitions must equal P. Thus the command "-partition 8x2 4 5" has 10 partitions and runs on a total of 25 processors.

Running with multiple partitions can e useful for running multi-replica simulations, where each replica runs on on one or a few processors. Note that with MPI installed on a machine (e.g. your desktop), you can run on more (virtual) processors than you have physical processors.

To run multiple independent simulatoins from one input script, using multiple partitions, see Section_howto 4 of the manual. World- and universe-style variables are useful in this context.

-plog file 
 

Specify the base name for the partition log files, so partition N writes log information to file.N. If file is none, then no partition log files are created. This overrides the filename specified in the -log command-line option. This option is useful when working with large numbers of partitions, allowing the partition log files to be suppressed (-plog none) or placed in a sub-directory (-plog replica_files/log.lammps) If this option is not used the log file for partition N is log.lammps.N or whatever is specified by the -log command-line option.

-pscreen file 
 

Specify the base name for the partition screen file, so partition N writes screen information to file.N. If file is none, then no partition screen files are created. This overrides the filename specified in the -screen command-line option. This option is useful when working with large numbers of partitions, allowing the partition screen files to be suppressed (-pscreen none) or placed in a sub-directory (-pscreen replica_files/screen). If this option is not used the screen file for partition N is screen.N or whatever is specified by the -screen command-line option.

-reorder nth N
 -reorder custom filename 
 

Reorder the processors in the MPI communicator used to instantiate LAMMPS, in one of several ways. The original MPI communicator ranks all P processors from 0 to P-1. The mapping of these ranks to physical processors is done by MPI before LAMMPS begins. It may be useful in some cases to alter the rank order. E.g. to insure that cores within each node are ranked in a desired order. Or when using the run_style verlet/split command with 2 partitions to insure that a specific Kspace processor (in the 2nd partition) is matched up with a specific set of processors in the 1st partition. See the Section_accelerate doc pages for more details.

If the keyword nth is used with a setting N, then it means every Nth processor will be moved to the end of the ranking. This is useful when using the run_style verlet/split command with 2 partitions via the -partition command-line switch. The first set of processors will be in the first partition, the 2nd set in the 2nd partition. The -reorder command-line switch can alter this so that the 1st N procs in the 1st partition and one proc in the 2nd partition will be ordered consecutively, e.g. as the cores on one physical node. This can boost performance. For example, if you use "-reorder nth 4" and "-partition 9 3" and you are running on 12 processors, the processors will be reordered from

0 1 2 3 4 5 6 7 8 9 10 11 
 

to

0 1 2 4 5 6 8 9 10 3 7 11 
 

so that the processors in each partition will be

0 1 2 4 5 6 8 9 10 
 3 7 11 
 

See the "processors" command for how to insure processors from each partition could then be grouped optimally for quad-core nodes.

If the keyword is custom, then a file that specifies a permutation of the processor ranks is also specified. The format of the reorder file is as follows. Any number of initial blank or comment lines (starting with a "#" character) can be present. These should be followed by P lines of the form:

I J 
 

where P is the number of processors LAMMPS was launched with. Note that if running in multi-partition mode (see the -partition switch above) P is the total number of processors in all partitions. The I and J values describe a permutation of the P processors. Every I and J should be values from 0 to P-1 inclusive. In the set of P I values, every proc ID should appear exactly once. Ditto for the set of P J values. A single I,J pairing means that the physical processor with rank I in the original MPI communicator will have rank J in the reordered communicator.

Note that rank ordering can also be specified by many MPI implementations, either by environment variables that specify how to order physical processors, or by config files that specify what physical processors to assign to each MPI rank. The -reorder switch simply gives you a portable way to do this without relying on MPI itself. See the processors out command for how to output info on the final assignment of physical processors to the LAMMPS simulation domain.

-screen file 
 

Specify a file for LAMMPS to write its screen information to. In one-partition mode, if the switch is not used, LAMMPS writes to the screen. If this switch is used, LAMMPS writes to the specified file instead and you will see no screen output. In multi-partition mode, if the switch is not used, hi-level status information is written to the screen. Each partition also writes to a screen.N file where N is the partition ID. If the switch is specified in multi-partition mode, the hi-level screen dump is named "file" and each partition also writes screen information to a file.N. For both one-partition and multi-partition mode, if the specified file is "none", then no screen output is performed. Option -pscreen will override the name of the partition screen files file.N.

-suffix style 
 

Use variants of various styles if they exist. The specified style can be opt, omp, gpu, or cuda. These refer to optional packages that LAMMPS can be built with, as described above in Section 2.3. The "opt" style corrsponds to the OPT package, the "omp" style to the USER-OMP package, the "gpu" style to the GPU package, and the "cuda" style to the USER-CUDA package.

As an example, all of the packages provide a pair_style lj/cut variant, with style names lj/cut/opt, lj/cut/omp, lj/cut/gpu, or lj/cut/cuda. A variant styles can be specified explicitly in your input script, e.g. pair_style lj/cut/gpu. If the -suffix switch is used, you do not need to modify your input script. The specified suffix (opt,omp,gpu,cuda) is automatically appended whenever your input script command creates a new atom, pair, fix, compute, or run style. If the variant version does not exist, the standard version is created.

For the GPU package, using this command-line switch also invokes the default GPU settings, as if the command "package gpu force/neigh 0 0 1" were used at the top of your input script. These settings can be changed by using the package gpu command in your script if desired.

For the OMP package, using this command-line switch also invokes the default OMP settings, as if the command "package omp *" were used at the top of your input script. These settings can be changed by using the package omp command in your script if desired.

The suffix command can also set a suffix and it can also turn off/on any suffix setting made via the command line.

-var name value1 value2 ... 
 

Specify a variable that will be defined for substitution purposes when the input script is read. "Name" is the variable name which can be a single character (referenced as $x in the input script) or a full string (referenced as ${abc}). An index-style variable will be created and populated with the subsequent values, e.g. a set of filenames. Using this command-line option is equivalent to putting the line "variable name index value1 value2 ..." at the beginning of the input script. Defining an index variable as a command-line argument overrides any setting for the same index variable in the input script, since index variables cannot be re-defined. See the variable command for more info on defining index and other kinds of variables and this section for more info on using variables in input scripts.

NOTE: Currently, the command-line parser looks for arguments that start with "-" to indicate new switches. Thus you cannot specify multiple variable values if any of they start with a "-", e.g. a negative numeric value. It is OK if the first value1 starts with a "-", since it is automatically skipped.


2.8 LAMMPS screen output

As LAMMPS reads an input script, it prints information to both the screen and a log file about significant actions it takes to setup a simulation. When the simulation is ready to begin, LAMMPS performs various initializations and prints the amount of memory (in MBytes per processor) that the simulation requires. It also prints details of the initial thermodynamic state of the system. During the run itself, thermodynamic information is printed periodically, every few timesteps. When the run concludes, LAMMPS prints the final thermodynamic state and a total run time for the simulation. It then appends statistics about the CPU time and storage requirements for the simulation. An example set of statistics is shown here:

Loop time of 49.002 on 2 procs for 2004 atoms 
 
Pair   time (%) = 35.0495 (71.5267)
 Bond   time (%) = 0.092046 (0.187841)
 Kspce  time (%) = 6.42073 (13.103)
 Neigh  time (%) = 2.73485 (5.5811)
 Comm   time (%) = 1.50291 (3.06703)
 Outpt  time (%) = 0.013799 (0.0281601)
 Other  time (%) = 2.13669 (4.36041) 
 
Nlocal:    1002 ave, 1015 max, 989 min
 Histogram: 1 0 0 0 0 0 0 0 0 1 
 Nghost:    8720 ave, 8724 max, 8716 min 
 Histogram: 1 0 0 0 0 0 0 0 0 1
 Neighs:    354141 ave, 361422 max, 346860 min 
 Histogram: 1 0 0 0 0 0 0 0 0 1 
 
Total # of neighbors = 708282
 Ave neighs/atom = 353.434
 Ave special neighs/atom = 2.34032
 Number of reneighborings = 42
 Dangerous reneighborings = 2 
 

The first section gives the breakdown of the CPU run time (in seconds) into major categories. The second section lists the number of owned atoms (Nlocal), ghost atoms (Nghost), and pair-wise neighbors stored per processor. The max and min values give the spread of these values across processors with a 10-bin histogram showing the distribution. The total number of histogram counts is equal to the number of processors.

The last section gives aggregate statistics for pair-wise neighbors and special neighbors that LAMMPS keeps track of (see the special_bonds command). The number of times neighbor lists were rebuilt during the run is given as well as the number of potentially "dangerous" rebuilds. If atom movement triggered neighbor list rebuilding (see the neigh_modify command), then dangerous reneighborings are those that were triggered on the first timestep atom movement was checked for. If this count is non-zero you may wish to reduce the delay factor to insure no force interactions are missed by atoms moving beyond the neighbor skin distance before a rebuild takes place.

If an energy minimization was performed via the minimize command, additional information is printed, e.g.

Minimization stats:
   E initial, next-to-last, final = -0.895962 -2.94193 -2.94342
   Gradient 2-norm init/final= 1920.78 20.9992
   Gradient inf-norm init/final= 304.283 9.61216
   Iterations = 36
   Force evaluations = 177 
 

The first line lists the initial and final energy, as well as the energy on the next-to-last iteration. The next 2 lines give a measure of the gradient of the energy (force on all atoms). The 2-norm is the "length" of this force vector; the inf-norm is the largest component. The last 2 lines are statistics on how many iterations and force-evaluations the minimizer required. Multiple force evaluations are typically done at each iteration to perform a 1d line minimization in the search direction.

If a kspace_style long-range Coulombics solve was performed during the run (PPPM, Ewald), then additional information is printed, e.g.

FFT time (% of Kspce) = 0.200313 (8.34477)
 FFT Gflps 3d 1d-only = 2.31074 9.19989 
 

The first line gives the time spent doing 3d FFTs (4 per timestep) and the fraction it represents of the total KSpace time (listed above). Each 3d FFT requires computation (3 sets of 1d FFTs) and communication (transposes). The total flops performed is 5Nlog_2(N), where N is the number of points in the 3d grid. The FFTs are timed with and without the communication and a Gflop rate is computed. The 3d rate is with communication; the 1d rate is without (just the 1d FFTs). Thus you can estimate what fraction of your FFT time was spent in communication, roughly 75% in the example above.


2.9 Tips for users of previous LAMMPS versions

The current C++ began with a complete rewrite of LAMMPS 2001, which was written in F90. Features of earlier versions of LAMMPS are listed in Section_history. The F90 and F77 versions (2001 and 99) are also freely distributed as open-source codes; check the LAMMPS WWW Site for distribution information if you prefer those versions. The 99 and 2001 versions are no longer under active development; they do not have all the features of C++ LAMMPS.

If you are a previous user of LAMMPS 2001, these are the most significant changes you will notice in C++ LAMMPS:

(1) The names and arguments of many input script commands have changed. All commands are now a single word (e.g. read_data instead of read data).

(2) All the functionality of LAMMPS 2001 is included in C++ LAMMPS, but you may need to specify the relevant commands in different ways.

(3) The format of the data file can be streamlined for some problems. See the read_data command for details. The data file section "Nonbond Coeff" has been renamed to "Pair Coeff" in C++ LAMMPS.

(4) Binary restart files written by LAMMPS 2001 cannot be read by C++ LAMMPS with a read_restart command. This is because they were output by F90 which writes in a different binary format than C or C++ writes or reads. Use the restart2data tool provided with LAMMPS 2001 to convert the 2001 restart file to a text data file. Then edit the data file as necessary before using the C++ LAMMPS read_data command to read it in.

(5) There are numerous small numerical changes in C++ LAMMPS that mean you will not get identical answers when comparing to a 2001 run. However, your initial thermodynamic energy and MD trajectory should be close if you have setup the problem for both codes the same.

diff --git a/doc/Section_start.txt b/doc/Section_start.txt index f905bd2e2..f785d4d10 100644 --- a/doc/Section_start.txt +++ b/doc/Section_start.txt @@ -1,1398 +1,1406 @@ "Previous Section"_Section_intro.html - "LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc - "Next Section"_Section_commands.html :c :link(lws,http://lammps.sandia.gov) :link(ld,Manual.html) :link(lc,Section_commands.html#comm) :line 2. Getting Started :h3 This section describes how to build and run LAMMPS, for both new and experienced users. 2.1 "What's in the LAMMPS distribution"_#start_1 2.2 "Making LAMMPS"_#start_2 2.3 "Making LAMMPS with optional packages"_#start_3 2.4 "Building LAMMPS via the Make.py script"_#start_4 2.5 "Building LAMMPS as a library"_#start_5 2.6 "Running LAMMPS"_#start_6 2.7 "Command-line options"_#start_7 2.8 "Screen output"_#start_8 2.9 "Tips for users of previous versions"_#start_9 :all(b) :line :line 2.1 What's in the LAMMPS distribution :h4,link(start_1) When you download LAMMPS you will need to unzip and untar the downloaded file with the following commands, after placing the file in an appropriate directory. gunzip lammps*.tar.gz tar xvf lammps*.tar :pre This will create a LAMMPS directory containing two files and several sub-directories: README: text file LICENSE: the GNU General Public License (GPL) bench: benchmark problems doc: documentation examples: simple test problems potentials: embedded atom method (EAM) potential files src: source files tools: pre- and post-processing tools :tb(s=:) If you download one of the Windows executables from the download page, then you just get a single file: lmp_windows.exe :pre Skip to the "Running LAMMPS"_#start_6 sections for info on how to launch these executables on a Windows box. The Windows executables for serial or parallel only include certain packages and bug-fixes/upgrades listed on "this page"_http://lammps.sandia.gov/bug.html up to a certain date, as stated on the download page. If you want something with more packages or that is more current, you'll have to download the source tarball and build it yourself from source code using Microsoft Visual Studio, as described in the next section. :line 2.2 Making LAMMPS :h4,link(start_2) This section has the following sub-sections: "Read this first"_#start_2_1 "Steps to build a LAMMPS executable"_#start_2_2 "Common errors that can occur when making LAMMPS"_#start_2_3 "Additional build tips"_#start_2_4 "Building for a Mac"_#start_2_5 "Building for Windows"_#start_2_6 :ul :line [{Read this first:}] :link(start_2_1) Building LAMMPS can be non-trivial. You may need to edit a makefile, there are compiler options to consider, additional libraries can be used (MPI, FFT, JPEG, PNG), LAMMPS packages may be included or excluded, some of these packages use auxiliary libraries which need to be pre-built, etc. Please read this section carefully. If you are not comfortable with makefiles, or building codes on a Unix platform, or running an MPI job on your machine, please find a local expert to help you. Many compiling, linking, and run problems that users have are often not LAMMPS issues - they are peculiar to the user's system, compilers, libraries, etc. Such questions are better answered by a local expert. If you have a build problem that you are convinced is a LAMMPS issue (e.g. the compiler complains about a line of LAMMPS source code), then please post a question to the "LAMMPS mail list"_http://lammps.sandia.gov/mail.html. If you succeed in building LAMMPS on a new kind of machine, for which there isn't a similar Makefile for in the src/MAKE directory, send it to the developers and we can include it in the LAMMPS distribution. :line [{Steps to build a LAMMPS executable:}] :link(start_2_2) [Step 0] The src directory contains the C++ source and header files for LAMMPS. It also contains a top-level Makefile and a MAKE sub-directory with low-level Makefile.* files for many machines. From within the src directory, type "make" or "gmake". You should see a list of available choices. If one of those is the machine and options you want, you can type a command like: make linux or gmake mac :pre Note that on a multi-processor or multi-core platform you can launch a parallel make, by using the "-j" switch with the make command, which will build LAMMPS more quickly. If you get no errors and an executable like lmp_linux or lmp_mac is produced, you're done; it's your lucky day. Note that by default only a few of LAMMPS optional packages are installed. To build LAMMPS with optional packages, see "this section"_#start_3 below. [Step 1] If Step 0 did not work, you will need to create a low-level Makefile for your machine, like Makefile.foo. You should make a copy of an existing src/MAKE/Makefile.* as a starting point. The only portions of the file you need to edit are the first line, the "compiler/linker settings" section, and the "LAMMPS-specific settings" section. [Step 2] Change the first line of src/MAKE/Makefile.foo to list the word "foo" after the "#", and whatever other options it will set. This is the line you will see if you just type "make". [Step 3] The "compiler/linker settings" section lists compiler and linker settings for your C++ compiler, including optimization flags. You can use g++, the open-source GNU compiler, which is available on all Unix systems. You can also use mpicc which will typically be available if MPI is installed on your system, though you should check which actual compiler it wraps. Vendor compilers often produce faster code. On boxes with Intel CPUs, we suggest using the commercial Intel icc compiler, which can be downloaded from "Intel's compiler site"_intel. :link(intel,http://www.intel.com/software/products/noncom) If building a C++ code on your machine requires additional libraries, then you should list them as part of the LIB variable. The DEPFLAGS setting is what triggers the C++ compiler to create a dependency list for a source file. This speeds re-compilation when source (*.cpp) or header (*.h) files are edited. Some compilers do not support dependency file creation, or may use a different switch than -D. GNU g++ works with -D. If your compiler can't create dependency files, then you'll need to create a Makefile.foo patterned after Makefile.storm, which uses different rules that do not involve dependency files. Note that when you build LAMMPS for the first time on a new platform, a long list of *.d files will be printed out rapidly. This is not an error; it is the Makefile doing its normal creation of dependencies. [Step 4] The "system-specific settings" section has several parts. Note that if you change any -D setting in this section, you should do a full re-compile, after typing "make clean" (which will describe different clean options). The LMP_INC variable is used to include options that turn on ifdefs within the LAMMPS code. The options that are currently recogized are: -DLAMMPS_GZIP -DLAMMPS_JPEG -DLAMMPS_PNG +-DLAMMPS_FFMPEG -DLAMMPS_MEMALIGN -DLAMMPS_XDR -DLAMMPS_SMALLBIG -DLAMMPS_BIGBIG -DLAMMPS_SMALLSMALL -DLAMMPS_LONGLONG_TO_LONG -DPACK_ARRAY -DPACK_POINTER -DPACK_MEMCPY :ul The read_data and dump commands will read/write gzipped files if you -compile with -DLAMMPS_GZIP. It requires that your Unix support the -"popen" command. +compile with -DLAMMPS_GZIP. It requires that your machine supports +the "popen" function in the standard runtime library and that a gzip +executable can be found by LAMMPS during a run. -If you use -DLAMMPS_JPEG, the "dump image"_dump.html command will be -able to write out JPEG image files. For JPEG files, you must also link -LAMMPS with a JPEG library, as described below. If you use +If you use -DLAMMPS_JPEG, the "dump image"_dump_image.html command +will be able to write out JPEG image files. For JPEG files, you must +also link LAMMPS with a JPEG library, as described below. If you use -DLAMMPS_PNG, the "dump image"_dump.html command will be able to write out PNG image files. For PNG files, you must also link LAMMPS with a PNG library, as described below. If neither of those two defines are -used, LAMMPS will only be able to write out text-based PPM image +used, LAMMPS will only be able to write out uncompressed PPM image files. +If you use -DLAMMPS_FFMPEG, the "dump movie"_dump_image.html command +will be available to support on-the-fly generation of rendered movies +the need to store intermediate image files. It requires that your +machines supports the "popen" function in the standard runtime library +and that an FFmpeg executable can be found by LAMMPS during the run. + Using -DLAMMPS_MEMALIGN= enables the use of the posix_memalign() call instead of malloc() when large chunks or memory are allocated by LAMMPS. This can help to make more efficient use of vector instructions of modern CPUS, since dynamically allocated memory has to be aligned on larger than default byte boundaries (e.g. 16 bytes instead of 8 bytes on x86 type platforms) for optimal performance. If you use -DLAMMPS_XDR, the build will include XDR compatibility files for doing particle dumps in XTC format. This is only necessary if your platform does have its own XDR files available. See the Restrictions section of the "dump"_dump.html command for details. Use at most one of the -DLAMMPS_SMALLBIG, -DLAMMPS_BIGBIG, -D-DLAMMPS_SMALLSMALL settings. The default is -DLAMMPS_SMALLBIG. These settings refer to use of 4-byte (small) vs 8-byte (big) integers within LAMMPS, as specified in src/lmptype.h. The only reason to use the BIGBIG setting is to enable simulation of huge molecular systems with more than 2 billion atoms or to allow moving atoms to wrap back through a periodic box more than 512 times. The only reason to use the SMALLSMALL setting is if your machine does not support 64-bit integers. See the "Additional build tips"_#start_2_4 section below for more details. The -DLAMMPS_LONGLONG_TO_LONG setting may be needed if your system or MPI version does not recognize "long long" data types. In this case a "long" data type is likely already 64-bits, in which case this setting will convert to that data type. Using one of the -DPACK_ARRAY, -DPACK_POINTER, and -DPACK_MEMCPY options can make for faster parallel FFTs (in the PPPM solver) on some platforms. The -DPACK_ARRAY setting is the default. See the "kspace_style"_kspace_style.html command for info about PPPM. See Step 6 below for info about building LAMMPS with an FFT library. [Step 5] The 3 MPI variables are used to specify an MPI library to build LAMMPS with. If you want LAMMPS to run in parallel, you must have an MPI library installed on your platform. If you use an MPI-wrapped compiler, such as "mpicc" to build LAMMPS, you should be able to leave these 3 variables blank; the MPI wrapper knows where to find the needed files. If not, and MPI is installed on your system in the usual place (under /usr/local), you also may not need to specify these 3 variables. On some large parallel machines which use "modules" for their compile/link environements, you may simply need to include the correct module in your build environment. Or the parallel machine may have a vendor-provided MPI which the compiler has no trouble finding. Failing this, with these 3 variables you can specify where the mpi.h file (MPI_INC) and the MPI library file (MPI_PATH) are found and the name of the library file (MPI_LIB). If you are installing MPI yourself, we recommend Argonne's MPICH2 or OpenMPI. MPICH can be downloaded from the "Argonne MPI site"_http://www.mcs.anl.gov/research/projects/mpich2/. OpenMPI can be downloaded from the "OpenMPI site"_http://www.open-mpi.org. Other MPI packages should also work. If you are running on a big parallel platform, your system people or the vendor should have already installed a version of MPI, which is likely to be faster than a self-installed MPICH or OpenMPI, so find out how to build and link with it. If you use MPICH or OpenMPI, you will have to configure and build it for your platform. The MPI configure script should have compiler options to enable you to use the same compiler you are using for the LAMMPS build, which can avoid problems that can arise when linking LAMMPS to the MPI library. If you just want to run LAMMPS on a single processor, you can use the dummy MPI library provided in src/STUBS, since you don't need a true MPI library installed on your system. See the src/MAKE/Makefile.serial file for how to specify the 3 MPI variables in this case. You will also need to build the STUBS library for your platform before making LAMMPS itself. To build from the src directory, type "make stubs", or from the STUBS dir, type "make". This should create a libmpi_stubs.a file suitable for linking to LAMMPS. If the build fails, you will need to edit the STUBS/Makefile for your platform. The file STUBS/mpi.c provides a CPU timer function called MPI_Wtime() that calls gettimeofday() . If your system doesn't support gettimeofday() , you'll need to insert code to call another timer. Note that the ANSI-standard function clock() rolls over after an hour or so, and is therefore insufficient for timing long LAMMPS simulations. [Step 6] The 3 FFT variables allow you to specify an FFT library which LAMMPS uses (for performing 1d FFTs) when running the particle-particle particle-mesh (PPPM) option for long-range Coulombics via the "kspace_style"_kspace_style.html command. LAMMPS supports various open-source or vendor-supplied FFT libraries for this purpose. If you leave these 3 variables blank, LAMMPS will use the open-source "KISS FFT library"_http://kissfft.sf.net, which is included in the LAMMPS distribution. This library is portable to all platforms and for typical LAMMPS simulations is almost as fast as FFTW or vendor optimized libraries. If you are not including the KSPACE package in your build, you can also leave the 3 variables blank. Otherwise, select which kinds of FFTs to use as part of the FFT_INC setting by a switch of the form -DFFT_XXX. Recommended values for XXX are: MKL, SCSL, FFTW2, and FFTW3. Legacy options are: INTEL, SGI, ACML, and T3E. For backward compatability, using -DFFT_FFTW will use the FFTW2 library. Using -DFFT_NONE will use the KISS library described above. You may also need to set the FFT_INC, FFT_PATH, and FFT_LIB variables, so the compiler and linker can find the needed FFT header and library files. Note that on some large parallel machines which use "modules" for their compile/link environements, you may simply need to include the correct module in your build environment. Or the parallel machine may have a vendor-provided FFT library which the compiler has no trouble finding. FFTW is a fast, portable library that should also work on any platform. You can download it from "www.fftw.org"_http://www.fftw.org. Both the legacy version 2.1.X and the newer 3.X versions are supported as -DFFT_FFTW2 or -DFFT_FFTW3. Building FFTW for your box should be as simple as ./configure; make. Note that on some platforms FFTW2 has been pre-installed, and uses renamed files indicating the precision it was compiled with, e.g. sfftw.h, or dfftw.h instead of fftw.h. In this case, you can specify an additional define variable for FFT_INC called -DFFTW_SIZE, which will select the correct include file. In this case, for FFT_LIB you must also manually specify the correct library, namely -lsfftw or -ldfftw. The FFT_INC variable also allows for a -DFFT_SINGLE setting that will use single-precision FFTs with PPPM, which can speed-up long-range calulations, particularly in parallel or on GPUs. Fourier transform and related PPPM operations are somewhat insensitive to floating point truncation errors and thus do not always need to be performed in double precision. Using the -DFFT_SINGLE setting trades off a little accuracy for reduced memory use and parallel communication costs for transposing 3d FFT data. Note that single precision FFTs have only been tested with the FFTW3, FFTW2, MKL, and KISS FFT options. [Step 7] The 3 JPG variables allow you to specify a JPEG and/or PNG library which LAMMPS uses when writing out JPEG or PNG files via the "dump image"_dump_image.html command. These can be left blank if you do not use the -DLAMMPS_JPEG or -DLAMMPS_PNG switches discussed above in Step 4, since in that case JPEG/PNG output will be disabled. A standard JPEG library usually goes by the name libjpeg.a or libjpeg.so and has an associated header file jpeglib.h. Whichever JPEG library you have on your platform, you'll need to set the appropriate JPG_INC, JPG_PATH, and JPG_LIB variables, so that the compiler and linker can find it. A standard PNG library usually goes by the name libpng.a or libpng.so and has an associated header file png.h. Whichever PNG library you have on your platform, you'll need to set the appropriate JPG_INC, JPG_PATH, and JPG_LIB variables, so that the compiler and linker can find it. As before, if these header and library files are in the usual place on your machine, you may not need to set these variables. [Step 8] Note that by default only a few of LAMMPS optional packages are installed. To build LAMMPS with optional packages, see "this section"_#start_3 below, before proceeding to Step 9. [Step 9] That's it. Once you have a correct Makefile.foo, you have installed the optional LAMMPS packages you want to include in your build, and you have pre-built any other needed libraries (e.g. MPI, FFT, package libraries), all you need to do from the src directory is type something like this: make foo or gmake foo :pre You should get the executable lmp_foo when the build is complete. :line [{Errors that can occur when making LAMMPS:}] :link(start_2_3) IMPORTANT NOTE: If an error occurs when building LAMMPS, the compiler or linker will state very explicitly what the problem is. The error message should give you a hint as to which of the steps above has failed, and what you need to do in order to fix it. Building a code with a Makefile is a very logical process. The compiler and linker need to find the appropriate files and those files need to be compatible with LAMMPS source files. When a make fails, there is usually a very simple reason, which you or a local expert will need to fix. Here are two non-obvious errors that can occur: (1) If the make command breaks immediately with errors that indicate it can't find files with a "*" in their names, this can be because your machine's native make doesn't support wildcard expansion in a makefile. Try gmake instead of make. If that doesn't work, try using a -f switch with your make command to use a pre-generated Makefile.list which explicitly lists all the needed files, e.g. make makelist make -f Makefile.list linux gmake -f Makefile.list mac :pre The first "make" command will create a current Makefile.list with all the file names in your src dir. The 2nd "make" command (make or gmake) will use it to build LAMMPS. Note that you should include/exclude any desired optional packages before using the "make makelist" command. (2) If you get an error that says something like 'identifier "atoll" is undefined', then your machine does not support "long long" integers. Try using the -DLAMMPS_LONGLONG_TO_LONG setting described above in Step 4. :line [{Additional build tips:}] :link(start_2_4) (1) Building LAMMPS for multiple platforms. You can make LAMMPS for multiple platforms from the same src directory. Each target creates its own object sub-directory called Obj_target where it stores the system-specific *.o files. (2) Cleaning up. Typing "make clean-all" or "make clean-machine" will delete *.o object files created when LAMMPS is built, for either all builds or for a particular machine. (3) Changing the LAMMPS size limits via -DLAMMPS_SMALLBIG or -DLAMMPS_BIBIG or -DLAMMPS_SMALLSMALL As explained above, any of these 3 settings can be specified on the LMP_INC line in your low-level src/MAKE/Makefile.foo. The default is -DLAMMPS_SMALLBIG which allows for systems with up to 2^63 atoms and timesteps (about 9 billion billion). The atom limit is for atomic systems that do not require atom IDs. For molecular models, which require atom IDs, the limit is 2^31 atoms (about 2 billion). With this setting, image flags are stored in 32-bit integers, which means for 3 dimensions that atoms can only wrap around a periodic box at most 512 times. If atoms move through the periodic box more than this limit, the image flags will "roll over", e.g. from 511 to -512, which can cause diagnostics like the mean-squared displacement, as calculated by the "compute msd"_compute_msd.html command, to be faulty. To allow for larger molecular systems or larger image flags, compile with -DLAMMPS_BIGBIG. This enables molecular systems with up to 2^63 atoms (about 9 billion billion). And image flags will not "roll over" until they reach 2^20 = 1048576. IMPORTANT NOTE: As of 6/2012, the BIGBIG setting does not yet enable molecular systems to grow as large as 2^63. Only the image flag roll over is currently affected by this compile option. If your system does not support 8-byte integers, you will need to compile with the -DLAMMPS_SMALLSMALL setting. This will restrict your total number of atoms (for atomic or molecular models) and timesteps to 2^31 (about 2 billion). Image flags will roll over at 2^9 = 512. Note that in src/lmptype.h there are also settings for the MPI data types associated with the integers that store atom IDs and total system sizes. These need to be consistent with the associated C data types, or else LAMMPS will generate a run-time error. In all cases, the size of problem that can be run on a per-processor basis is limited by 4-byte integer storage to 2^31 atoms per processor (about 2 billion). This should not normally be a restriction since such a problem would have a huge per-processor memory footprint due to neighbor lists and would run very slowly in terms of CPU secs/timestep. :line [{Building for a Mac:}] :link(start_2_5) OS X is BSD Unix, so it should just work. See the src/MAKE/Makefile.mac file. :line [{Building for Windows:}] :link(start_2_6) The LAMMPS download page has an option to download both a serial and parallel pre-built Windows exeutable. See the "Running LAMMPS"_#start_6 section for instructions for running these executables on a Windows box. The pre-built executables are built with a subset of the available pacakges; see the download page for the list. If you want a Windows version with specific packages included and excluded, you can build it yourself. One way to do this is install and use cygwin to build LAMMPS with a standard Linus make, just as you would on any Linux box; see src/MAKE/Makefile.cygwin. The other way to do this is using Visual Studio and project files. See the src/WINDOWS directory and its README.txt file for instructions on both a basic build and a customized build with pacakges you select. :line 2.3 Making LAMMPS with optional packages :h4,link(start_3) This section has the following sub-sections: "Package basics"_#start_3_1 "Including/excluding packages"_#start_3_2 "Packages that require extra libraries"_#start_3_3 "Additional Makefile settings for extra libraries"_#start_3_4 :ul :line [{Package basics:}] :link(start_3_1) The source code for LAMMPS is structured as a set of core files which are always included, plus optional packages. Packages are groups of files that enable a specific set of features. For example, force fields for molecular systems or granular systems are in packages. You can see the list of all packages by typing "make package" from within the src directory of the LAMMPS distribution. If you use a command in a LAMMPS input script that is specific to a particular package, you must have built LAMMPS with that package, else you will get an error that the style is invalid or the command is unknown. Every command's doc page specfies if it is part of a package. You can also type lmp_machine -h :pre to run your executable with the optional "-h command-line switch"_#start_7 for "help", which will list the styles and commands known to your executable. There are two kinds of packages in LAMMPS, standard and user packages. More information about the contents of standard and user packages is given in "Section_packages"_Section_packages.html of the manual. The difference between standard and user packages is as follows: Standard packages are supported by the LAMMPS developers and are written in a syntax and style consistent with the rest of LAMMPS. This means we will answer questions about them, debug and fix them if necessary, and keep them compatible with future changes to LAMMPS. User packages have been contributed by users, and always begin with the user prefix. If they are a single command (single file), they are typically in the user-misc package. Otherwise, they are a a set of files grouped together which add a specific functionality to the code. User packages don't necessarily meet the requirements of the standard packages. If you have problems using a feature provided in a user package, you will likely need to contact the contributor directly to get help. Information on how to submit additions you make to LAMMPS as a user-contributed package is given in "this section"_Section_modify.html#mod_15 of the documentation. Some packages (both standard and user) require additional libraries. See more details below. :line [{Including/excluding packages:}] :link(start_3_2) To use or not use a package you must include or exclude it before building LAMMPS. From the src directory, this is typically as simple as: make yes-colloid make g++ :pre or make no-manybody make g++ :pre IMPORTANT NOTE: You should NOT include/exclude packages and build LAMMPS in a single make command by using multiple targets, e.g. make yes-colloid g++. This is because the make procedure creates a list of source files that will be out-of-date for the build if the package configuration changes during the same command. Some packages have individual files that depend on other packages being included. LAMMPS checks for this and does the right thing. I.e. individual files are only included if their dependencies are already included. Likewise, if a package is excluded, other files dependent on that package are also excluded. The reason to exclude packages is if you will never run certain kinds of simulations. For some packages, this will keep you from having to build auxiliary libraries (see below), and will also produce a smaller executable which may run a bit faster. When you download a LAMMPS tarball, these packages are pre-installed in the src directory: KSPACE, MANYBODY,MOLECULE. When you download LAMMPS source files from the SVN or Git repositories, no packages are pre-installed. Packages are included or excluded by typing "make yes-name" or "make no-name", where "name" is the name of the package in lower-case, e.g. name = kspace for the KSPACE package or name = user-atc for the USER-ATC package. You can also type "make yes-standard", "make no-standard", "make yes-user", "make no-user", "make yes-all" or "make no-all" to include/exclude various sets of packages. Type "make package" to see the all of the package-related make options. IMPORTANT NOTE: Inclusion/exclusion of a package works by simply moving files back and forth between the main src directory and sub-directories with the package name (e.g. src/KSPACE, src/USER-ATC), so that the files are seen or not seen when LAMMPS is built. After you have included or excluded a package, you must re-build LAMMPS. Additional package-related make options exist to help manage LAMMPS files that exist in both the src directory and in package sub-directories. You do not normally need to use these commands unless you are editing LAMMPS files or have downloaded a patch from the LAMMPS WWW site. Typing "make package-update" will overwrite src files with files from the package sub-directories if the package has been included. It should be used after a patch is installed, since patches only update the files in the package sub-directory, but not the src files. Typing "make package-overwrite" will overwrite files in the package sub-directories with src files. Typing "make package-status" will show which packages are currently included. Of those that are included, it will list files that are different in the src directory and package sub-directory. Typing "make package-diff" lists all differences between these files. Again, type "make package" to see all of the package-related make options. :line [{Packages that require extra libraries:}] :link(start_3_3) A few of the standard and user packages require additional auxiliary libraries. They must be compiled first, before LAMMPS is built. If you get a LAMMPS build error about a missing library, this is likely the reason. See the "Section_packages"_Section_packages.html doc page for a list of packages that have auxiliary libraries. Code for some of these auxiliary libraries is included in the LAMMPS distribution under the lib directory. Examples are the USER-ATC and MEAM packages. Some auxiliary libraries are not included with LAMMPS; to use the associated package you must download and install the auxiliary library yourself. Examples are the KIM and VORONOI and USER-MOLFILE packages. For libraries with provided source code, each lib directory has a README file (e.g. lib/reax/README) with instructions on how to build that library. Typically this is done by typing something like: make -f Makefile.g++ :pre If one of the provided Makefiles is not appropriate for your system you will need to edit or add one. Note that all the Makefiles have a setting for EXTRAMAKE at the top that names a Makefile.lammps.* file. If successful, this will produce 2 files in the lib directory: libpackage.a Makefile.lammps :pre The Makefile.lammps file is a copy of the EXTRAMAKE file specified in the Makefile you used. You MUST insure that the settings in Makefile.lammps are appropriate for your system. If they are not, the LAMMPS build will fail. As explained in the lib/package/README files, they are used to specify additional system libraries and their locations so that LAMMPS can build with the auxiliary library. For example, if the MEAM or REAX packages are used, the auxiliary libraries consist of F90 code, build with a F90 complier. To link that library with LAMMPS (a C++ code) via whatever C++ compiler LAMMPS is built with, typically requires additional Fortran-to-C libraries be included in the link. Another example are the BLAS and LAPACK libraries needed to use the USER-ATC or USER-AWPMD packages. For libraries without provided source code, see the src/package/Makefile.lammps file for information on where to find the library and how to build it. E.g. the file src/KIM/Makefile.lammps. This file serves the same purpose as the lib/package/Makefile.lammps file described above. It has settings needed when LAMMPS is built to link with the auxiliary library. Again, you MUST insure that the settings in src/package/Makefile.lammps are appropriate for your system and where you installed the auxiliary library. If they are not, the LAMMPS build will fail. :line 2.4 Building LAMMPS via the Make.py script :h4,link(start_4) The src directory includes a Make.py script, written in Python, which can be used to automate various steps of the build process. You can run the script from the src directory by typing either: Make.py python Make.py :pre which will give you info about the tool. For the former to work, you may need to edit the 1st line of the script to point to your local Python. And you may need to insure the script is executable: chmod +x Make.py :pre The following options are supported as switches: -i file1 file2 ... -p package1 package2 ... -u package1 package2 ... -e package1 arg1 arg2 package2 ... -o dir -b machine -s suffix1 suffix2 ... -l dir -j N -h switch1 switch2 ... :ul Help on any switch can be listed by using -h, e.g. Make.py -h -i -p :pre At a hi-level, these are the kinds of package management and build tasks that can be performed easily, using the Make.py tool: install/uninstall packages and build the associated external libs (use -p and -u and -e) install packages needed for one or more input scripts (use -i and -p) build LAMMPS, either in the src dir or new dir (use -b) create a new dir with only the source code needed for one or more input scripts (use -i and -o) :ul The last bullet can be useful when you wish to build a stripped-down version of LAMMPS to run a specific script(s). Or when you wish to move the minimal amount of files to another platform for a remote LAMMPS build. Note that using Make.py is not a substitute for insuring you have a valid src/MAKE/Makefile.foo for your system, or that external library Makefiles in any lib/* directories you use are also valid for your system. But once you have done that, you can use Make.py to quickly include/exclude the packages and external libraries needed by your input scripts. :line 2.5 Building LAMMPS as a library :h4,link(start_5) LAMMPS can be built as either a static or shared library, which can then be called from another application or a scripting language. See "this section"_Section_howto.html#howto_10 for more info on coupling LAMMPS to other codes. See "this section"_Section_python.html for more info on wrapping and running LAMMPS from Python. [Static library:] :h5 To build LAMMPS as a static library (*.a file on Linux), type make makelib make -f Makefile.lib foo :pre where foo is the machine name. This kind of library is typically used to statically link a driver application to LAMMPS, so that you can insure all dependencies are satisfied at compile time. Note that inclusion or exclusion of any desired optional packages should be done before typing "make makelib". The first "make" command will create a current Makefile.lib with all the file names in your src dir. The second "make" command will use it to build LAMMPS as a static library, using the ARCHIVE and ARFLAGS settings in src/MAKE/Makefile.foo. The build will create the file liblammps_foo.a which another application can link to. [Shared library:] :h5 To build LAMMPS as a shared library (*.so file on Linux), which can be dynamically loaded, e.g. from Python, type make makeshlib make -f Makefile.shlib foo :pre where foo is the machine name. This kind of library is required when wrapping LAMMPS with Python; see "Section_python"_Section_python.html for details. Again, note that inclusion or exclusion of any desired optional packages should be done before typing "make makelib". The first "make" command will create a current Makefile.shlib with all the file names in your src dir. The second "make" command will use it to build LAMMPS as a shared library, using the SHFLAGS and SHLIBFLAGS settings in src/MAKE/Makefile.foo. The build will create the file liblammps_foo.so which another application can link to dyamically. It will also create a soft link liblammps.so, which the Python wrapper uses by default. Note that for a shared library to be usable by a calling program, all the auxiliary libraries it depends on must also exist as shared libraries. This will be the case for libraries included with LAMMPS, such as the dummy MPI library in src/STUBS or any package libraries in lib/packges, since they are always built as shared libraries with the -fPIC switch. However, if a library like MPI or FFTW does not exist as a shared library, the second make command will generate an error. This means you will need to install a shared library version of the package. The build instructions for the library should tell you how to do this. As an example, here is how to build and install the "MPICH library"_mpich, a popular open-source version of MPI, distributed by Argonne National Labs, as a shared library in the default /usr/local/lib location: :link(mpich,http://www-unix.mcs.anl.gov/mpi) ./configure --enable-shared make make install :pre You may need to use "sudo make install" in place of the last line if you do not have write privileges for /usr/local/lib. The end result should be the file /usr/local/lib/libmpich.so. [Additional requirement for using a shared library:] :h5 The operating system finds shared libraries to load at run-time using the environment variable LD_LIBRARY_PATH. So you may wish to copy the file src/liblammps.so or src/liblammps_g++.so (for example) to a place the system can find it by default, such as /usr/local/lib, or you may wish to add the LAMMPS src directory to LD_LIBRARY_PATH, so that the current version of the shared library is always available to programs that use it. For the csh or tcsh shells, you would add something like this to your ~/.cshrc file: setenv LD_LIBRARY_PATH ${LD_LIBRARY_PATH}:/home/sjplimp/lammps/src :pre [Calling the LAMMPS library:] :h5 Either flavor of library (static or shared0 allows one or more LAMMPS objects to be instantiated from the calling program. When used from a C++ program, all of LAMMPS is wrapped in a LAMMPS_NS namespace; you can safely use any of its classes and methods from within the calling code, as needed. When used from a C or Fortran program or a scripting language like Python, the library has a simple function-style interface, provided in src/library.cpp and src/library.h. See the sample codes in examples/COUPLE/simple for examples of C++ and C and Fortran codes that invoke LAMMPS thru its library interface. There are other examples as well in the COUPLE directory which are discussed in "Section_howto 10"_Section_howto.html#howto_10 of the manual. See "Section_python"_Section_python.html of the manual for a description of the Python wrapper provided with LAMMPS that operates through the LAMMPS library interface. The files src/library.cpp and library.h define the C-style API for using LAMMPS as a library. See "Section_howto 19"_Section_howto.html#howto_19 of the manual for a description of the interface and how to extend it for your needs. :line 2.6 Running LAMMPS :h4,link(start_6) By default, LAMMPS runs by reading commands from stdin; e.g. lmp_linux < in.file. This means you first create an input script (e.g. in.file) containing the desired commands. "This section"_Section_commands.html describes how input scripts are structured and what commands they contain. You can test LAMMPS on any of the sample inputs provided in the examples or bench directory. Input scripts are named in.* and sample outputs are named log.*.name.P where name is a machine and P is the number of processors it was run on. Here is how you might run a standard Lennard-Jones benchmark on a Linux box, using mpirun to launch a parallel job: cd src make linux cp lmp_linux ../bench cd ../bench mpirun -np 4 lmp_linux < in.lj :pre See "this page"_bench for timings for this and the other benchmarks on various platforms. :link(bench,http://lammps.sandia.gov/bench.html) :line On a Windows box, you can skip making LAMMPS and simply download an executable, as described above, though the pre-packaged executables include only certain packages. To run a LAMMPS executable on a Windows machine, first decide whether you want to download the non-MPI (serial) or the MPI (parallel) version of the executable. Download and save the version you have chosen. For the non-MPI version, follow these steps: Get a command prompt by going to Start->Run... , then typing "cmd". :ulb,l Move to the directory where you have saved lmp_win_no-mpi.exe (e.g. by typing: cd "Documents"). :l At the command prompt, type "lmp_win_no-mpi -in in.lj", replacing in.lj with the name of your LAMMPS input script. :l,ule For the MPI version, which allows you to run LAMMPS under Windows on multiple processors, follow these steps: Download and install "MPICH2"_http://www.mcs.anl.gov/research/projects/mpich2/downloads/index.php?s=downloads for Windows. :ulb,l You'll need to use the mpiexec.exe and smpd.exe files from the MPICH2 package. Put them in same directory (or path) as the LAMMPS Windows executable. :l Get a command prompt by going to Start->Run... , then typing "cmd". :l Move to the directory where you have saved lmp_win_mpi.exe (e.g. by typing: cd "Documents"). :l Then type something like this: "mpiexec -np 4 -localonly lmp_win_mpi -in in.lj", replacing in.lj with the name of your LAMMPS input script. :l Note that you may need to provide smpd with a passphrase --- it doesn't matter what you type. :l In this mode, output may not immediately show up on the screen, so if your input script takes a long time to execute, you may need to be patient before the output shows up. :l Alternatively, you can still use this executable to run on a single processor by typing something like: "lmp_win_mpi -in in.lj". :l,ule :line The screen output from LAMMPS is described in the next section. As it runs, LAMMPS also writes a log.lammps file with the same information. Note that this sequence of commands copies the LAMMPS executable (lmp_linux) to the directory with the input files. This may not be necessary, but some versions of MPI reset the working directory to where the executable is, rather than leave it as the directory where you launch mpirun from (if you launch lmp_linux on its own and not under mpirun). If that happens, LAMMPS will look for additional input files and write its output files to the executable directory, rather than your working directory, which is probably not what you want. If LAMMPS encounters errors in the input script or while running a simulation it will print an ERROR message and stop or a WARNING message and continue. See "Section_errors"_Section_errors.html for a discussion of the various kinds of errors LAMMPS can or can't detect, a list of all ERROR and WARNING messages, and what to do about them. LAMMPS can run a problem on any number of processors, including a single processor. In theory you should get identical answers on any number of processors and on any machine. In practice, numerical round-off can cause slight differences and eventual divergence of molecular dynamics phase space trajectories. LAMMPS can run as large a problem as will fit in the physical memory of one or more processors. If you run out of memory, you must run on more processors or setup a smaller problem. :line 2.7 Command-line options :h4,link(start_7) At run time, LAMMPS recognizes several optional command-line switches which may be used in any order. Either the full word or a one-or-two letter abbreviation can be used: -c or -cuda -e or -echo -i or -in -h or -help -l or -log -nc or -nocite -p or -partition -pl or -plog -ps or -pscreen -r or -reorder -sc or -screen -sf or -suffix -v or -var :ul For example, lmp_ibm might be launched as follows: mpirun -np 16 lmp_ibm -v f tmp.out -l my.log -sc none < in.alloy mpirun -np 16 lmp_ibm -var f tmp.out -log my.log -screen none < in.alloy :pre Here are the details on the options: -cuda on/off :pre Explicitly enable or disable CUDA support, as provided by the USER-CUDA package. If LAMMPS is built with this package, as described above in "Section 2.3"_#start_3, then by default LAMMPS will run in CUDA mode. If this switch is set to "off", then it will not, even if it was built with the USER-CUDA package, which means you can run standard LAMMPS or with the GPU package for testing or benchmarking purposes. The only reason to set the switch to "on", is to check if LAMMPS was built with the USER-CUDA package, since an error will be generated if it was not. -echo style :pre Set the style of command echoing. The style can be {none} or {screen} or {log} or {both}. Depending on the style, each command read from the input script will be echoed to the screen and/or logfile. This can be useful to figure out which line of your script is causing an input error. The default value is {log}. The echo style can also be set by using the "echo"_echo.html command in the input script itself. -in file :pre Specify a file to use as an input script. This is an optional switch when running LAMMPS in one-partition mode. If it is not specified, LAMMPS reads its input script from stdin - e.g. lmp_linux < in.run. This is a required switch when running LAMMPS in multi-partition mode, since multiple processors cannot all read from stdin. -help :pre Print a list of options compiled into this executable for each LAMMPS style (atom_style, fix, compute, pair_style, bond_style, etc). This can help you know if the command you want to use was included via the appropriate package. LAMMPS will print the info and immediately exit if this switch is used. -log file :pre Specify a log file for LAMMPS to write status information to. In one-partition mode, if the switch is not used, LAMMPS writes to the file log.lammps. If this switch is used, LAMMPS writes to the specified file. In multi-partition mode, if the switch is not used, a log.lammps file is created with hi-level status information. Each partition also writes to a log.lammps.N file where N is the partition ID. If the switch is specified in multi-partition mode, the hi-level logfile is named "file" and each partition also logs information to a file.N. For both one-partition and multi-partition mode, if the specified file is "none", then no log files are created. Using a "log"_log.html command in the input script will override this setting. Option -plog will override the name of the partition log files file.N. -nocite :pre Disable writing the log.cite file which is normally written to list references for specific cite-able features used during a LAMMPS run. See the "citation page"_http://lammps.sandia.gov/cite.html for more details. -partition 8x2 4 5 ... :pre Invoke LAMMPS in multi-partition mode. When LAMMPS is run on P processors and this switch is not used, LAMMPS runs in one partition, i.e. all P processors run a single simulation. If this switch is used, the P processors are split into separate partitions and each partition runs its own simulation. The arguments to the switch specify the number of processors in each partition. Arguments of the form MxN mean M partitions, each with N processors. Arguments of the form N mean a single partition with N processors. The sum of processors in all partitions must equal P. Thus the command "-partition 8x2 4 5" has 10 partitions and runs on a total of 25 processors. Running with multiple partitions can e useful for running "multi-replica simulations"_Section_howto.html#howto_5, where each replica runs on on one or a few processors. Note that with MPI installed on a machine (e.g. your desktop), you can run on more (virtual) processors than you have physical processors. To run multiple independent simulatoins from one input script, using multiple partitions, see "Section_howto 4"_Section_howto.html#howto_4 of the manual. World- and universe-style "variables"_variable.html are useful in this context. -plog file :pre Specify the base name for the partition log files, so partition N writes log information to file.N. If file is none, then no partition log files are created. This overrides the filename specified in the -log command-line option. This option is useful when working with large numbers of partitions, allowing the partition log files to be suppressed (-plog none) or placed in a sub-directory (-plog replica_files/log.lammps) If this option is not used the log file for partition N is log.lammps.N or whatever is specified by the -log command-line option. -pscreen file :pre Specify the base name for the partition screen file, so partition N writes screen information to file.N. If file is none, then no partition screen files are created. This overrides the filename specified in the -screen command-line option. This option is useful when working with large numbers of partitions, allowing the partition screen files to be suppressed (-pscreen none) or placed in a sub-directory (-pscreen replica_files/screen). If this option is not used the screen file for partition N is screen.N or whatever is specified by the -screen command-line option. -reorder nth N -reorder custom filename :pre Reorder the processors in the MPI communicator used to instantiate LAMMPS, in one of several ways. The original MPI communicator ranks all P processors from 0 to P-1. The mapping of these ranks to physical processors is done by MPI before LAMMPS begins. It may be useful in some cases to alter the rank order. E.g. to insure that cores within each node are ranked in a desired order. Or when using the "run_style verlet/split"_run_style.html command with 2 partitions to insure that a specific Kspace processor (in the 2nd partition) is matched up with a specific set of processors in the 1st partition. See the "Section_accelerate"_Section_accelerate.html doc pages for more details. If the keyword {nth} is used with a setting {N}, then it means every Nth processor will be moved to the end of the ranking. This is useful when using the "run_style verlet/split"_run_style.html command with 2 partitions via the -partition command-line switch. The first set of processors will be in the first partition, the 2nd set in the 2nd partition. The -reorder command-line switch can alter this so that the 1st N procs in the 1st partition and one proc in the 2nd partition will be ordered consecutively, e.g. as the cores on one physical node. This can boost performance. For example, if you use "-reorder nth 4" and "-partition 9 3" and you are running on 12 processors, the processors will be reordered from 0 1 2 3 4 5 6 7 8 9 10 11 :pre to 0 1 2 4 5 6 8 9 10 3 7 11 :pre so that the processors in each partition will be 0 1 2 4 5 6 8 9 10 3 7 11 :pre See the "processors" command for how to insure processors from each partition could then be grouped optimally for quad-core nodes. If the keyword is {custom}, then a file that specifies a permutation of the processor ranks is also specified. The format of the reorder file is as follows. Any number of initial blank or comment lines (starting with a "#" character) can be present. These should be followed by P lines of the form: I J :pre where P is the number of processors LAMMPS was launched with. Note that if running in multi-partition mode (see the -partition switch above) P is the total number of processors in all partitions. The I and J values describe a permutation of the P processors. Every I and J should be values from 0 to P-1 inclusive. In the set of P I values, every proc ID should appear exactly once. Ditto for the set of P J values. A single I,J pairing means that the physical processor with rank I in the original MPI communicator will have rank J in the reordered communicator. Note that rank ordering can also be specified by many MPI implementations, either by environment variables that specify how to order physical processors, or by config files that specify what physical processors to assign to each MPI rank. The -reorder switch simply gives you a portable way to do this without relying on MPI itself. See the "processors out"_processors command for how to output info on the final assignment of physical processors to the LAMMPS simulation domain. -screen file :pre Specify a file for LAMMPS to write its screen information to. In one-partition mode, if the switch is not used, LAMMPS writes to the screen. If this switch is used, LAMMPS writes to the specified file instead and you will see no screen output. In multi-partition mode, if the switch is not used, hi-level status information is written to the screen. Each partition also writes to a screen.N file where N is the partition ID. If the switch is specified in multi-partition mode, the hi-level screen dump is named "file" and each partition also writes screen information to a file.N. For both one-partition and multi-partition mode, if the specified file is "none", then no screen output is performed. Option -pscreen will override the name of the partition screen files file.N. -suffix style :pre Use variants of various styles if they exist. The specified style can be {opt}, {omp}, {gpu}, or {cuda}. These refer to optional packages that LAMMPS can be built with, as described above in "Section 2.3"_#start_3. The "opt" style corrsponds to the OPT package, the "omp" style to the USER-OMP package, the "gpu" style to the GPU package, and the "cuda" style to the USER-CUDA package. As an example, all of the packages provide a "pair_style lj/cut"_pair_lj.html variant, with style names lj/cut/opt, lj/cut/omp, lj/cut/gpu, or lj/cut/cuda. A variant styles can be specified explicitly in your input script, e.g. pair_style lj/cut/gpu. If the -suffix switch is used, you do not need to modify your input script. The specified suffix (opt,omp,gpu,cuda) is automatically appended whenever your input script command creates a new "atom"_atom_style.html, "pair"_pair_style.html, "fix"_fix.html, "compute"_compute.html, or "run"_run_style.html style. If the variant version does not exist, the standard version is created. For the GPU package, using this command-line switch also invokes the default GPU settings, as if the command "package gpu force/neigh 0 0 1" were used at the top of your input script. These settings can be changed by using the "package gpu"_package.html command in your script if desired. For the OMP package, using this command-line switch also invokes the default OMP settings, as if the command "package omp *" were used at the top of your input script. These settings can be changed by using the "package omp"_package.html command in your script if desired. The "suffix"_suffix.html command can also set a suffix and it can also turn off/on any suffix setting made via the command line. -var name value1 value2 ... :pre Specify a variable that will be defined for substitution purposes when the input script is read. "Name" is the variable name which can be a single character (referenced as $x in the input script) or a full string (referenced as $\{abc\}). An "index-style variable"_variable.html will be created and populated with the subsequent values, e.g. a set of filenames. Using this command-line option is equivalent to putting the line "variable name index value1 value2 ..." at the beginning of the input script. Defining an index variable as a command-line argument overrides any setting for the same index variable in the input script, since index variables cannot be re-defined. See the "variable"_variable.html command for more info on defining index and other kinds of variables and "this section"_Section_commands.html#cmd_2 for more info on using variables in input scripts. NOTE: Currently, the command-line parser looks for arguments that start with "-" to indicate new switches. Thus you cannot specify multiple variable values if any of they start with a "-", e.g. a negative numeric value. It is OK if the first value1 starts with a "-", since it is automatically skipped. :line 2.8 LAMMPS screen output :h4,link(start_8) As LAMMPS reads an input script, it prints information to both the screen and a log file about significant actions it takes to setup a simulation. When the simulation is ready to begin, LAMMPS performs various initializations and prints the amount of memory (in MBytes per processor) that the simulation requires. It also prints details of the initial thermodynamic state of the system. During the run itself, thermodynamic information is printed periodically, every few timesteps. When the run concludes, LAMMPS prints the final thermodynamic state and a total run time for the simulation. It then appends statistics about the CPU time and storage requirements for the simulation. An example set of statistics is shown here: Loop time of 49.002 on 2 procs for 2004 atoms :pre Pair time (%) = 35.0495 (71.5267) Bond time (%) = 0.092046 (0.187841) Kspce time (%) = 6.42073 (13.103) Neigh time (%) = 2.73485 (5.5811) Comm time (%) = 1.50291 (3.06703) Outpt time (%) = 0.013799 (0.0281601) Other time (%) = 2.13669 (4.36041) :pre Nlocal: 1002 ave, 1015 max, 989 min Histogram: 1 0 0 0 0 0 0 0 0 1 Nghost: 8720 ave, 8724 max, 8716 min Histogram: 1 0 0 0 0 0 0 0 0 1 Neighs: 354141 ave, 361422 max, 346860 min Histogram: 1 0 0 0 0 0 0 0 0 1 :pre Total # of neighbors = 708282 Ave neighs/atom = 353.434 Ave special neighs/atom = 2.34032 Number of reneighborings = 42 Dangerous reneighborings = 2 :pre The first section gives the breakdown of the CPU run time (in seconds) into major categories. The second section lists the number of owned atoms (Nlocal), ghost atoms (Nghost), and pair-wise neighbors stored per processor. The max and min values give the spread of these values across processors with a 10-bin histogram showing the distribution. The total number of histogram counts is equal to the number of processors. The last section gives aggregate statistics for pair-wise neighbors and special neighbors that LAMMPS keeps track of (see the "special_bonds"_special_bonds.html command). The number of times neighbor lists were rebuilt during the run is given as well as the number of potentially "dangerous" rebuilds. If atom movement triggered neighbor list rebuilding (see the "neigh_modify"_neigh_modify.html command), then dangerous reneighborings are those that were triggered on the first timestep atom movement was checked for. If this count is non-zero you may wish to reduce the delay factor to insure no force interactions are missed by atoms moving beyond the neighbor skin distance before a rebuild takes place. If an energy minimization was performed via the "minimize"_minimize.html command, additional information is printed, e.g. Minimization stats: E initial, next-to-last, final = -0.895962 -2.94193 -2.94342 Gradient 2-norm init/final= 1920.78 20.9992 Gradient inf-norm init/final= 304.283 9.61216 Iterations = 36 Force evaluations = 177 :pre The first line lists the initial and final energy, as well as the energy on the next-to-last iteration. The next 2 lines give a measure of the gradient of the energy (force on all atoms). The 2-norm is the "length" of this force vector; the inf-norm is the largest component. The last 2 lines are statistics on how many iterations and force-evaluations the minimizer required. Multiple force evaluations are typically done at each iteration to perform a 1d line minimization in the search direction. If a "kspace_style"_kspace_style.html long-range Coulombics solve was performed during the run (PPPM, Ewald), then additional information is printed, e.g. FFT time (% of Kspce) = 0.200313 (8.34477) FFT Gflps 3d 1d-only = 2.31074 9.19989 :pre The first line gives the time spent doing 3d FFTs (4 per timestep) and the fraction it represents of the total KSpace time (listed above). Each 3d FFT requires computation (3 sets of 1d FFTs) and communication (transposes). The total flops performed is 5Nlog_2(N), where N is the number of points in the 3d grid. The FFTs are timed with and without the communication and a Gflop rate is computed. The 3d rate is with communication; the 1d rate is without (just the 1d FFTs). Thus you can estimate what fraction of your FFT time was spent in communication, roughly 75% in the example above. :line 2.9 Tips for users of previous LAMMPS versions :h4,link(start_9) The current C++ began with a complete rewrite of LAMMPS 2001, which was written in F90. Features of earlier versions of LAMMPS are listed in "Section_history"_Section_history.html. The F90 and F77 versions (2001 and 99) are also freely distributed as open-source codes; check the "LAMMPS WWW Site"_lws for distribution information if you prefer those versions. The 99 and 2001 versions are no longer under active development; they do not have all the features of C++ LAMMPS. If you are a previous user of LAMMPS 2001, these are the most significant changes you will notice in C++ LAMMPS: (1) The names and arguments of many input script commands have changed. All commands are now a single word (e.g. read_data instead of read data). (2) All the functionality of LAMMPS 2001 is included in C++ LAMMPS, but you may need to specify the relevant commands in different ways. (3) The format of the data file can be streamlined for some problems. See the "read_data"_read_data.html command for details. The data file section "Nonbond Coeff" has been renamed to "Pair Coeff" in C++ LAMMPS. (4) Binary restart files written by LAMMPS 2001 cannot be read by C++ LAMMPS with a "read_restart"_read_restart.html command. This is because they were output by F90 which writes in a different binary format than C or C++ writes or reads. Use the {restart2data} tool provided with LAMMPS 2001 to convert the 2001 restart file to a text data file. Then edit the data file as necessary before using the C++ LAMMPS "read_data"_read_data.html command to read it in. (5) There are numerous small numerical changes in C++ LAMMPS that mean you will not get identical answers when comparing to a 2001 run. However, your initial thermodynamic energy and MD trajectory should be close if you have setup the problem for both codes the same. diff --git a/doc/dump.html b/doc/dump.html index eb83e900a..3d2e4f4a2 100644 --- a/doc/dump.html +++ b/doc/dump.html @@ -1,572 +1,572 @@
LAMMPS WWW Site - LAMMPS Documentation - LAMMPS Commands

dump command

dump image command

dump molfile command

Syntax:

dump ID group-ID style N file args 
 

Examples:

dump myDump all atom 100 dump.atom
 dump 2 subgroup atom 50 dump.run.bin
 dump 4a all custom 100 dump.myforce.* id type x y vx fx
 dump 4b flow custom 100 dump.%.myforce id type c_myF[3] v_ke
-dump 2 inner cfg 10 dump.snap.*.cfg id type xs ys zs vx vy vz
-dump snap all cfg 100 dump.config.*.cfg id type xs ys zs id type c_Stress2
+dump 2 inner cfg 10 dump.snap.*.cfg mass type xs ys zs vx vy vz
+dump snap all cfg 100 dump.config.*.cfg mass type xs ys zs id type c_Stress2
 dump 1 all xtc 1000 file.xtc
 dump e_data all custom 100 dump.eff id type x y z spin eradius fx fy fz eforce 
 

Description:

Dump a snapshot of atom quantities to one or more files every N timesteps in one of several styles. The image style is the exception; it creates a JPG or PPM image file of the atom configuration every N timesteps, as discussed on the dump image doc page. The timesteps on which dump output is written can also be controlled by a variable. See the dump_modify every command.

Only information for atoms in the specified group is dumped. The dump_modify thresh and region commands can also alter what atoms are included. Not all styles support all these options; see details below.

As described below, the filename determines the kind of output (text or binary or gzipped, one big file or one per timestep, one big file or one per processor).

IMPORTANT NOTE: Because periodic boundary conditions are enforced only on timesteps when neighbor lists are rebuilt, the coordinates of an atom written to a dump file may be slightly outside the simulation box.

IMPORTANT NOTE: Unless the dump_modify sort option is invoked, the lines of atom information written to dump files (typically one line per atom) will be in an indeterminate order for each snapshot. This is even true when running on a single processor, if the atom_modify sort option is on, which it is by default. In this case atoms are re-ordered periodically during a simulation, due to spatial sorting. It is also true when running in parallel, because data for a single snapshot is collected from multiple processors.

For the atom, custom, cfg, and local styles, sorting is off by default. For the dcd, xtc, xyz, and molfile styles, sorting by atom ID is on by default. See the dump_modify doc page for details.


The style keyword determines what atom quantities are written to the file and in what format. Settings made via the dump_modify command can also alter the format of individual values and the file itself.

The atom, local, and custom styles create files in a simple text format that is self-explanatory when viewing a dump file. Many of the LAMMPS post-processing tools, including Pizza.py, work with this format, as does the rerun command.

For post-processing purposes the atom, local, and custom text files are self-describing in the following sense.

The dimensions of the simulation box are included in each snapshot. For an orthogonal simulation box this information is is formatted as:

ITEM: BOX BOUNDS xx yy zz
 xlo xhi
 ylo yhi
 zlo zhi 
 

where xlo,xhi are the maximum extents of the simulation box in the x-dimension, and similarly for y and z. The "xx yy zz" represent 6 characters that encode the style of boundary for each of the 6 simulation box boundaries (xlo,xhi and ylo,yhi and zlo,zhi). Each of the 6 characters is either p = periodic, f = fixed, s = shrink wrap, or m = shrink wrapped with a minimum value. See the boundary command for details.

For triclinic simulation boxes (non-orthogonal), an orthogonal bounding box which encloses the triclinic simulation box is output, along with the 3 tilt factors (xy, xz, yz) of the triclinic box, formatted as follows:

ITEM: BOX BOUNDS xy xz yz xx yy zz 
 xlo_bound xhi_bound xy
 ylo_bound yhi_bound xz
 zlo_bound zhi_bound yz 
 

The presence of the text "xy xz yz" in the ITEM line indicates that the 3 tilt factors will be included on each of the 3 following lines. This bounding box is convenient for many visualization programs. The meaning of the 6 character flags for "xx yy zz" is the same as above.

Note that the first two numbers on each line are now xlo_bound instead of xlo, etc, since they repesent a bounding box. See this section of the doc pages for a geometric description of triclinic boxes, as defined by LAMMPS, simple formulas for how the 6 bounding box extents (xlo_bound,xhi_bound,etc) are calculated from the triclinic parameters, and how to transform those parameters to and from other commonly used triclinic representations.

The "ITEM: ATOMS" line in each snapshot lists column descriptors for the per-atom lines that follow. For example, the descriptors would be "id type xs ys zs" for the default atom style, and would be the atom attributes you specify in the dump command for the custom style.

For style atom, atom coordinates are written to the file, along with the atom ID and atom type. By default, atom coords are written in a scaled format (from 0 to 1). I.e. an x value of 0.25 means the atom is at a location 1/4 of the distance from xlo to xhi of the box boundaries. The format can be changed to unscaled coords via the dump_modify settings. Image flags can also be added for each atom via dump_modify.

Style custom allows you to specify a list of atom attributes to be written to the dump file for each atom. Possible attributes are listed above and will appear in the order specified. You cannot specify a quantity that is not defined for a particular simulation - such as q for atom style bond, since that atom style doesn't assign charges. Dumps occur at the very end of a timestep, so atom attributes will include effects due to fixes that are applied during the timestep. An explanation of the possible dump custom attributes is given below.

For style local, local output generated by computes and fixes is used to generate lines of output that is written to the dump file. This local data is typically calculated by each processor based on the atoms it owns, but there may be zero or more entities per atom, e.g. a list of bond distances. An explanation of the possible dump local attributes is given below. Note that by using input from the compute property/local command with dump local, it is possible to generate information on bonds, angles, etc that can be cut and pasted directly into a data file read by the read_data command.

Style cfg has the same command syntax as style custom and writes extended CFG format files, as used by the AtomEye visualization package. Since the extended CFG format uses a single snapshot of the system per file, a wildcard "*" must be included in the filename, as discussed below. The list of atom attributes for style cfg must -begin with either "id type xs ys zs" or "id type xsu ysu zsu" or +begin with either "mass type xs ys zs" or "mass type xsu ysu zsu" since these quantities are needed to -write the CFG files in the appropriate format (though the "id" and +write the CFG files in the appropriate format (though the "mass" and "type" fields do not appear explicitly in the file). Any remaining attributes will be stored as "auxiliary properties" in the CFG files. Note that you will typically want to use the dump_modify element command with CFG-formatted files, to associate element names with atom types, so that AtomEye can render atoms appropriately. When unwrapped coordinates xsu, ysu, and zsu are requested, the nominal AtomEye periodic cell dimensions are expanded by a large factor UNWRAPEXPAND = 10.0, which ensures atoms that are displayed correctly for up to UNWRAPEXPAND/2 periodic boundary crossings in any direction. Beyond this, AtomEye will rewrap the unwrapped coordinates. The expansion causes the atoms to be drawn farther away from the viewer, but it is easy to zoom the atoms closer, and the interatomic distances are unaffected.

The dcd style writes DCD files, a standard atomic trajectory format used by the CHARMM, NAMD, and XPlor molecular dynamics packages. DCD files are binary and thus may not be portable to different machines. The number of atoms per snapshot cannot change with the dcd style. The unwrap option of the dump_modify command allows DCD coordinates to be written "unwrapped" by the image flags for each atom. Unwrapped means that if the atom has passed through a periodic boundary one or more times, the value is printed for what the coordinate would be if it had not been wrapped back into the periodic box. Note that these coordinates may thus be far outside the box size stored with the snapshot.

The xtc style writes XTC files, a compressed trajectory format used by the GROMACS molecular dynamics package, and described here. The precision used in XTC files can be adjusted via the dump_modify command. The default value of 1000 means that coordinates are stored to 1/1000 nanometer accuracy. XTC files are portable binary files written in the NFS XDR data format, so that any machine which supports XDR should be able to read them. The number of atoms per snapshot cannot change with the xtc style. The unwrap option of the dump_modify command allows XTC coordinates to be written "unwrapped" by the image flags for each atom. Unwrapped means that if the atom has passed thru a periodic boundary one or more times, the value is printed for what the coordinate would be if it had not been wrapped back into the periodic box. Note that these coordinates may thus be far outside the box size stored with the snapshot.

The xyz style writes XYZ files, which is a simple text-based coordinate format that many codes can read. Specifically it has a line with the number of atoms, then a comment line that is usually ignored followed by one line per atom with the atom type and the x-, y-, and z-coordinate of that atom. You can use the dump_modify element option to change the output from using the (numerical) atom type to an element name (or some other label). This will help many visualization programs to guess bonds and colors.

Note that atom, custom, dcd, xtc, and xyz style dump files can be read directly by VMD (a popular molecular viewing program). See Section tools of the manual and the tools/lmp2vmd/README.txt file for more information about support in VMD for reading and visualizing LAMMPS dump files.


Dumps are performed on timesteps that are a multiple of N (including timestep 0) and on the last timestep of a minimization if the minimization converges. Note that this means a dump will not be performed on the initial timestep after the dump command is invoked, if the current timestep is not a multiple of N. This behavior can be changed via the dump_modify first command, which can also be useful if the dump command is invoked after a minimization ended on an arbitrary timestep. N can be changed between runs by using the dump_modify every command (not allowed for dcd style). The dump_modify every command also allows a variable to be used to determine the sequence of timesteps on which dump files are written. In this mode a dump on the first timestep of a run will also not be written unless the dump_modify first command is used.

The specified filename determines how the dump file(s) is written. The default is to write one large text file, which is opened when the dump command is invoked and closed when an undump command is used or when LAMMPS exits. For the dcd and xtc styles, this is a single large binary file.

Dump filenames can contain two wildcard characters. If a "*" character appears in the filename, then one file per snapshot is written and the "*" character is replaced with the timestep value. For example, tmp.dump.* becomes tmp.dump.0, tmp.dump.10000, tmp.dump.20000, etc. This option is not available for the dcd and xtc styles. Note that the dump_modify pad command can be used to insure all timestep numbers are the same length (e.g. 00010), which can make it easier to read a series of dump files in order by some post-processing tools.

If a "%" character appears in the filename, then each of P processors writes a portion of the dump file, and the "%" character is replaced with the processor ID from 0 to P-1. For example, tmp.dump.% becomes tmp.dump.0, tmp.dump.1, ... tmp.dump.P-1, etc. This creates smaller files and can be a fast mode of output on parallel machines that support parallel I/O for output. This option is not available for the dcd, xtc, and xyz styles.

By default, P = the number of processors meaning one file per processor, but P can be set to a smaller value via the nfile or fileper keywords of the dump_modify command. These options can be the most efficient way of writing out dump files when running on large numbers of processors.

Note that using the "*" and "%" characters together can produce a large number of small dump files!

If the filename ends with ".bin", the dump file (or files, if "*" or "%" is also used) is written in binary format. A binary dump file will be about the same size as a text version, but will typically write out much faster. Of course, when post-processing, you will need to convert it back to text format (see the binary2txt tool) or write your own code to read the binary file. The format of the binary file can be understood by looking at the tools/binary2txt.cpp file. This option is only available for the atom and custom styles.

If the filename ends with ".gz", the dump file (or files, if "*" or "%" is also used) is written in gzipped format. A gzipped dump file will be about 3x smaller than the text version, but will also take longer to write. This option is not available for the dcd and xtc styles.


This section explains the local attributes that can be specified as part of the local style.

The index attribute can be used to generate an index number from 1 to N for each line written into the dump file, where N is the total number of local datums from all processors, or lines of output that will appear in the snapshot. Note that because data from different processors depend on what atoms they currently own, and atoms migrate between processor, there is no guarantee that the same index will be used for the same info (e.g. a particular bond) in successive snapshots.

The c_ID and c_ID[N] attributes allow local vectors or arrays calculated by a compute to be output. The ID in the attribute should be replaced by the actual ID of the compute that has been defined previously in the input script. See the compute command for details. There are computes for calculating local information such as indices, types, and energies for bonds and angles.

Note that computes which calculate global or per-atom quantities, as opposed to local quantities, cannot be output in a dump local command. Instead, global quantities can be output by the thermo_style custom command, and per-atom quantities can be output by the dump custom command.

If c_ID is used as a attribute, then the local vector calculated by the compute is printed. If c_ID[N] is used, then N must be in the range from 1-M, which will print the Nth column of the M-length local array calculated by the compute.

The f_ID and f_ID[N] attributes allow local vectors or arrays calculated by a fix to be output. The ID in the attribute should be replaced by the actual ID of the fix that has been defined previously in the input script.

If f_ID is used as a attribute, then the local vector calculated by the fix is printed. If f_ID[N] is used, then N must be in the range from 1-M, which will print the Nth column of the M-length local array calculated by the fix.

Here is an example of how to dump bond info for a system, including the distance and energy of each bond:

compute 1 all property/local batom1 batom2 btype 
 compute 2 all bond/local dist eng
 dump 1 all local 1000 tmp.dump index c_1[1] c_1[2] c_1[3] c_2[1] c_2[2] 
 

This section explains the atom attributes that can be specified as part of the custom and cfg styles.

The id, mol, type, element, mass, vx, vy, vz, fx, fy, fz, q attributes are self-explanatory.

Id is the atom ID. Mol is the molecule ID, included in the data file for molecular systems. Type is the atom type. Element is typically the chemical name of an element, which you must assign to each type via the dump_modify element command. More generally, it can be any string you wish to associated with an atom type. Mass is the atom mass. Vx, vy, vz, fx, fy, fz, and q are components of atom velocity and force and atomic charge.

There are several options for outputting atom coordinates. The x, y, z attributes write atom coordinates "unscaled", in the appropriate distance units (Angstroms, sigma, etc). Use xs, ys, zs if you want the coordinates "scaled" to the box size, so that each value is 0.0 to 1.0. If the simulation box is triclinic (tilted), then all atom coords will still be between 0.0 and 1.0. Use xu, yu, zu if you want the coordinates "unwrapped" by the image flags for each atom. Unwrapped means that if the atom has passed thru a periodic boundary one or more times, the value is printed for what the coordinate would be if it had not been wrapped back into the periodic box. Note that using xu, yu, zu means that the coordinate values may be far outside the box bounds printed with the snapshot. Using xsu, ysu, zsu is similar to using xu, yu, zu, except that the unwrapped coordinates are scaled by the box size. Atoms that have passed through a periodic boundary will have the corresponding cooordinate increased or decreased by 1.0.

The image flags can be printed directly using the ix, iy, iz attributes. For periodic dimensions, they specify which image of the simulation box the atom is considered to be in. An image of 0 means it is inside the box as defined. A value of 2 means add 2 box lengths to get the true value. A value of -1 means subtract 1 box length to get the true value. LAMMPS updates these flags as atoms cross periodic boundaries during the simulation.

The mux, muy, muz attributes are specific to dipolar systems defined with an atom style of dipole. They give the orientation of the atom's point dipole moment. The mu attribute gives the magnitude of the atom's dipole moment.

The radius and diameter attributes are specific to spherical particles that have a finite size, such as those defined with an atom style of sphere.

The omegax, omegay, and omegaz attributes are specific to finite-size spherical particles that have an angular velocity. Only certain atom styles, such as sphere define this quantity.

The angmomx, angmomy, and angmomz attributes are specific to finite-size aspherical particles that have an angular momentum. Only the ellipsoid atom style defines this quantity.

The tqx, tqy, tqz attributes are for finite-size particles that can sustain a rotational torque due to interactions with other particles.

The spin, eradius, ervel, and erforce attributes are for particles that represent nuclei and electrons modeled with the electronic force field (EFF). See atom_style electron and pair_style eff for more details.

The c_ID and c_ID[N] attributes allow per-atom vectors or arrays calculated by a compute to be output. The ID in the attribute should be replaced by the actual ID of the compute that has been defined previously in the input script. See the compute command for details. There are computes for calculating the per-atom energy, stress, centro-symmetry parameter, and coordination number of individual atoms.

Note that computes which calculate global or local quantities, as opposed to per-atom quantities, cannot be output in a dump custom command. Instead, global quantities can be output by the thermo_style custom command, and local quantities can be output by the dump local command.

If c_ID is used as a attribute, then the per-atom vector calculated by the compute is printed. If c_ID[N] is used, then N must be in the range from 1-M, which will print the Nth column of the M-length per-atom array calculated by the compute.

The f_ID and f_ID[N] attributes allow vector or array per-atom quantities calculated by a fix to be output. The ID in the attribute should be replaced by the actual ID of the fix that has been defined previously in the input script. The fix ave/atom command is one that calculates per-atom quantities. Since it can time-average per-atom quantities produced by any compute, fix, or atom-style variable, this allows those time-averaged results to be written to a dump file.

If f_ID is used as a attribute, then the per-atom vector calculated by the fix is printed. If f_ID[N] is used, then N must be in the range from 1-M, which will print the Nth column of the M-length per-atom array calculated by the fix.

The v_name attribute allows per-atom vectors calculated by a variable to be output. The name in the attribute should be replaced by the actual name of the variable that has been defined previously in the input script. Only an atom-style variable can be referenced, since it is the only style that generates per-atom values. Variables of style atom can reference individual atom attributes, per-atom atom attributes, thermodynamic keywords, or invoke other computes, fixes, or variables when they are evaluated, so this is a very general means of creating quantities to output to a dump file.

See Section_modify of the manual for information on how to add new compute and fix styles to LAMMPS to calculate per-atom quantities which could then be output into dump files.


Restrictions:

To write gzipped dump files, you must compile LAMMPS with the -DLAMMPS_GZIP option - see the Making LAMMPS section of the documentation.

The xtc style is part of the XTC package. It is only enabled if LAMMPS was built with that package. See the Making LAMMPS section for more info. This is because some machines may not support the low-level XDR data format that XTC files are written with, which will result in a compile-time error when a low-level include file is not found. Putting this style in a package makes it easy to exclude from a LAMMPS build for those machines. However, the XTC package also includes two compatibility header files and associated functions, which should be a suitable substitute on machines that do not have the appropriate native header files. This option can be invoked at build time by adding -DLAMMPS_XDR to the CCFLAGS variable in the appropriate low-level Makefile, e.g. src/MAKE/Makefile.foo. This compatibility mode has been tested successfully on Cray XT3/XT4/XT5 and IBM BlueGene/L machines and should also work on IBM BG/P, and Windows XP/Vista/7 machines.

Related commands:

dump image, dump_modify, undump

Default:

The defaults for the image style are listed on the dump image doc page.

diff --git a/doc/dump.txt b/doc/dump.txt index 743acf148..f68415f42 100644 --- a/doc/dump.txt +++ b/doc/dump.txt @@ -1,558 +1,558 @@ "LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c :link(lws,http://lammps.sandia.gov) :link(ld,Manual.html) :link(lc,Section_commands.html#comm) :line dump command :h3 "dump image"_dump_image.html command :h3 "dump molfile"_dump_molfile.html command :h3 [Syntax:] dump ID group-ID style N file args :pre ID = user-assigned name for the dump :ulb,l group-ID = ID of the group of atoms to be dumped :l style = {atom} or {cfg} or {dcd} or {xtc} or {xyz} or {image} or {molfile} or {local} or {custom} :l N = dump every this many timesteps :l file = name of file to write dump info to :l args = list of arguments for a particular style :l {atom} args = none {cfg} args = same as {custom} args, see below {dcd} args = none {xtc} args = none {xyz} args = none :pre {image} args = discussed on "dump image"_dump_image.html doc page :pre {molfile} args = discussed on "dump molfile"_dump_molfile.html doc page :pre {local} args = list of local attributes possible attributes = index, c_ID, c_ID\[N\], f_ID, f_ID\[N\] index = enumeration of local values c_ID = local vector calculated by a compute with ID c_ID\[N\] = Nth column of local array calculated by a compute with ID f_ID = local vector calculated by a fix with ID f_ID\[N\] = Nth column of local array calculated by a fix with ID :pre {custom} args = list of atom attributes possible attributes = id, mol, type, element, mass, x, y, z, xs, ys, zs, xu, yu, zu, xsu, ysu, zsu, ix, iy, iz, vx, vy, vz, fx, fy, fz, q, mux, muy, muz, mu, radius, diameter, omegax, omegay, omegaz, angmomx, angmomy, angmomz, tqx, tqy, tqz, spin, eradius, ervel, erforce, c_ID, c_ID\[N\], f_ID, f_ID\[N\], v_name :pre id = atom ID mol = molecule ID type = atom type element = name of atom element, as defined by "dump_modify"_dump_modify.html command mass = atom mass x,y,z = unscaled atom coordinates xs,ys,zs = scaled atom coordinates xu,yu,zu = unwrapped atom coordinates xsu,ysu,zsu = scaled unwrapped atom coordinates ix,iy,iz = box image that the atom is in vx,vy,vz = atom velocities fx,fy,fz = forces on atoms q = atom charge mux,muy,muz = orientation of dipole moment of atom mu = magnitude of dipole moment of atom radius,diameter = radius,diameter of spherical particle omegax,omegay,omegaz = angular velocity of spherical particle angmomx,angmomy,angmomz = angular momentum of aspherical particle tqx,tqy,tqz = torque on finite-size particles spin = electron spin eradius = electron radius ervel = electron radial velocity erforce = electron radial force c_ID = per-atom vector calculated by a compute with ID c_ID\[N\] = Nth column of per-atom array calculated by a compute with ID f_ID = per-atom vector calculated by a fix with ID f_ID\[N\] = Nth column of per-atom array calculated by a fix with ID v_name = per-atom vector calculated by an atom-style variable with name :pre :ule [Examples:] dump myDump all atom 100 dump.atom dump 2 subgroup atom 50 dump.run.bin dump 4a all custom 100 dump.myforce.* id type x y vx fx dump 4b flow custom 100 dump.%.myforce id type c_myF\[3\] v_ke -dump 2 inner cfg 10 dump.snap.*.cfg id type xs ys zs vx vy vz -dump snap all cfg 100 dump.config.*.cfg id type xs ys zs id type c_Stress[2] +dump 2 inner cfg 10 dump.snap.*.cfg mass type xs ys zs vx vy vz +dump snap all cfg 100 dump.config.*.cfg mass type xs ys zs id type c_Stress[2] dump 1 all xtc 1000 file.xtc dump e_data all custom 100 dump.eff id type x y z spin eradius fx fy fz eforce :pre [Description:] Dump a snapshot of atom quantities to one or more files every N timesteps in one of several styles. The {image} style is the exception; it creates a JPG or PPM image file of the atom configuration every N timesteps, as discussed on the "dump image"_dump_image.html doc page. The timesteps on which dump output is written can also be controlled by a variable. See the "dump_modify every"_dump_modify.html command. Only information for atoms in the specified group is dumped. The "dump_modify thresh and region"_dump_modify.html commands can also alter what atoms are included. Not all styles support all these options; see details below. As described below, the filename determines the kind of output (text or binary or gzipped, one big file or one per timestep, one big file or one per processor). IMPORTANT NOTE: Because periodic boundary conditions are enforced only on timesteps when neighbor lists are rebuilt, the coordinates of an atom written to a dump file may be slightly outside the simulation box. IMPORTANT NOTE: Unless the "dump_modify sort"_dump_modify.html option is invoked, the lines of atom information written to dump files (typically one line per atom) will be in an indeterminate order for each snapshot. This is even true when running on a single processor, if the "atom_modify sort"_atom_modify.html option is on, which it is by default. In this case atoms are re-ordered periodically during a simulation, due to spatial sorting. It is also true when running in parallel, because data for a single snapshot is collected from multiple processors. For the {atom}, {custom}, {cfg}, and {local} styles, sorting is off by default. For the {dcd}, {xtc}, {xyz}, and {molfile} styles, sorting by atom ID is on by default. See the "dump_modify"_dump_modify.html doc page for details. :line The {style} keyword determines what atom quantities are written to the file and in what format. Settings made via the "dump_modify"_dump_modify.html command can also alter the format of individual values and the file itself. The {atom}, {local}, and {custom} styles create files in a simple text format that is self-explanatory when viewing a dump file. Many of the LAMMPS "post-processing tools"_Section_tools.html, including "Pizza.py"_http://www.sandia.gov/~sjplimp/pizza.html, work with this format, as does the "rerun"_rerun.html command. For post-processing purposes the {atom}, {local}, and {custom} text files are self-describing in the following sense. The dimensions of the simulation box are included in each snapshot. For an orthogonal simulation box this information is is formatted as: ITEM: BOX BOUNDS xx yy zz xlo xhi ylo yhi zlo zhi :pre where xlo,xhi are the maximum extents of the simulation box in the x-dimension, and similarly for y and z. The "xx yy zz" represent 6 characters that encode the style of boundary for each of the 6 simulation box boundaries (xlo,xhi and ylo,yhi and zlo,zhi). Each of the 6 characters is either p = periodic, f = fixed, s = shrink wrap, or m = shrink wrapped with a minimum value. See the "boundary"_boundary.html command for details. For triclinic simulation boxes (non-orthogonal), an orthogonal bounding box which encloses the triclinic simulation box is output, along with the 3 tilt factors (xy, xz, yz) of the triclinic box, formatted as follows: ITEM: BOX BOUNDS xy xz yz xx yy zz xlo_bound xhi_bound xy ylo_bound yhi_bound xz zlo_bound zhi_bound yz :pre The presence of the text "xy xz yz" in the ITEM line indicates that the 3 tilt factors will be included on each of the 3 following lines. This bounding box is convenient for many visualization programs. The meaning of the 6 character flags for "xx yy zz" is the same as above. Note that the first two numbers on each line are now xlo_bound instead of xlo, etc, since they repesent a bounding box. See "this section"_Section_howto.html#howto_12 of the doc pages for a geometric description of triclinic boxes, as defined by LAMMPS, simple formulas for how the 6 bounding box extents (xlo_bound,xhi_bound,etc) are calculated from the triclinic parameters, and how to transform those parameters to and from other commonly used triclinic representations. The "ITEM: ATOMS" line in each snapshot lists column descriptors for the per-atom lines that follow. For example, the descriptors would be "id type xs ys zs" for the default {atom} style, and would be the atom attributes you specify in the dump command for the {custom} style. For style {atom}, atom coordinates are written to the file, along with the atom ID and atom type. By default, atom coords are written in a scaled format (from 0 to 1). I.e. an x value of 0.25 means the atom is at a location 1/4 of the distance from xlo to xhi of the box boundaries. The format can be changed to unscaled coords via the "dump_modify"_dump_modify.html settings. Image flags can also be added for each atom via dump_modify. Style {custom} allows you to specify a list of atom attributes to be written to the dump file for each atom. Possible attributes are listed above and will appear in the order specified. You cannot specify a quantity that is not defined for a particular simulation - such as {q} for atom style {bond}, since that atom style doesn't assign charges. Dumps occur at the very end of a timestep, so atom attributes will include effects due to fixes that are applied during the timestep. An explanation of the possible dump custom attributes is given below. For style {local}, local output generated by "computes"_compute.html and "fixes"_fix.html is used to generate lines of output that is written to the dump file. This local data is typically calculated by each processor based on the atoms it owns, but there may be zero or more entities per atom, e.g. a list of bond distances. An explanation of the possible dump local attributes is given below. Note that by using input from the "compute property/local"_compute_property_local.html command with dump local, it is possible to generate information on bonds, angles, etc that can be cut and pasted directly into a data file read by the "read_data"_read_data.html command. Style {cfg} has the same command syntax as style {custom} and writes extended CFG format files, as used by the "AtomEye"_http://mt.seas.upenn.edu/Archive/Graphics/A visualization package. Since the extended CFG format uses a single snapshot of the system per file, a wildcard "*" must be included in the filename, as discussed below. The list of atom attributes for style {cfg} must -begin with either "id type xs ys zs" or "id type xsu ysu zsu" or +begin with either "mass type xs ys zs" or "mass type xsu ysu zsu" since these quantities are needed to -write the CFG files in the appropriate format (though the "id" and +write the CFG files in the appropriate format (though the "mass" and "type" fields do not appear explicitly in the file). Any remaining attributes will be stored as "auxiliary properties" in the CFG files. Note that you will typically want to use the "dump_modify element"_dump_modify.html command with CFG-formatted files, to associate element names with atom types, so that AtomEye can render atoms appropriately. When unwrapped coordinates {xsu}, {ysu}, and {zsu} are requested, the nominal AtomEye periodic cell dimensions are expanded by a large factor UNWRAPEXPAND = 10.0, which ensures atoms that are displayed correctly for up to UNWRAPEXPAND/2 periodic boundary crossings in any direction. Beyond this, AtomEye will rewrap the unwrapped coordinates. The expansion causes the atoms to be drawn farther away from the viewer, but it is easy to zoom the atoms closer, and the interatomic distances are unaffected. The {dcd} style writes DCD files, a standard atomic trajectory format used by the CHARMM, NAMD, and XPlor molecular dynamics packages. DCD files are binary and thus may not be portable to different machines. The number of atoms per snapshot cannot change with the {dcd} style. The {unwrap} option of the "dump_modify"_dump_modify.html command allows DCD coordinates to be written "unwrapped" by the image flags for each atom. Unwrapped means that if the atom has passed through a periodic boundary one or more times, the value is printed for what the coordinate would be if it had not been wrapped back into the periodic box. Note that these coordinates may thus be far outside the box size stored with the snapshot. The {xtc} style writes XTC files, a compressed trajectory format used by the GROMACS molecular dynamics package, and described "here"_http://manual.gromacs.org/current/online/xtc.html. The precision used in XTC files can be adjusted via the "dump_modify"_dump_modify.html command. The default value of 1000 means that coordinates are stored to 1/1000 nanometer accuracy. XTC files are portable binary files written in the NFS XDR data format, so that any machine which supports XDR should be able to read them. The number of atoms per snapshot cannot change with the {xtc} style. The {unwrap} option of the "dump_modify"_dump_modify.html command allows XTC coordinates to be written "unwrapped" by the image flags for each atom. Unwrapped means that if the atom has passed thru a periodic boundary one or more times, the value is printed for what the coordinate would be if it had not been wrapped back into the periodic box. Note that these coordinates may thus be far outside the box size stored with the snapshot. The {xyz} style writes XYZ files, which is a simple text-based coordinate format that many codes can read. Specifically it has a line with the number of atoms, then a comment line that is usually ignored followed by one line per atom with the atom type and the x-, y-, and z-coordinate of that atom. You can use the "dump_modify element"_dump_modify.html option to change the output from using the (numerical) atom type to an element name (or some other label). This will help many visualization programs to guess bonds and colors. Note that {atom}, {custom}, {dcd}, {xtc}, and {xyz} style dump files can be read directly by "VMD"_http://www.ks.uiuc.edu/Research/vmd (a popular molecular viewing program). See "Section tools"_Section_tools.html#vmd of the manual and the tools/lmp2vmd/README.txt file for more information about support in VMD for reading and visualizing LAMMPS dump files. :line Dumps are performed on timesteps that are a multiple of N (including timestep 0) and on the last timestep of a minimization if the minimization converges. Note that this means a dump will not be performed on the initial timestep after the dump command is invoked, if the current timestep is not a multiple of N. This behavior can be changed via the "dump_modify first"_dump_modify.html command, which can also be useful if the dump command is invoked after a minimization ended on an arbitrary timestep. N can be changed between runs by using the "dump_modify every"_dump_modify.html command (not allowed for {dcd} style). The "dump_modify every"_dump_modify.html command also allows a variable to be used to determine the sequence of timesteps on which dump files are written. In this mode a dump on the first timestep of a run will also not be written unless the "dump_modify first"_dump_modify.html command is used. The specified filename determines how the dump file(s) is written. The default is to write one large text file, which is opened when the dump command is invoked and closed when an "undump"_undump.html command is used or when LAMMPS exits. For the {dcd} and {xtc} styles, this is a single large binary file. Dump filenames can contain two wildcard characters. If a "*" character appears in the filename, then one file per snapshot is written and the "*" character is replaced with the timestep value. For example, tmp.dump.* becomes tmp.dump.0, tmp.dump.10000, tmp.dump.20000, etc. This option is not available for the {dcd} and {xtc} styles. Note that the "dump_modify pad"_dump_modify.html command can be used to insure all timestep numbers are the same length (e.g. 00010), which can make it easier to read a series of dump files in order by some post-processing tools. If a "%" character appears in the filename, then each of P processors writes a portion of the dump file, and the "%" character is replaced with the processor ID from 0 to P-1. For example, tmp.dump.% becomes tmp.dump.0, tmp.dump.1, ... tmp.dump.P-1, etc. This creates smaller files and can be a fast mode of output on parallel machines that support parallel I/O for output. This option is not available for the {dcd}, {xtc}, and {xyz} styles. By default, P = the number of processors meaning one file per processor, but P can be set to a smaller value via the {nfile} or {fileper} keywords of the "dump_modify"_dump_modify.html command. These options can be the most efficient way of writing out dump files when running on large numbers of processors. Note that using the "*" and "%" characters together can produce a large number of small dump files! If the filename ends with ".bin", the dump file (or files, if "*" or "%" is also used) is written in binary format. A binary dump file will be about the same size as a text version, but will typically write out much faster. Of course, when post-processing, you will need to convert it back to text format (see the "binary2txt tool"_Section_tools.html#binary) or write your own code to read the binary file. The format of the binary file can be understood by looking at the tools/binary2txt.cpp file. This option is only available for the {atom} and {custom} styles. If the filename ends with ".gz", the dump file (or files, if "*" or "%" is also used) is written in gzipped format. A gzipped dump file will be about 3x smaller than the text version, but will also take longer to write. This option is not available for the {dcd} and {xtc} styles. :line This section explains the local attributes that can be specified as part of the {local} style. The {index} attribute can be used to generate an index number from 1 to N for each line written into the dump file, where N is the total number of local datums from all processors, or lines of output that will appear in the snapshot. Note that because data from different processors depend on what atoms they currently own, and atoms migrate between processor, there is no guarantee that the same index will be used for the same info (e.g. a particular bond) in successive snapshots. The {c_ID} and {c_ID\[N\]} attributes allow local vectors or arrays calculated by a "compute"_compute.html to be output. The ID in the attribute should be replaced by the actual ID of the compute that has been defined previously in the input script. See the "compute"_compute.html command for details. There are computes for calculating local information such as indices, types, and energies for bonds and angles. Note that computes which calculate global or per-atom quantities, as opposed to local quantities, cannot be output in a dump local command. Instead, global quantities can be output by the "thermo_style custom"_thermo_style.html command, and per-atom quantities can be output by the dump custom command. If {c_ID} is used as a attribute, then the local vector calculated by the compute is printed. If {c_ID\[N\]} is used, then N must be in the range from 1-M, which will print the Nth column of the M-length local array calculated by the compute. The {f_ID} and {f_ID\[N\]} attributes allow local vectors or arrays calculated by a "fix"_fix.html to be output. The ID in the attribute should be replaced by the actual ID of the fix that has been defined previously in the input script. If {f_ID} is used as a attribute, then the local vector calculated by the fix is printed. If {f_ID\[N\]} is used, then N must be in the range from 1-M, which will print the Nth column of the M-length local array calculated by the fix. Here is an example of how to dump bond info for a system, including the distance and energy of each bond: compute 1 all property/local batom1 batom2 btype compute 2 all bond/local dist eng dump 1 all local 1000 tmp.dump index c_1\[1\] c_1\[2\] c_1\[3\] c_2\[1\] c_2\[2\] :pre :line This section explains the atom attributes that can be specified as part of the {custom} and {cfg} styles. The {id}, {mol}, {type}, {element}, {mass}, {vx}, {vy}, {vz}, {fx}, {fy}, {fz}, {q} attributes are self-explanatory. {Id} is the atom ID. {Mol} is the molecule ID, included in the data file for molecular systems. {Type} is the atom type. {Element} is typically the chemical name of an element, which you must assign to each type via the "dump_modify element"_dump_modify.html command. More generally, it can be any string you wish to associated with an atom type. {Mass} is the atom mass. {Vx}, {vy}, {vz}, {fx}, {fy}, {fz}, and {q} are components of atom velocity and force and atomic charge. There are several options for outputting atom coordinates. The {x}, {y}, {z} attributes write atom coordinates "unscaled", in the appropriate distance "units"_units.html (Angstroms, sigma, etc). Use {xs}, {ys}, {zs} if you want the coordinates "scaled" to the box size, so that each value is 0.0 to 1.0. If the simulation box is triclinic (tilted), then all atom coords will still be between 0.0 and 1.0. Use {xu}, {yu}, {zu} if you want the coordinates "unwrapped" by the image flags for each atom. Unwrapped means that if the atom has passed thru a periodic boundary one or more times, the value is printed for what the coordinate would be if it had not been wrapped back into the periodic box. Note that using {xu}, {yu}, {zu} means that the coordinate values may be far outside the box bounds printed with the snapshot. Using {xsu}, {ysu}, {zsu} is similar to using {xu}, {yu}, {zu}, except that the unwrapped coordinates are scaled by the box size. Atoms that have passed through a periodic boundary will have the corresponding cooordinate increased or decreased by 1.0. The image flags can be printed directly using the {ix}, {iy}, {iz} attributes. For periodic dimensions, they specify which image of the simulation box the atom is considered to be in. An image of 0 means it is inside the box as defined. A value of 2 means add 2 box lengths to get the true value. A value of -1 means subtract 1 box length to get the true value. LAMMPS updates these flags as atoms cross periodic boundaries during the simulation. The {mux}, {muy}, {muz} attributes are specific to dipolar systems defined with an atom style of {dipole}. They give the orientation of the atom's point dipole moment. The {mu} attribute gives the magnitude of the atom's dipole moment. The {radius} and {diameter} attributes are specific to spherical particles that have a finite size, such as those defined with an atom style of {sphere}. The {omegax}, {omegay}, and {omegaz} attributes are specific to finite-size spherical particles that have an angular velocity. Only certain atom styles, such as {sphere} define this quantity. The {angmomx}, {angmomy}, and {angmomz} attributes are specific to finite-size aspherical particles that have an angular momentum. Only the {ellipsoid} atom style defines this quantity. The {tqx}, {tqy}, {tqz} attributes are for finite-size particles that can sustain a rotational torque due to interactions with other particles. The {spin}, {eradius}, {ervel}, and {erforce} attributes are for particles that represent nuclei and electrons modeled with the electronic force field (EFF). See "atom_style electron"_atom_style.html and "pair_style eff"_pair_eff.html for more details. The {c_ID} and {c_ID\[N\]} attributes allow per-atom vectors or arrays calculated by a "compute"_compute.html to be output. The ID in the attribute should be replaced by the actual ID of the compute that has been defined previously in the input script. See the "compute"_compute.html command for details. There are computes for calculating the per-atom energy, stress, centro-symmetry parameter, and coordination number of individual atoms. Note that computes which calculate global or local quantities, as opposed to per-atom quantities, cannot be output in a dump custom command. Instead, global quantities can be output by the "thermo_style custom"_thermo_style.html command, and local quantities can be output by the dump local command. If {c_ID} is used as a attribute, then the per-atom vector calculated by the compute is printed. If {c_ID\[N\]} is used, then N must be in the range from 1-M, which will print the Nth column of the M-length per-atom array calculated by the compute. The {f_ID} and {f_ID\[N\]} attributes allow vector or array per-atom quantities calculated by a "fix"_fix.html to be output. The ID in the attribute should be replaced by the actual ID of the fix that has been defined previously in the input script. The "fix ave/atom"_fix_ave_atom.html command is one that calculates per-atom quantities. Since it can time-average per-atom quantities produced by any "compute"_compute.html, "fix"_fix.html, or atom-style "variable"_variable.html, this allows those time-averaged results to be written to a dump file. If {f_ID} is used as a attribute, then the per-atom vector calculated by the fix is printed. If {f_ID\[N\]} is used, then N must be in the range from 1-M, which will print the Nth column of the M-length per-atom array calculated by the fix. The {v_name} attribute allows per-atom vectors calculated by a "variable"_variable.html to be output. The name in the attribute should be replaced by the actual name of the variable that has been defined previously in the input script. Only an atom-style variable can be referenced, since it is the only style that generates per-atom values. Variables of style {atom} can reference individual atom attributes, per-atom atom attributes, thermodynamic keywords, or invoke other computes, fixes, or variables when they are evaluated, so this is a very general means of creating quantities to output to a dump file. See "Section_modify"_Section_modify.html of the manual for information on how to add new compute and fix styles to LAMMPS to calculate per-atom quantities which could then be output into dump files. :line [Restrictions:] To write gzipped dump files, you must compile LAMMPS with the -DLAMMPS_GZIP option - see the "Making LAMMPS"_Section_start.html#start_2 section of the documentation. The {xtc} style is part of the XTC package. It is only enabled if LAMMPS was built with that package. See the "Making LAMMPS"_Section_start.html#start_3 section for more info. This is because some machines may not support the low-level XDR data format that XTC files are written with, which will result in a compile-time error when a low-level include file is not found. Putting this style in a package makes it easy to exclude from a LAMMPS build for those machines. However, the XTC package also includes two compatibility header files and associated functions, which should be a suitable substitute on machines that do not have the appropriate native header files. This option can be invoked at build time by adding -DLAMMPS_XDR to the CCFLAGS variable in the appropriate low-level Makefile, e.g. src/MAKE/Makefile.foo. This compatibility mode has been tested successfully on Cray XT3/XT4/XT5 and IBM BlueGene/L machines and should also work on IBM BG/P, and Windows XP/Vista/7 machines. [Related commands:] "dump image"_dump_image.html, "dump_modify"_dump_modify.html, "undump"_undump.html [Default:] The defaults for the image style are listed on the "dump image"_dump_image.html doc page. diff --git a/doc/fix_phonon.html b/doc/fix_phonon.html index 0c4690999..e013e0992 100644 --- a/doc/fix_phonon.html +++ b/doc/fix_phonon.html @@ -1,207 +1,221 @@
LAMMPS WWW Site - LAMMPS Documentation - LAMMPS Commands

fix phonon command

Syntax:

fix ID group-ID phonon N Noutput Nwait map_file prefix keyword values ... 
 

Examples:

fix 1 all phonon 20 5000 200000 map.in LJ1D sysdim 1
-fix 1 all phonon 20 5000 200000 map.in EAM3D 
+fix 1 all phonon 20 5000 200000 map.in EAM3D
+fix 1 all phonon 10 5000 500000 GAMMA EAM0D nasr 100 
 

Description:

Calculate the dynamical matrix from molecular dynamics simulations based on fluctuation-dissipation theory for a group of atoms.

Consider a crystal with N unit cells in three dimensions labelled l = (l1,l2,l3) where li are integers. Each unit cell is defined by three linearly independent vectors a1, a2, a3 forming a parallelipiped, containing K basis atoms labelled k.

Based on fluctuation-dissipation theory, the force constant coefficients of the system in reciprocal space are given by (Campañá , Kong)

Φkα,k'β(q) = kBT G-1kα,k'β(q),

where G is the Green's functions coefficients given by

Gkα,k'β(q) = <u(q)•uk'β*(q)>,

where <...> denotes the ensemble average, and

u(q) = ∑l ulkα exp(iqrl)

is the α component of the atomic displacement for the kth atom in the unit cell in reciprocal space at q. In practice, the Green's functions coefficients can also be measured according to the following formula,

Gkα,k'β(q) = <R(q)•R*k'β(q)> - <R>(q)•<R>*k'β(q),

where R is the instantaneous positions of atoms, and <R> is the averaged atomic positions. It gives essentially the same results as the displacement method and is easier to implement in an MD code.

Once the force constant matrix is known, the dynamical matrix D can then be obtained by

Dkα, k'β(q) = (mkmk')-1/2 Φkα,k'β(q)

whose eigenvalues are exactly the phonon frequencies at q.

This fix uses positions of atoms in the specified group and calculates two-point correlations. To achieve this. the positions of the atoms are examined every Nevery steps and are Fourier-transformed into reciprocal space, where the averaging process and correlation computation is then done. After every Noutput measurements, the matrix G(q) is calculated and inverted to obtain the elastic stiffness coefficients. The dynamical matrices are then constructed and written to prefix.bin.timestep files in binary format and to the file prefix.log for each wavevector q.

A detailed description of this method can be found in (Kong2011).

The sysdim keyword is optional. If specified with a value smaller than the dimensionality of the LAMMPS simulation, its value is used for the dynamical matrix calculation. For example, using LAMMPS ot model a 2D or 3D system, the phonon dispersion of a 1D atomic chain can be computed using sysdim = 1.

The nasr keyword is optional. An iterative procedure is employed to enforce the acoustic sum rule on Φ at Γ, and the number provided by keyword nasr gives the total number of iterations. For a system whose unit cell has only one atom, nasr = 1 is sufficient; for other systems, nasr = 10 is typically sufficient.

The map_file contains the mapping information between the lattice indices and the atom IDs, which tells the code which atom sits at which lattice point; the lattice indices start from 0. An auxiliary code, latgen, can be employed to generate the compatible map file for various crystals.

+

In case one simulates an aperiodic system, where the whole simulation box +is treated as a unit cell, one can set map_file as GAMMA, so that the mapping +info will be generated internally and a file is not needed. In this case, the +dynamical matrix at only the gamma-point will/can be evaluated. Please keep in +mind that fix-phonon is designed for cyrstals, it will be inefficient and +even degrade the performance of lammps in case the unit cell is too large. +

The calculated dynamical matrix elements are written out in energy/distance^2/mass units. The coordinates for q points in the log file is in the units of the basis vectors of the corresponding reciprocal lattice.

Restart, fix_modify, output, run start/stop, minimize info:

No information about this fix is written to binary restart files.

The fix_modify temp option is supported by this fix. You can use it to change the temperature compute from thermo_temp to the one that reflects the true temperature of atoms in the group.

No global scalar or vector or per-atom quantities are stored by this fix for access by various output commands.

Instead, this fix outputs its initialization information (including mapping information) and the calculated dynamical matrices to the file prefix.log, with the specified prefix. The dynamical matrices are also written to files prefix.bin.timestep in binary format. These can be read by the post-processing tool in tools/phonon to compute the phonon density of states and/or phonon dispersion curves.

No parameter of this fix can be used with the start/stop keywords of the run command.

This fix is not invoked during energy minimization.

Restrictions:

This fix assumes a crystalline system with periodical lattice. The temperature of the system should not exceed the melting temperature to keep the system in its solid state.

This fix is part of the USER-PHONON package. It is only enabled if LAMMPS was built with that package. See the Making LAMMPS section for more info.

This fix requires LAMMPS be built with an FFT library. See the Making LAMMPS section for more info.

Related commands:

compute msd

Default:

The option defaults are sysdim = the same dimemsion as specified by the dimension command, and nasr = 20.


(Campañá) C. Campañá and M. H. Müser, Practical Green's function approach to the simulation of elastic semi-infinite solids, Phys. Rev. B 74, 075420 (2006)

(Kong) L.T. Kong, G. Bartels, C. Campañá, C. Denniston, and Martin H. Müser, Implementation of Green's function molecular dynamics: An extension to LAMMPS, Computer Physics Communications 180(6):1004-1010 (2009).

L.T. Kong, C. Denniston, and Martin H. Müser, An improved version of the Green's function molecular dynamics method, Computer Physics Communications 182(2):540-541 (2011).

(Kong2011) L.T. Kong, Phonon dispersion measured directly from molecular dynamics simulations, Computer Physics Communications 182(10):2201-2207, (2011).

diff --git a/doc/fix_phonon.txt b/doc/fix_phonon.txt index 9590ded07..50285d06b 100644 --- a/doc/fix_phonon.txt +++ b/doc/fix_phonon.txt @@ -1,189 +1,202 @@ "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 phonon command :h3 [Syntax:] fix ID group-ID phonon N Noutput Nwait map_file prefix keyword values ... :pre ID, group-ID are documented in "fix"_fix.html command :ulb,l phonon = style name of this fix command :l N = measure the Green's function every this many timesteps :l Noutput = output the dynamical matrix every this many measurements :l Nwait = wait this many timesteps before measuring :l -map_file = file containing the mapping info between atom ID and the lattice indices :l +map_file = {file} or {GAMMA} :l + {file} is the file that contains the mapping info between atom ID and the lattice indices. :pre + + {GAMMA} flags to treate the whole simulation box as a unit cell, so that the mapping + info can be generated internally. In this case, dynamical matrix at only the gamma-point + will/can be evaluated. :pre prefix = prefix for output files :l one or none keyword/value pairs may be appended :l keyword = {sysdim} or {nasr} :l {sysdim} value = d d = dimension of the system, usually the same as the MD model dimension {nasr} value = n n = number of iterations to enforce the acoustic sum rule :pre :ule [Examples:] fix 1 all phonon 20 5000 200000 map.in LJ1D sysdim 1 -fix 1 all phonon 20 5000 200000 map.in EAM3D :pre +fix 1 all phonon 20 5000 200000 map.in EAM3D +fix 1 all phonon 10 5000 500000 GAMMA EAM0D nasr 100 :pre [Description:] Calculate the dynamical matrix from molecular dynamics simulations based on fluctuation-dissipation theory for a group of atoms. Consider a crystal with {N} unit cells in three dimensions labelled {l = (l1,l2,l3)} where {li} are integers. Each unit cell is defined by three linearly independent vectors [a]1, [a]2, [a]3 forming a parallelipiped, containing {K} basis atoms labelled {k}. Based on fluctuation-dissipation theory, the force constant coefficients of the system in reciprocal space are given by ("Campañá"_#Campana , "Kong"_#Kong)
Φkα,k'β(q) = kBT G-1kα,k'β(q),
where [G] is the Green's functions coefficients given by
Gkα,k'β(q) = <u(q)•uk'β*(q)>,
where <...> denotes the ensemble average, and
[u](q) = ∑l ulkα exp(i[qr]l)
is the α component of the atomic displacement for the {k}th atom in the unit cell in reciprocal space at [q]. In practice, the Green's functions coefficients can also be measured according to the following formula,
Gkα,k'β(q) = <R(q)•R*k'β(q)> - <R>(q)•<R>*k'β(q),
where [R] is the instantaneous positions of atoms, and <[R]> is the averaged atomic positions. It gives essentially the same results as the displacement method and is easier to implement in an MD code. Once the force constant matrix is known, the dynamical matrix [D] can then be obtained by
Dkα, k'β(q) = (mkmk')-1/2 Φkα,k'β(q)
whose eigenvalues are exactly the phonon frequencies at [q]. This fix uses positions of atoms in the specified group and calculates two-point correlations. To achieve this. the positions of the atoms are examined every {Nevery} steps and are Fourier-transformed into reciprocal space, where the averaging process and correlation computation is then done. After every {Noutput} measurements, the matrix [G]([q]) is calculated and inverted to obtain the elastic stiffness coefficients. The dynamical matrices are then constructed and written to {prefix}.bin.timestep files in binary format and to the file {prefix}.log for each wavevector [q]. A detailed description of this method can be found in ("Kong2011"_#Kong2011). The {sysdim} keyword is optional. If specified with a value smaller than the dimensionality of the LAMMPS simulation, its value is used for the dynamical matrix calculation. For example, using LAMMPS ot model a 2D or 3D system, the phonon dispersion of a 1D atomic chain can be computed using {sysdim} = 1. The {nasr} keyword is optional. An iterative procedure is employed to enforce the acoustic sum rule on Φ at Γ, and the number provided by keyword {nasr} gives the total number of iterations. For a system whose unit cell has only one atom, {nasr} = 1 is sufficient; for other systems, {nasr} = 10 is typically sufficient. The {map_file} contains the mapping information between the lattice indices and the atom IDs, which tells the code which atom sits at which lattice point; the lattice indices start from 0. An auxiliary code, "latgen"_http://code.google.com/p/latgen, can be employed to generate the compatible map file for various crystals. +In case one simulates an aperiodic system, where the whole simulation box +is treated as a unit cell, one can set {map_file} as {GAMMA}, so that the mapping +info will be generated internally and a file is not needed. In this case, the +dynamical matrix at only the gamma-point will/can be evaluated. Please keep in +mind that fix-phonon is designed for cyrstals, it will be inefficient and +even degrade the performance of lammps in case the unit cell is too large. + The calculated dynamical matrix elements are written out in "energy/distance^2/mass"_units.html units. The coordinates for {q} points in the log file is in the units of the basis vectors of the corresponding reciprocal lattice. [Restart, fix_modify, output, run start/stop, minimize info:] No information about this fix is written to "binary restart files"_restart.html. The "fix_modify"_fix_modify.html {temp} option is supported by this fix. You can use it to change the temperature compute from thermo_temp to the one that reflects the true temperature of atoms in the group. No global scalar or vector or per-atom quantities are stored by this fix for access by various "output commands"_Section_howto.html#4_15. Instead, this fix outputs its initialization information (including mapping information) and the calculated dynamical matrices to the file {prefix}.log, with the specified {prefix}. The dynamical matrices are also written to files {prefix}.bin.timestep in binary format. These can be read by the post-processing tool in tools/phonon to compute the phonon density of states and/or phonon dispersion curves. No parameter of this fix can be used with the {start/stop} keywords of the "run"_run.html command. This fix is not invoked during "energy minimization"_minimize.html. [Restrictions:] This fix assumes a crystalline system with periodical lattice. The temperature of the system should not exceed the melting temperature to keep the system in its solid state. This fix is part of the USER-PHONON 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 fix requires LAMMPS be built with an FFT library. See the "Making LAMMPS"_Section_start.html#start_2 section for more info. [Related commands:] "compute msd"_compute_msd.html [Default:] The option defaults are sysdim = the same dimemsion as specified by the "dimension"_dimension command, and nasr = 20. :line :link(Campana) [(Campañá)] C. Campañá and M. H. Müser, {Practical Green's function approach to the simulation of elastic semi-infinite solids}, "Phys. Rev. B [74], 075420 (2006)"_http://dx.doi.org/10.1103/PhysRevB.74.075420 :link(Kong) [(Kong)] L.T. Kong, G. Bartels, C. Campañá, C. Denniston, and Martin H. Müser, {Implementation of Green's function molecular dynamics: An extension to LAMMPS}, "Computer Physics Communications [180](6):1004-1010 (2009)."_http://dx.doi.org/10.1016/j.cpc.2008.12.035 L.T. Kong, C. Denniston, and Martin H. Müser, {An improved version of the Green's function molecular dynamics method}, "Computer Physics Communications [182](2):540-541 (2011)."_http://dx.doi.org/10.1016/j.cpc.2010.10.006 :link(Kong2011) [(Kong2011)] L.T. Kong, {Phonon dispersion measured directly from molecular dynamics simulations}, "Computer Physics Communications [182](10):2201-2207, (2011)."_http://dx.doi.org/10.1016/j.cpc.2011.04.019 diff --git a/src/USER-PHONON/fix_phonon.cpp b/src/USER-PHONON/fix_phonon.cpp index 83f667907..5e3113300 100644 --- a/src/USER-PHONON/fix_phonon.cpp +++ b/src/USER-PHONON/fix_phonon.cpp @@ -1,927 +1,927 @@ -/* ---------------------------------------------------------------------- - LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator - http://lammps.sandia.gov, Sandia National Laboratories - Steve Plimpton, sjplimp@sandia.gov - - Copyright (2003) Sandia Corporation. Under the terms of Contract - DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains - certain rights in this software. This software is distributed under - the GNU General Public License. - - See the README file in the top-level LAMMPS directory. -------------------------------------------------------------------------- */ -/* ---------------------------------------------------------------------- - Contributing authors: - Ling-Ti Kong - - Contact: - School of Materials Science and Engineering, - Shanghai Jiao Tong University, - 800 Dongchuan Road, Minhang, - Shanghai 200240, CHINA - - konglt@sjtu.edu.cn; konglt@gmail.com -------------------------------------------------------------------------- */ - -#include "string.h" -#include "fix_phonon.h" -#include "atom.h" -#include "compute.h" -#include "domain.h" -#include "fft3d_wrap.h" -#include "force.h" -#include "group.h" -#include "lattice.h" -#include "modify.h" -#include "update.h" -#include "citeme.h" -#include "memory.h" -#include "error.h" - -using namespace LAMMPS_NS; -using namespace FixConst; - -#define INVOKED_SCALAR 1 -#define INVOKED_VECTOR 2 -#define MAXLINE 512 - -static const char cite_fix_phonon[] = - "fix phonon command:\n\n" - "@Article{Kong11,\n" - " author = {L. T. Kong},\n" - " title = {Phonon dispersion measured directly from molecular dynamics simulations},\n" - " journal = {Comp.~Phys.~Comm.},\n" - " year = 2011,\n" - " volume = 182,\n" - " pages = {2201--2207}\n" - "}\n\n"; - -/* ---------------------------------------------------------------------- */ - -FixPhonon::FixPhonon(LAMMPS *lmp, int narg, char **arg) : Fix(lmp, narg, arg) -{ - if (lmp->citeme) lmp->citeme->add(cite_fix_phonon); - - MPI_Comm_rank(world,&me); - MPI_Comm_size(world,&nprocs); - - if (narg < 8) error->all(FLERR,"Illegal fix phonon command: number of arguments < 8"); - - nevery = force->inumeric(FLERR, arg[3]); // Calculate this fix every n steps! - if (nevery < 1) error->all(FLERR,"Illegal fix phonon command"); - - nfreq = force->inumeric(FLERR, arg[4]); // frequency to output result - if (nfreq < 1) error->all(FLERR,"Illegal fix phonon command"); - - waitsteps = ATOBIGINT(arg[5]); // Wait this many timesteps before actually measuring - if (waitsteps < 0) error->all(FLERR,"Illegal fix phonon command: waitsteps < 0 !"); - - int n = strlen(arg[6]) + 1; // map file - mapfile = new char[n]; - strcpy(mapfile, arg[6]); - - n = strlen(arg[7]) + 1; // prefix of output - prefix = new char[n]; - strcpy(prefix, arg[7]); - logfile = new char[n+4]; - sprintf(logfile,"%s.log",prefix); - - int sdim = sysdim = domain->dimension; - int iarg = 8; - nasr = 20; - - // other command line options - while (iarg < narg){ - if (strcmp(arg[iarg],"sysdim") == 0){ - if (++iarg >= narg) error->all(FLERR,"Illegal fix phonon command: incomplete command line options."); - sdim = force->inumeric(FLERR, arg[iarg]); - if (sdim < 1) error->all(FLERR,"Illegal fix phonon command: sysdim should not be less than 1."); - - } else if (strcmp(arg[iarg],"nasr") == 0){ - if (++iarg >= narg) error->all(FLERR,"Illegal fix phonon command: incomplete command line options."); - nasr = force->inumeric(FLERR, arg[iarg]); - - } else { - error->all(FLERR,"Illegal fix phonon command: unknown option read!"); - } - - ++iarg; - } - - // get the dimension of the simulation; 1D is possible by specifying the option of "sysdim 1" - if (sdim < sysdim) sysdim = sdim; - nasr = MAX(0, nasr); - - // get the total number of atoms in group - ngroup = static_cast(group->count(igroup)); - if (ngroup < 1) error->all(FLERR,"No atom found for fix phonon!"); - - // MPI gatherv related variables - recvcnts = new int[nprocs]; - displs = new int[nprocs]; - - // mapping index - tag2surf.clear(); // clear map info - surf2tag.clear(); - - // get the mapping between lattice indices and atom IDs - readmap(); delete []mapfile; - if (nucell == 1) nasr = MIN(1,nasr); - - // get the mass matrix for dynamic matrix - getmass(); - - // create FFT and allocate memory for FFT - // here the parallization is done on the x direction only - nxlo = 0; - int *nx_loc = new int [nprocs]; - for (int i = 0; i < nprocs; ++i){ - nx_loc[i] = nx/nprocs; - if (i < nx%nprocs) ++nx_loc[i]; - } - for (int i = 0; i < me; ++i) nxlo += nx_loc[i]; - nxhi = nxlo + nx_loc[me] - 1; - mynpt = nx_loc[me]*ny*nz; - mynq = mynpt; - - fft_dim = nucell*sysdim; - fft_dim2 = fft_dim*fft_dim; - fft_nsend = mynpt*fft_dim; - - fft_cnts = new int[nprocs]; - fft_disp = new int[nprocs]; - fft_disp[0] = 0; - for (int i = 0; i < nprocs; ++i) fft_cnts[i] = nx_loc[i]*ny*nz*fft_dim; - for (int i = 1; i < nprocs; ++i) fft_disp[i] = fft_disp[i-1]+fft_cnts[i-1]; - delete []nx_loc; - - fft = new FFT3d(lmp,world,nz,ny,nx,0,nz-1,0,ny-1,nxlo,nxhi,0,nz-1,0,ny-1,nxlo,nxhi,0,0,&mysize); - memory->create(fft_data, MAX(1,mynq)*2, "fix_phonon:fft_data"); - - // allocate variables; MAX(1,... is used because NULL buffer will result in error for MPI - memory->create(RIloc,ngroup,(sysdim+1),"fix_phonon:RIloc"); - memory->create(RIall,ngroup,(sysdim+1),"fix_phonon:RIall"); - memory->create(Rsort,ngroup, sysdim, "fix_phonon:Rsort"); - - memory->create(Rnow, MAX(1,mynpt),fft_dim,"fix_phonon:Rnow"); - memory->create(Rsum, MAX(1,mynpt),fft_dim,"fix_phonon:Rsum"); - - memory->create(basis,nucell, sysdim, "fix_phonon:basis"); - - // because of hermit, only nearly half of q points are stored - memory->create(Rqnow,MAX(1,mynq),fft_dim, "fix_phonon:Rqnow"); - memory->create(Rqsum,MAX(1,mynq),fft_dim2,"fix_phonon:Rqsum"); - memory->create(Phi_q,MAX(1,mynq),fft_dim2,"fix_phonon:Phi_q"); - - // variable to collect all local Phi to root - if (me == 0) memory->create(Phi_all,ntotal,fft_dim2,"fix_phonon:Phi_all"); - else memory->create(Phi_all,1,1,"fix_phonon:Phi_all"); - - // output some information on the system to log file - if (me == 0){ - flog = fopen(logfile, "w"); - if (flog == NULL) { - char str[MAXLINE]; - sprintf(str,"Can not open output file %s",logfile); - error->one(FLERR,str); - } - for (int i = 0; i < 60; ++i) fprintf(flog,"#"); fprintf(flog,"\n"); - fprintf(flog,"# group name of the atoms under study : %s\n", group->names[igroup]); - fprintf(flog,"# total number of atoms in the group : %d\n", ngroup); - fprintf(flog,"# dimension of the system : %d D\n", sysdim); - fprintf(flog,"# number of atoms per unit cell : %d\n", nucell); - fprintf(flog,"# dimension of the FFT mesh : %d x %d x %d\n", nx, ny, nz); - fprintf(flog,"# number of wait steps before measurement : " BIGINT_FORMAT "\n", waitsteps); - fprintf(flog,"# frequency of the measurement : %d\n", nevery); - fprintf(flog,"# output result after this many measurement: %d\n", nfreq); - fprintf(flog,"# number of processors used by this run : %d\n", nprocs); - for (int i = 0; i < 60; ++i) fprintf(flog,"#"); fprintf(flog,"\n"); - fprintf(flog,"# mapping information between lattice index and atom id\n"); - fprintf(flog,"# nx ny nz nucell\n"); - fprintf(flog,"%d %d %d %d\n", nx, ny, nz, nucell); - fprintf(flog,"# l1 l2 l3 k atom_id\n"); - int ix, iy, iz, iu; - for (idx = 0; idx < ngroup; ++idx){ - itag = surf2tag[idx]; - iu = idx%nucell; - iz = (idx/nucell)%nz; - iy = (idx/(nucell*nz))%ny; - ix = (idx/(nucell*nz*ny))%nx; - fprintf(flog,"%d %d %d %d %d\n", ix, iy, iz, iu, itag); - } - for (int i = 0; i < 60; ++i) fprintf(flog,"#"); fprintf(flog,"\n"); - fflush(flog); - } - surf2tag.clear(); - - // default temperature is from thermo - TempSum = new double[sysdim]; - id_temp = new char[12]; - strcpy(id_temp,"thermo_temp"); - int icompute = modify->find_compute(id_temp); - temperature = modify->compute[icompute]; - inv_nTemp = 1.0/group->count(temperature->igroup); - -return; -} // end of constructor - -/* ---------------------------------------------------------------------- */ - -void FixPhonon::post_run() -{ - // compute and output final results - if (ifreq > 0 && ifreq != nfreq) postprocess(); - if (me == 0) fclose(flog); -} - -/* ---------------------------------------------------------------------- */ - -FixPhonon::~FixPhonon() -{ - // delete locally stored array - memory->destroy(RIloc); - memory->destroy(RIall); - memory->destroy(Rsort); - memory->destroy(Rnow); - memory->destroy(Rsum); - - memory->destroy(basis); - - memory->destroy(Rqnow); - memory->destroy(Rqsum); - memory->destroy(Phi_q); - memory->destroy(Phi_all); - - delete []recvcnts; - delete []displs; - delete []prefix; - delete []logfile; - delete []fft_cnts; - delete []fft_disp; - delete []id_temp; - delete []TempSum; - delete []M_inv_sqrt; - delete []basetype; - - // destroy FFT - delete fft; - memory->sfree(fft_data); - - // clear map info - tag2surf.clear(); - surf2tag.clear(); - -} - -/* ---------------------------------------------------------------------- */ - -int FixPhonon::setmask() -{ - int mask = 0; - mask |= END_OF_STEP; - -return mask; -} - -/* ---------------------------------------------------------------------- */ - -void FixPhonon::init() -{ - // warn if more than one fix-phonon - int count = 0; - for (int i = 0; i < modify->nfix; ++i) if (strcmp(modify->fix[i]->style,"gfc") == 0) ++count; - if (count > 1 && me == 0) error->warning(FLERR,"More than one fix phonon defined"); // just warn, but allowed. - -return; -} - -/* ---------------------------------------------------------------------- */ - -void FixPhonon::setup(int flag) -{ - // initialize accumulating variables - for (int i = 0; i < sysdim; ++i) TempSum[i] = 0.; - - for (int i = 0; i < mynpt; ++i) - for (int j = 0; j < fft_dim; ++j) Rsum[i][j] = 0.; - - for (int i =0; i < mynq; ++i) - for (int j =0; j < fft_dim2; ++j) Rqsum[i][j] = std::complex (0.,0.); - - for (int i = 0; i < 6; ++i) hsum[i] = 0.; - - for (int i = 0; i < nucell; ++i) - for (int j = 0; j < sysdim; ++j) basis[i][j] = 0.; - - prev_nstep = update->ntimestep; - neval = ifreq = 0; - -return; -} - -/* ---------------------------------------------------------------------- */ - -void FixPhonon::end_of_step() -{ - if ( (update->ntimestep-prev_nstep) <= waitsteps) return; - - double **x = atom->x; - int *mask = atom->mask; - int *tag = atom->tag; - int *image = atom->image; - int nlocal = atom->nlocal; - - double xprd = domain->xprd; - double yprd = domain->yprd; - double zprd = domain->zprd; - double *h = domain->h; - double xbox, ybox, zbox; - - int i,idim,jdim,ndim; - double xcur[3]; - - // to get the current temperature - if (!(temperature->invoked_flag & INVOKED_VECTOR)) temperature->compute_vector(); - for (idim = 0; idim < sysdim; ++idim) TempSum[idim] += temperature->vector[idim]; - - // evaluate R(r) on local proc - nfind = 0; - for (i = 0; i < nlocal; ++i){ - if (mask[i] & groupbit){ - itag = tag[i]; - idx = tag2surf[itag]; - - domain->unmap(x[i], image[i], xcur); - - for (idim = 0; idim < sysdim; ++idim) RIloc[nfind][idim] = xcur[idim]; - RIloc[nfind++][sysdim] = double(idx); - } - } - - // gather R(r) on local proc, then sort and redistribute to all procs for FFT - nfind *= (sysdim+1); - displs[0] = 0; - for (i = 0; i < nprocs; ++i) recvcnts[i] = 0; - MPI_Gather(&nfind,1,MPI_INT,recvcnts,1,MPI_INT,0,world); - for (i = 1; i < nprocs; ++i) displs[i] = displs[i-1] + recvcnts[i-1]; - - MPI_Gatherv(RIloc[0],nfind,MPI_DOUBLE,RIall[0],recvcnts,displs,MPI_DOUBLE,0,world); - if (me == 0){ - for (i = 0; i < ngroup; ++i){ - idx = static_cast(RIall[i][sysdim]); - for (idim = 0; idim < sysdim; ++idim) Rsort[idx][idim] = RIall[i][idim]; - } - } - MPI_Scatterv(Rsort[0],fft_cnts,fft_disp, MPI_DOUBLE, Rnow[0], fft_nsend, MPI_DOUBLE,0,world); - - // get Rsum - for (idx = 0; idx < mynpt; ++idx) - for (idim = 0; idim < fft_dim; ++idim) Rsum[idx][idim] += Rnow[idx][idim]; - - // FFT R(r) to get R(q) - for (idim = 0; idim < fft_dim; ++idim){ - int m=0; - for (idx = 0; idx < mynpt; ++idx){ - fft_data[m++] = Rnow[idx][idim]; - fft_data[m++] = 0.; - } - - fft->compute(fft_data, fft_data, -1); - - m = 0; - for (idq = 0; idq < mynq; ++idq){ - Rqnow[idq][idim] = std::complex(fft_data[m], fft_data[m+1]); - m += 2; - } - } - - // to get sum(R(q).R(q)*) - for (idq = 0; idq < mynq; ++idq){ - ndim = 0; - for (idim = 0; idim < fft_dim; ++idim) - for (jdim = 0; jdim < fft_dim; ++jdim) Rqsum[idq][ndim++] += Rqnow[idq][idim]*conj(Rqnow[idq][jdim]); - } - - // get basis info - if (fft_dim > sysdim){ - double dist2orig[3]; - for (idx = 0; idx < mynpt; ++idx){ - ndim = sysdim; - for (i = 1; i < nucell; ++i){ - for (idim = 0; idim < sysdim; ++idim) dist2orig[idim] = Rnow[idx][ndim++] - Rnow[idx][idim]; - domain->minimum_image(dist2orig); - for (idim = 0; idim < sysdim; ++idim) basis[i][idim] += dist2orig[idim]; - } - } - } - // get lattice vector info - for (int i = 0; i < 6; ++i) hsum[i] += h[i]; - - // increment counter - ++neval; - - // compute and output Phi_q after every nfreq evaluations - if (++ifreq == nfreq) postprocess(); - -return; -} // end of end_of_step() - -/* ---------------------------------------------------------------------- */ - -double FixPhonon::memory_usage() -{ - double bytes = sizeof(double)*2*mynq - + sizeof(std::map)*2*ngroup - + sizeof(double)*(ngroup*(3*sysdim+2)+mynpt*fft_dim*2) - + sizeof(std::complex)*MAX(1,mynq)*fft_dim *(1+2*fft_dim) - + sizeof(std::complex)*ntotal*fft_dim2 - + sizeof(int) * nprocs * 4; - return bytes; -} - -/* ---------------------------------------------------------------------- */ - -int FixPhonon::modify_param(int narg, char **arg) -{ - if (strcmp(arg[0],"temp") == 0) { - if (narg < 2) error->all(FLERR,"Illegal fix_modify command"); - delete [] id_temp; - int n = strlen(arg[1]) + 1; - id_temp = new char[n]; - strcpy(id_temp,arg[1]); - - int icompute = modify->find_compute(id_temp); - if (icompute < 0) error->all(FLERR,"Could not find fix_modify temp ID"); - temperature = modify->compute[icompute]; - - if (temperature->tempflag == 0) - error->all(FLERR,"Fix_modify temp ID does not compute temperature"); - inv_nTemp = 1.0/group->count(temperature->igroup); - - return 2; - } - -return 0; -} - -/* ---------------------------------------------------------------------- - * private method, to get the mass matrix for dynamic matrix - * --------------------------------------------------------------------*/ -void FixPhonon::getmass() -{ - int nlocal = atom->nlocal; - int *mask = atom->mask; - int *tag = atom->tag; - int *type = atom->type; - double *rmass = atom->rmass; - double *mass = atom->mass; - double *mass_one, *mass_all; - double *type_one, *type_all; - - mass_one = new double[nucell]; - mass_all = new double[nucell]; - type_one = new double[nucell]; - type_all = new double[nucell]; - for (int i = 0; i < nucell; ++i) mass_one[i] = type_one[i] = 0.; - - if (rmass){ - for (int i = 0; i < nlocal; ++i){ - if (mask[i] & groupbit){ - itag = tag[i]; - idx = tag2surf[itag]; - int iu = idx%nucell; - mass_one[iu] += rmass[i]; - type_one[iu] += double(type[i]); - } - } - } else { - for (int i = 0; i < nlocal; ++i){ - if (mask[i] & groupbit){ - itag = tag[i]; - idx = tag2surf[itag]; - int iu = idx%nucell; - mass_one[iu] += mass[type[i]]; - type_one[iu] += double(type[i]); - } - } - } - - MPI_Allreduce(mass_one,mass_all,nucell,MPI_DOUBLE,MPI_SUM,world); - MPI_Allreduce(type_one,type_all,nucell,MPI_DOUBLE,MPI_SUM,world); - - M_inv_sqrt = new double[nucell]; - basetype = new int[nucell]; - - double inv_total = 1./double(ntotal); - for (int i = 0; i < nucell; ++i){ - mass_all[i] *= inv_total; - M_inv_sqrt[i] = sqrt(1./mass_all[i]); - - basetype[i] = int(type_all[i]*inv_total); - } - delete []mass_one; - delete []mass_all; - delete []type_one; - delete []type_all; - -return; -} - - -/* ---------------------------------------------------------------------- - * private method, to read the mapping info from file - * --------------------------------------------------------------------*/ - -void FixPhonon::readmap() -{ - int info = 0; - - // auto-generate mapfile for "cluster" (gamma only system) - if (strcmp(mapfile, "GAMMA") == 0){ - nx = ny = nz = ntotal = 1; - nucell = ngroup; - - int *tag_loc, *tag_all; - memory->create(tag_loc,ngroup,"fix_phonon:tag_loc"); - memory->create(tag_all,ngroup,"fix_phonon:tag_all"); - - // get atom IDs on local proc - int nfind = 0; - for (int i = 0; i < atom->nlocal; ++i){ - if (atom->mask[i] & groupbit) tag_loc[nfind++] = atom->tag[i]; - } - - // gather IDs on local proc - displs[0] = 0; - for (int i = 0; i < nprocs; ++i) recvcnts[i] = 0; - MPI_Allgather(&nfind,1,MPI_INT,recvcnts,1,MPI_INT,world); - for (int i = 1; i < nprocs; ++i) displs[i] = displs[i-1] + recvcnts[i-1]; - - MPI_Allgatherv(tag_loc,nfind,MPI_INT,tag_all,recvcnts,displs,MPI_INT,world); - for (int i = 0; i < ngroup; ++i){ - itag = tag_all[i]; - tag2surf[itag] = i; - surf2tag[i] = itag; - } - - memory->destroy(tag_loc); - memory->destroy(tag_all); - return; - } - - // read from map file for others - char line[MAXLINE]; - FILE *fp = fopen(mapfile, "r"); - if (fp == NULL){ - sprintf(line,"Cannot open input map file %s", mapfile); - error->all(FLERR,line); - } - - if (fgets(line,MAXLINE,fp) == NULL) error->all(FLERR,"Error while reading header of mapping file!"); - nx = force->inumeric(FLERR, strtok(line, " \n\t\r\f")); - ny = force->inumeric(FLERR, strtok(NULL, " \n\t\r\f")); - nz = force->inumeric(FLERR, strtok(NULL, " \n\t\r\f")); - nucell = force->inumeric(FLERR, strtok(NULL, " \n\t\r\f")); - ntotal = nx*ny*nz; - if (ntotal*nucell != ngroup) error->all(FLERR,"FFT mesh and number of atoms in group mismatch!"); - - // second line of mapfile is comment - if (fgets(line,MAXLINE,fp) == NULL) error->all(FLERR,"Error while reading comment of mapping file!"); - - int ix, iy, iz, iu; - // the remaining lines carry the mapping info - for (int i = 0; i < ngroup; ++i){ - if (fgets(line,MAXLINE,fp) == NULL) {info = 1; break;} - ix = force->inumeric(FLERR, strtok(line, " \n\t\r\f")); - iy = force->inumeric(FLERR, strtok(NULL, " \n\t\r\f")); - iz = force->inumeric(FLERR, strtok(NULL, " \n\t\r\f")); - iu = force->inumeric(FLERR, strtok(NULL, " \n\t\r\f")); - itag = force->inumeric(FLERR, strtok(NULL, " \n\t\r\f")); - - // check if index is in correct range - if (ix < 0 || ix >= nx || iy < 0 || iy >= ny || iz < 0 || iz >= nz|| iu < 0 || iu >= nucell) {info = 2; break;} - // 1 <= itag <= natoms - if (itag < 1 || itag > static_cast(atom->natoms)) {info = 3; break;} - idx = ((ix*ny+iy)*nz+iz)*nucell + iu; - tag2surf[itag] = idx; - surf2tag[idx] = itag; - } - fclose(fp); - - if (tag2surf.size() != surf2tag.size() || tag2surf.size() != static_cast(ngroup) ) - error->all(FLERR,"The mapping is incomplete!"); - if (info) error->all(FLERR,"Error while reading mapping file!"); - - // check the correctness of mapping - int *mask = atom->mask; - int *tag = atom->tag; - int nlocal = atom->nlocal; - - for (int i = 0; i < nlocal; ++i) { - if (mask[i] & groupbit){ - itag = tag[i]; - idx = tag2surf[itag]; - if (itag != surf2tag[idx]) error->one(FLERR,"The mapping info read is incorrect!"); - } - } - -return; -} - -/* ---------------------------------------------------------------------- - * private method, to output the force constant matrix - * --------------------------------------------------------------------*/ -void FixPhonon::postprocess( ) -{ - if (neval < 1) return; - - ifreq = 0; - int idim, jdim, ndim; - double inv_neval = 1.0 /double(neval); - - // to get - for (idq = 0; idq < mynq; ++idq) - for (idim = 0; idim < fft_dim2; ++idim) Phi_q[idq][idim] = Rqsum[idq][idim]*inv_neval; - - // to get - for (idx = 0; idx < mynpt; ++idx) - for (idim = 0; idim < fft_dim; ++idim) Rnow[idx][idim] = Rsum[idx][idim] * inv_neval; - - // to get q - for (idim = 0; idim < fft_dim; ++idim){ - int m = 0; - for (idx = 0; idx < mynpt; ++idx){ - fft_data[m++] = Rnow[idx][idim]; - fft_data[m++] = 0.; - } - - fft->compute(fft_data,fft_data,-1); - - m = 0; - for (idq = 0; idq < mynq; ++idq){ - Rqnow[idq][idim] = std::complex(fft_data[m], fft_data[m+1]); - m += 2; - } - } - - // to get G(q) = - q.q - for (idq = 0; idq < mynq; ++idq){ - ndim = 0; - for (idim = 0; idim < fft_dim; ++idim) - for (jdim = 0; jdim < fft_dim; ++jdim) Phi_q[idq][ndim++] -= Rqnow[idq][idim]*conj(Rqnow[idq][jdim]); - } - - // to get Phi = KT.G^-1; normalization of FFTW data is done here - double boltz = force->boltz, kbtsqrt[sysdim], TempAve = 0.; - double TempFac = inv_neval*inv_nTemp; - double NormFac = TempFac*double(ntotal); - - for (idim = 0; idim < sysdim; ++idim){ - kbtsqrt[idim] = sqrt(TempSum[idim]*NormFac); - TempAve += TempSum[idim]*TempFac; - } - TempAve /= sysdim*boltz; - - for (idq = 0; idq < mynq; ++idq){ - GaussJordan(fft_dim, Phi_q[idq]); - ndim =0; - for (idim = 0; idim < fft_dim; ++idim) - for (jdim = 0; jdim < fft_dim; ++jdim) Phi_q[idq][ndim++] *= kbtsqrt[idim%sysdim]*kbtsqrt[jdim%sysdim]; - } - - // to collect all local Phi_q to root - displs[0]=0; - for (int i = 0; i < nprocs; ++i) recvcnts[i] = fft_cnts[i]*fft_dim*2; - for (int i = 1; i < nprocs; ++i) displs[i] = displs[i-1] + recvcnts[i-1]; - MPI_Gatherv(Phi_q[0],mynq*fft_dim2*2,MPI_DOUBLE,Phi_all[0],recvcnts,displs,MPI_DOUBLE,0,world); - - // to collect all basis info and averaged it on root - double basis_root[fft_dim]; - if (fft_dim > sysdim) MPI_Reduce(&basis[1][0], &basis_root[sysdim], fft_dim-sysdim, MPI_DOUBLE, MPI_SUM, 0, world); - - if (me == 0){ // output dynamic matrix by root - - // get basis info - for (idim = 0; idim < sysdim; ++idim) basis_root[idim] = 0.; - for (idim = sysdim; idim < fft_dim; ++idim) basis_root[idim] /= double(ntotal)*double(neval); - // get unit cell base vector info; might be incorrect if MD pbc and FixPhonon pbc mismatch. - double basevec[9]; - basevec[1] = basevec[2] = basevec[5] = 0.; - basevec[0] = hsum[0] * inv_neval / double(nx); - basevec[4] = hsum[1] * inv_neval / double(ny); - basevec[8] = hsum[2] * inv_neval / double(nz); - basevec[7] = hsum[3] * inv_neval / double(nz); - basevec[6] = hsum[4] * inv_neval / double(nz); - basevec[3] = hsum[5] * inv_neval / double(ny); - - // write binary file, in fact, it is the force constants matrix that is written - // Enforcement of ASR and the conversion of dynamical matrix is done in the postprocessing code - char fname[MAXLINE]; - sprintf(fname,"%s.bin." BIGINT_FORMAT,prefix,update->ntimestep); - FILE *fp_bin = fopen(fname,"wb"); - - fwrite(&sysdim, sizeof(int), 1, fp_bin); - fwrite(&nx, sizeof(int), 1, fp_bin); - fwrite(&ny, sizeof(int), 1, fp_bin); - fwrite(&nz, sizeof(int), 1, fp_bin); - fwrite(&nucell, sizeof(int), 1, fp_bin); - fwrite(&boltz, sizeof(double), 1, fp_bin); - - fwrite(Phi_all[0],sizeof(double),ntotal*fft_dim2*2,fp_bin); - - fwrite(&TempAve, sizeof(double),1, fp_bin); - fwrite(&basevec[0], sizeof(double),9, fp_bin); - fwrite(&basis_root[0],sizeof(double),fft_dim,fp_bin); - fwrite(basetype, sizeof(int), nucell, fp_bin); - fwrite(M_inv_sqrt, sizeof(double),nucell, fp_bin); - - fclose(fp_bin); - - // write log file, here however, it is the dynamical matrix that is written - for (int i = 0; i < 60; ++i) fprintf(flog,"#"); fprintf(flog,"\n"); - fprintf(flog, "# Current time step : " BIGINT_FORMAT "\n", update->ntimestep); - fprintf(flog, "# Total number of measurements : %d\n", neval); - fprintf(flog, "# Average temperature of the measurement : %lg\n", TempAve); - fprintf(flog, "# Boltzmann constant under current units : %lg\n", boltz); - fprintf(flog, "# basis vector A1 = [%lg %lg %lg]\n", basevec[0], basevec[1], basevec[2]); - fprintf(flog, "# basis vector A2 = [%lg %lg %lg]\n", basevec[3], basevec[4], basevec[5]); - fprintf(flog, "# basis vector A3 = [%lg %lg %lg]\n", basevec[6], basevec[7], basevec[8]); - for (int i = 0; i < 60; ++i) fprintf(flog,"#"); fprintf(flog,"\n"); - fprintf(flog, "# qx\t qy \t qz \t\t Phi(q)\n"); - - EnforceASR(); - - // to get D = 1/M x Phi - for (idq = 0; idq < ntotal; ++idq){ - ndim =0; - for (idim = 0; idim < fft_dim; ++idim) - for (jdim = 0; jdim < fft_dim; ++jdim) Phi_all[idq][ndim++] *= M_inv_sqrt[idim/sysdim]*M_inv_sqrt[jdim/sysdim]; - } - - idq =0; - for (int ix = 0; ix < nx; ++ix){ - double qx = double(ix)/double(nx); - for (int iy = 0; iy < ny; ++iy){ - double qy = double(iy)/double(ny); - for (int iz = 0; iz < nz; ++iz){ - double qz = double(iz)/double(nz); - fprintf(flog,"%lg %lg %lg", qx, qy, qz); - for (idim = 0; idim < fft_dim2; ++idim) fprintf(flog, " %lg %lg", real(Phi_all[idq][idim]), imag(Phi_all[idq][idim])); - fprintf(flog, "\n"); - ++idq; - } - } - } - fflush(flog); - } - -return; -} // end of postprocess - -/* ---------------------------------------------------------------------- - * private method, to get the inverse of a complex matrix by means of - * Gaussian-Jordan Elimination with full pivoting; square matrix required. - * - * Adapted from the Numerical Recipes in Fortran. - * --------------------------------------------------------------------*/ -void FixPhonon::GaussJordan(int n, std::complex *Mat) -{ - int i,icol,irow,j,k,l,ll,idr,idc; - int *indxc,*indxr,*ipiv; - double big, nmjk; - std::complex dum, pivinv; - - indxc = new int[n]; - indxr = new int[n]; - ipiv = new int[n]; - - for (i = 0; i < n; ++i) ipiv[i] = 0; - for (i = 0; i < n; ++i){ - big = 0.; - for (j = 0; j < n; ++j){ - if (ipiv[j] != 1){ - for (k = 0; k < n; ++k){ - if (ipiv[k] == 0){ - idr = j*n+k; - nmjk = norm(Mat[idr]); - if (nmjk >= big){ - big = nmjk; - irow = j; - icol = k; - } - } else if (ipiv[k] > 1) error->one(FLERR,"Singular matrix in complex GaussJordan!"); - } - } - } - ipiv[icol] += 1; - if (irow != icol){ - for (l = 0; l < n; ++l){ - idr = irow*n+l; - idc = icol*n+l; - dum = Mat[idr]; - Mat[idr] = Mat[idc]; - Mat[idc] = dum; - } - } - indxr[i] = irow; - indxc[i] = icol; - idr = icol*n+icol; - if (Mat[idr] == std::complex(0.,0.)) error->one(FLERR,"Singular matrix in complex GaussJordan!"); - - pivinv = 1./ Mat[idr]; - Mat[idr] = std::complex(1.,0.); - idr = icol*n; - for (l = 0; l < n; ++l) Mat[idr+l] *= pivinv; - for (ll = 0; ll < n; ++ll){ - if (ll != icol){ - idc = ll*n + icol; - dum = Mat[idc]; - Mat[idc] = 0.; - idc -= icol; - for (l = 0; l < n; ++l) Mat[idc+l] -= Mat[idr+l]*dum; - } - } - } - - for (l = n-1; l >= 0; --l){ - int rl = indxr[l]; - int cl = indxc[l]; - if (rl != cl){ - for (k = 0; k < n; ++k){ - idr = k*n + rl; - idc = k*n + cl; - dum = Mat[idr]; - Mat[idr] = Mat[idc]; - Mat[idc] = dum; - } - } - } - delete []indxr; - delete []indxc; - delete []ipiv; - -return; -} - -/* ---------------------------------------------------------------------- - * private method, to apply the acoustic sum rule on force constant matrix - * at gamma point. Should be executed on root only. - * --------------------------------------------------------------------*/ -void FixPhonon::EnforceASR() -{ - if (nasr < 1) return; - - for (int iit = 0; iit < nasr; ++iit){ - // simple ASR; the resultant matrix might not be symmetric - for (int a = 0; a < sysdim; ++a) - for (int b = 0; b < sysdim; ++b){ - for (int k = 0; k < nucell; ++k){ - double sum = 0.; - for (int kp = 0; kp < nucell; ++kp){ - int idx = (k*sysdim+a)*fft_dim + kp*sysdim + b; - sum += real(Phi_all[0][idx]); - } - sum /= double(nucell); - for (int kp = 0; kp < nucell; ++kp){ - int idx = (k*sysdim+a)*fft_dim + kp*sysdim + b; - real(Phi_all[0][idx]) -= sum; - } - } - } - - // symmetrize - for (int k = 0; k < nucell; ++k) - for (int kp = k; kp < nucell; ++kp){ - double csum = 0.; - for (int a = 0; a < sysdim; ++a) - for (int b = 0; b < sysdim; ++b){ - int idx = (k*sysdim+a)*fft_dim + kp*sysdim + b; - int jdx = (kp*sysdim+b)*fft_dim + k*sysdim + a; - csum = (real(Phi_all[0][idx])+real(Phi_all[0][jdx]))*0.5; - real(Phi_all[0][idx]) = real(Phi_all[0][jdx]) = csum; - } - } - } - - // symmetric ASR - for (int a = 0; a < sysdim; ++a) - for (int b = 0; b < sysdim; ++b){ - for (int k = 0; k < nucell; ++k){ - double sum = 0.; - for (int kp = 0; kp < nucell; ++kp){ - int idx = (k*sysdim+a)*fft_dim + kp*sysdim + b; - sum += real(Phi_all[0][idx]); - } - sum /= double(nucell-k); - for (int kp = k; kp < nucell; ++kp){ - int idx = (k*sysdim+a)*fft_dim + kp*sysdim + b; - int jdx = (kp*sysdim+b)*fft_dim + k*sysdim + a; - real(Phi_all[0][idx]) -= sum; - real(Phi_all[0][jdx]) = real(Phi_all[0][idx]); - } - } - } - -return; -} -/* --------------------------------------------------------------------*/ +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. +------------------------------------------------------------------------- */ +/* ---------------------------------------------------------------------- + Contributing authors: + Ling-Ti Kong + + Contact: + School of Materials Science and Engineering, + Shanghai Jiao Tong University, + 800 Dongchuan Road, Minhang, + Shanghai 200240, CHINA + + konglt@sjtu.edu.cn; konglt@gmail.com +------------------------------------------------------------------------- */ + +#include "string.h" +#include "fix_phonon.h" +#include "atom.h" +#include "compute.h" +#include "domain.h" +#include "fft3d_wrap.h" +#include "force.h" +#include "group.h" +#include "lattice.h" +#include "modify.h" +#include "update.h" +#include "citeme.h" +#include "memory.h" +#include "error.h" + +using namespace LAMMPS_NS; +using namespace FixConst; + +#define INVOKED_SCALAR 1 +#define INVOKED_VECTOR 2 +#define MAXLINE 512 + +static const char cite_fix_phonon[] = + "fix phonon command:\n\n" + "@Article{Kong11,\n" + " author = {L. T. Kong},\n" + " title = {Phonon dispersion measured directly from molecular dynamics simulations},\n" + " journal = {Comp.~Phys.~Comm.},\n" + " year = 2011,\n" + " volume = 182,\n" + " pages = {2201--2207}\n" + "}\n\n"; + +/* ---------------------------------------------------------------------- */ + +FixPhonon::FixPhonon(LAMMPS *lmp, int narg, char **arg) : Fix(lmp, narg, arg) +{ + if (lmp->citeme) lmp->citeme->add(cite_fix_phonon); + + MPI_Comm_rank(world,&me); + MPI_Comm_size(world,&nprocs); + + if (narg < 8) error->all(FLERR,"Illegal fix phonon command: number of arguments < 8"); + + nevery = force->inumeric(FLERR, arg[3]); // Calculate this fix every n steps! + if (nevery < 1) error->all(FLERR,"Illegal fix phonon command"); + + nfreq = force->inumeric(FLERR, arg[4]); // frequency to output result + if (nfreq < 1) error->all(FLERR,"Illegal fix phonon command"); + + waitsteps = ATOBIGINT(arg[5]); // Wait this many timesteps before actually measuring + if (waitsteps < 0) error->all(FLERR,"Illegal fix phonon command: waitsteps < 0 !"); + + int n = strlen(arg[6]) + 1; // map file + mapfile = new char[n]; + strcpy(mapfile, arg[6]); + + n = strlen(arg[7]) + 1; // prefix of output + prefix = new char[n]; + strcpy(prefix, arg[7]); + logfile = new char[n+4]; + sprintf(logfile,"%s.log",prefix); + + int sdim = sysdim = domain->dimension; + int iarg = 8; + nasr = 20; + + // other command line options + while (iarg < narg){ + if (strcmp(arg[iarg],"sysdim") == 0){ + if (++iarg >= narg) error->all(FLERR,"Illegal fix phonon command: incomplete command line options."); + sdim = force->inumeric(FLERR, arg[iarg]); + if (sdim < 1) error->all(FLERR,"Illegal fix phonon command: sysdim should not be less than 1."); + + } else if (strcmp(arg[iarg],"nasr") == 0){ + if (++iarg >= narg) error->all(FLERR,"Illegal fix phonon command: incomplete command line options."); + nasr = force->inumeric(FLERR, arg[iarg]); + + } else { + error->all(FLERR,"Illegal fix phonon command: unknown option read!"); + } + + ++iarg; + } + + // get the dimension of the simulation; 1D is possible by specifying the option of "sysdim 1" + if (sdim < sysdim) sysdim = sdim; + nasr = MAX(0, nasr); + + // get the total number of atoms in group + ngroup = static_cast(group->count(igroup)); + if (ngroup < 1) error->all(FLERR,"No atom found for fix phonon!"); + + // MPI gatherv related variables + recvcnts = new int[nprocs]; + displs = new int[nprocs]; + + // mapping index + tag2surf.clear(); // clear map info + surf2tag.clear(); + + // get the mapping between lattice indices and atom IDs + readmap(); delete []mapfile; + if (nucell == 1) nasr = MIN(1,nasr); + + // get the mass matrix for dynamic matrix + getmass(); + + // create FFT and allocate memory for FFT + // here the parallization is done on the x direction only + nxlo = 0; + int *nx_loc = new int [nprocs]; + for (int i = 0; i < nprocs; ++i){ + nx_loc[i] = nx/nprocs; + if (i < nx%nprocs) ++nx_loc[i]; + } + for (int i = 0; i < me; ++i) nxlo += nx_loc[i]; + nxhi = nxlo + nx_loc[me] - 1; + mynpt = nx_loc[me]*ny*nz; + mynq = mynpt; + + fft_dim = nucell*sysdim; + fft_dim2 = fft_dim*fft_dim; + fft_nsend = mynpt*fft_dim; + + fft_cnts = new int[nprocs]; + fft_disp = new int[nprocs]; + fft_disp[0] = 0; + for (int i = 0; i < nprocs; ++i) fft_cnts[i] = nx_loc[i]*ny*nz*fft_dim; + for (int i = 1; i < nprocs; ++i) fft_disp[i] = fft_disp[i-1]+fft_cnts[i-1]; + delete []nx_loc; + + fft = new FFT3d(lmp,world,nz,ny,nx,0,nz-1,0,ny-1,nxlo,nxhi,0,nz-1,0,ny-1,nxlo,nxhi,0,0,&mysize); + memory->create(fft_data, MAX(1,mynq)*2, "fix_phonon:fft_data"); + + // allocate variables; MAX(1,... is used because NULL buffer will result in error for MPI + memory->create(RIloc,ngroup,(sysdim+1),"fix_phonon:RIloc"); + memory->create(RIall,ngroup,(sysdim+1),"fix_phonon:RIall"); + memory->create(Rsort,ngroup, sysdim, "fix_phonon:Rsort"); + + memory->create(Rnow, MAX(1,mynpt),fft_dim,"fix_phonon:Rnow"); + memory->create(Rsum, MAX(1,mynpt),fft_dim,"fix_phonon:Rsum"); + + memory->create(basis,nucell, sysdim, "fix_phonon:basis"); + + // because of hermit, only nearly half of q points are stored + memory->create(Rqnow,MAX(1,mynq),fft_dim, "fix_phonon:Rqnow"); + memory->create(Rqsum,MAX(1,mynq),fft_dim2,"fix_phonon:Rqsum"); + memory->create(Phi_q,MAX(1,mynq),fft_dim2,"fix_phonon:Phi_q"); + + // variable to collect all local Phi to root + if (me == 0) memory->create(Phi_all,ntotal,fft_dim2,"fix_phonon:Phi_all"); + else memory->create(Phi_all,1,1,"fix_phonon:Phi_all"); + + // output some information on the system to log file + if (me == 0){ + flog = fopen(logfile, "w"); + if (flog == NULL) { + char str[MAXLINE]; + sprintf(str,"Can not open output file %s",logfile); + error->one(FLERR,str); + } + for (int i = 0; i < 60; ++i) fprintf(flog,"#"); fprintf(flog,"\n"); + fprintf(flog,"# group name of the atoms under study : %s\n", group->names[igroup]); + fprintf(flog,"# total number of atoms in the group : %d\n", ngroup); + fprintf(flog,"# dimension of the system : %d D\n", sysdim); + fprintf(flog,"# number of atoms per unit cell : %d\n", nucell); + fprintf(flog,"# dimension of the FFT mesh : %d x %d x %d\n", nx, ny, nz); + fprintf(flog,"# number of wait steps before measurement : " BIGINT_FORMAT "\n", waitsteps); + fprintf(flog,"# frequency of the measurement : %d\n", nevery); + fprintf(flog,"# output result after this many measurement: %d\n", nfreq); + fprintf(flog,"# number of processors used by this run : %d\n", nprocs); + for (int i = 0; i < 60; ++i) fprintf(flog,"#"); fprintf(flog,"\n"); + fprintf(flog,"# mapping information between lattice index and atom id\n"); + fprintf(flog,"# nx ny nz nucell\n"); + fprintf(flog,"%d %d %d %d\n", nx, ny, nz, nucell); + fprintf(flog,"# l1 l2 l3 k atom_id\n"); + int ix, iy, iz, iu; + for (idx = 0; idx < ngroup; ++idx){ + itag = surf2tag[idx]; + iu = idx%nucell; + iz = (idx/nucell)%nz; + iy = (idx/(nucell*nz))%ny; + ix = (idx/(nucell*nz*ny))%nx; + fprintf(flog,"%d %d %d %d %d\n", ix, iy, iz, iu, itag); + } + for (int i = 0; i < 60; ++i) fprintf(flog,"#"); fprintf(flog,"\n"); + fflush(flog); + } + surf2tag.clear(); + + // default temperature is from thermo + TempSum = new double[sysdim]; + id_temp = new char[12]; + strcpy(id_temp,"thermo_temp"); + int icompute = modify->find_compute(id_temp); + temperature = modify->compute[icompute]; + inv_nTemp = 1.0/group->count(temperature->igroup); + +return; +} // end of constructor + +/* ---------------------------------------------------------------------- */ + +void FixPhonon::post_run() +{ + // compute and output final results + if (ifreq > 0 && ifreq != nfreq) postprocess(); + if (me == 0) fclose(flog); +} + +/* ---------------------------------------------------------------------- */ + +FixPhonon::~FixPhonon() +{ + // delete locally stored array + memory->destroy(RIloc); + memory->destroy(RIall); + memory->destroy(Rsort); + memory->destroy(Rnow); + memory->destroy(Rsum); + + memory->destroy(basis); + + memory->destroy(Rqnow); + memory->destroy(Rqsum); + memory->destroy(Phi_q); + memory->destroy(Phi_all); + + delete []recvcnts; + delete []displs; + delete []prefix; + delete []logfile; + delete []fft_cnts; + delete []fft_disp; + delete []id_temp; + delete []TempSum; + delete []M_inv_sqrt; + delete []basetype; + + // destroy FFT + delete fft; + memory->sfree(fft_data); + + // clear map info + tag2surf.clear(); + surf2tag.clear(); + +} + +/* ---------------------------------------------------------------------- */ + +int FixPhonon::setmask() +{ + int mask = 0; + mask |= END_OF_STEP; + +return mask; +} + +/* ---------------------------------------------------------------------- */ + +void FixPhonon::init() +{ + // warn if more than one fix-phonon + int count = 0; + for (int i = 0; i < modify->nfix; ++i) if (strcmp(modify->fix[i]->style,"gfc") == 0) ++count; + if (count > 1 && me == 0) error->warning(FLERR,"More than one fix phonon defined"); // just warn, but allowed. + +return; +} + +/* ---------------------------------------------------------------------- */ + +void FixPhonon::setup(int flag) +{ + // initialize accumulating variables + for (int i = 0; i < sysdim; ++i) TempSum[i] = 0.; + + for (int i = 0; i < mynpt; ++i) + for (int j = 0; j < fft_dim; ++j) Rsum[i][j] = 0.; + + for (int i =0; i < mynq; ++i) + for (int j =0; j < fft_dim2; ++j) Rqsum[i][j] = std::complex (0.,0.); + + for (int i = 0; i < 6; ++i) hsum[i] = 0.; + + for (int i = 0; i < nucell; ++i) + for (int j = 0; j < sysdim; ++j) basis[i][j] = 0.; + + prev_nstep = update->ntimestep; + neval = ifreq = 0; + +return; +} + +/* ---------------------------------------------------------------------- */ + +void FixPhonon::end_of_step() +{ + if ( (update->ntimestep-prev_nstep) <= waitsteps) return; + + double **x = atom->x; + int *mask = atom->mask; + int *tag = atom->tag; + int *image = atom->image; + int nlocal = atom->nlocal; + + double xprd = domain->xprd; + double yprd = domain->yprd; + double zprd = domain->zprd; + double *h = domain->h; + double xbox, ybox, zbox; + + int i,idim,jdim,ndim; + double xcur[3]; + + // to get the current temperature + if (!(temperature->invoked_flag & INVOKED_VECTOR)) temperature->compute_vector(); + for (idim = 0; idim < sysdim; ++idim) TempSum[idim] += temperature->vector[idim]; + + // evaluate R(r) on local proc + nfind = 0; + for (i = 0; i < nlocal; ++i){ + if (mask[i] & groupbit){ + itag = tag[i]; + idx = tag2surf[itag]; + + domain->unmap(x[i], image[i], xcur); + + for (idim = 0; idim < sysdim; ++idim) RIloc[nfind][idim] = xcur[idim]; + RIloc[nfind++][sysdim] = double(idx); + } + } + + // gather R(r) on local proc, then sort and redistribute to all procs for FFT + nfind *= (sysdim+1); + displs[0] = 0; + for (i = 0; i < nprocs; ++i) recvcnts[i] = 0; + MPI_Gather(&nfind,1,MPI_INT,recvcnts,1,MPI_INT,0,world); + for (i = 1; i < nprocs; ++i) displs[i] = displs[i-1] + recvcnts[i-1]; + + MPI_Gatherv(RIloc[0],nfind,MPI_DOUBLE,RIall[0],recvcnts,displs,MPI_DOUBLE,0,world); + if (me == 0){ + for (i = 0; i < ngroup; ++i){ + idx = static_cast(RIall[i][sysdim]); + for (idim = 0; idim < sysdim; ++idim) Rsort[idx][idim] = RIall[i][idim]; + } + } + MPI_Scatterv(Rsort[0],fft_cnts,fft_disp, MPI_DOUBLE, Rnow[0], fft_nsend, MPI_DOUBLE,0,world); + + // get Rsum + for (idx = 0; idx < mynpt; ++idx) + for (idim = 0; idim < fft_dim; ++idim) Rsum[idx][idim] += Rnow[idx][idim]; + + // FFT R(r) to get R(q) + for (idim = 0; idim < fft_dim; ++idim){ + int m=0; + for (idx = 0; idx < mynpt; ++idx){ + fft_data[m++] = Rnow[idx][idim]; + fft_data[m++] = 0.; + } + + fft->compute(fft_data, fft_data, -1); + + m = 0; + for (idq = 0; idq < mynq; ++idq){ + Rqnow[idq][idim] = std::complex(fft_data[m], fft_data[m+1]); + m += 2; + } + } + + // to get sum(R(q).R(q)*) + for (idq = 0; idq < mynq; ++idq){ + ndim = 0; + for (idim = 0; idim < fft_dim; ++idim) + for (jdim = 0; jdim < fft_dim; ++jdim) Rqsum[idq][ndim++] += Rqnow[idq][idim]*conj(Rqnow[idq][jdim]); + } + + // get basis info + if (fft_dim > sysdim){ + double dist2orig[3]; + for (idx = 0; idx < mynpt; ++idx){ + ndim = sysdim; + for (i = 1; i < nucell; ++i){ + for (idim = 0; idim < sysdim; ++idim) dist2orig[idim] = Rnow[idx][ndim++] - Rnow[idx][idim]; + domain->minimum_image(dist2orig); + for (idim = 0; idim < sysdim; ++idim) basis[i][idim] += dist2orig[idim]; + } + } + } + // get lattice vector info + for (int i = 0; i < 6; ++i) hsum[i] += h[i]; + + // increment counter + ++neval; + + // compute and output Phi_q after every nfreq evaluations + if (++ifreq == nfreq) postprocess(); + +return; +} // end of end_of_step() + +/* ---------------------------------------------------------------------- */ + +double FixPhonon::memory_usage() +{ + double bytes = sizeof(double)*2*mynq + + sizeof(std::map)*2*ngroup + + sizeof(double)*(ngroup*(3*sysdim+2)+mynpt*fft_dim*2) + + sizeof(std::complex)*MAX(1,mynq)*fft_dim *(1+2*fft_dim) + + sizeof(std::complex)*ntotal*fft_dim2 + + sizeof(int) * nprocs * 4; + return bytes; +} + +/* ---------------------------------------------------------------------- */ + +int FixPhonon::modify_param(int narg, char **arg) +{ + if (strcmp(arg[0],"temp") == 0) { + if (narg < 2) error->all(FLERR,"Illegal fix_modify command"); + delete [] id_temp; + int n = strlen(arg[1]) + 1; + id_temp = new char[n]; + strcpy(id_temp,arg[1]); + + int icompute = modify->find_compute(id_temp); + if (icompute < 0) error->all(FLERR,"Could not find fix_modify temp ID"); + temperature = modify->compute[icompute]; + + if (temperature->tempflag == 0) + error->all(FLERR,"Fix_modify temp ID does not compute temperature"); + inv_nTemp = 1.0/group->count(temperature->igroup); + + return 2; + } + +return 0; +} + +/* ---------------------------------------------------------------------- + * private method, to get the mass matrix for dynamic matrix + * --------------------------------------------------------------------*/ +void FixPhonon::getmass() +{ + int nlocal = atom->nlocal; + int *mask = atom->mask; + int *tag = atom->tag; + int *type = atom->type; + double *rmass = atom->rmass; + double *mass = atom->mass; + double *mass_one, *mass_all; + double *type_one, *type_all; + + mass_one = new double[nucell]; + mass_all = new double[nucell]; + type_one = new double[nucell]; + type_all = new double[nucell]; + for (int i = 0; i < nucell; ++i) mass_one[i] = type_one[i] = 0.; + + if (rmass){ + for (int i = 0; i < nlocal; ++i){ + if (mask[i] & groupbit){ + itag = tag[i]; + idx = tag2surf[itag]; + int iu = idx%nucell; + mass_one[iu] += rmass[i]; + type_one[iu] += double(type[i]); + } + } + } else { + for (int i = 0; i < nlocal; ++i){ + if (mask[i] & groupbit){ + itag = tag[i]; + idx = tag2surf[itag]; + int iu = idx%nucell; + mass_one[iu] += mass[type[i]]; + type_one[iu] += double(type[i]); + } + } + } + + MPI_Allreduce(mass_one,mass_all,nucell,MPI_DOUBLE,MPI_SUM,world); + MPI_Allreduce(type_one,type_all,nucell,MPI_DOUBLE,MPI_SUM,world); + + M_inv_sqrt = new double[nucell]; + basetype = new int[nucell]; + + double inv_total = 1./double(ntotal); + for (int i = 0; i < nucell; ++i){ + mass_all[i] *= inv_total; + M_inv_sqrt[i] = sqrt(1./mass_all[i]); + + basetype[i] = int(type_all[i]*inv_total); + } + delete []mass_one; + delete []mass_all; + delete []type_one; + delete []type_all; + +return; +} + + +/* ---------------------------------------------------------------------- + * private method, to read the mapping info from file + * --------------------------------------------------------------------*/ + +void FixPhonon::readmap() +{ + int info = 0; + + // auto-generate mapfile for "cluster" (gamma only system) + if (strcmp(mapfile, "GAMMA") == 0){ + nx = ny = nz = ntotal = 1; + nucell = ngroup; + + int *tag_loc, *tag_all; + memory->create(tag_loc,ngroup,"fix_phonon:tag_loc"); + memory->create(tag_all,ngroup,"fix_phonon:tag_all"); + + // get atom IDs on local proc + int nfind = 0; + for (int i = 0; i < atom->nlocal; ++i){ + if (atom->mask[i] & groupbit) tag_loc[nfind++] = atom->tag[i]; + } + + // gather IDs on local proc + displs[0] = 0; + for (int i = 0; i < nprocs; ++i) recvcnts[i] = 0; + MPI_Allgather(&nfind,1,MPI_INT,recvcnts,1,MPI_INT,world); + for (int i = 1; i < nprocs; ++i) displs[i] = displs[i-1] + recvcnts[i-1]; + + MPI_Allgatherv(tag_loc,nfind,MPI_INT,tag_all,recvcnts,displs,MPI_INT,world); + for (int i = 0; i < ngroup; ++i){ + itag = tag_all[i]; + tag2surf[itag] = i; + surf2tag[i] = itag; + } + + memory->destroy(tag_loc); + memory->destroy(tag_all); + return; + } + + // read from map file for others + char line[MAXLINE]; + FILE *fp = fopen(mapfile, "r"); + if (fp == NULL){ + sprintf(line,"Cannot open input map file %s", mapfile); + error->all(FLERR,line); + } + + if (fgets(line,MAXLINE,fp) == NULL) error->all(FLERR,"Error while reading header of mapping file!"); + nx = force->inumeric(FLERR, strtok(line, " \n\t\r\f")); + ny = force->inumeric(FLERR, strtok(NULL, " \n\t\r\f")); + nz = force->inumeric(FLERR, strtok(NULL, " \n\t\r\f")); + nucell = force->inumeric(FLERR, strtok(NULL, " \n\t\r\f")); + ntotal = nx*ny*nz; + if (ntotal*nucell != ngroup) error->all(FLERR,"FFT mesh and number of atoms in group mismatch!"); + + // second line of mapfile is comment + if (fgets(line,MAXLINE,fp) == NULL) error->all(FLERR,"Error while reading comment of mapping file!"); + + int ix, iy, iz, iu; + // the remaining lines carry the mapping info + for (int i = 0; i < ngroup; ++i){ + if (fgets(line,MAXLINE,fp) == NULL) {info = 1; break;} + ix = force->inumeric(FLERR, strtok(line, " \n\t\r\f")); + iy = force->inumeric(FLERR, strtok(NULL, " \n\t\r\f")); + iz = force->inumeric(FLERR, strtok(NULL, " \n\t\r\f")); + iu = force->inumeric(FLERR, strtok(NULL, " \n\t\r\f")); + itag = force->inumeric(FLERR, strtok(NULL, " \n\t\r\f")); + + // check if index is in correct range + if (ix < 0 || ix >= nx || iy < 0 || iy >= ny || iz < 0 || iz >= nz|| iu < 0 || iu >= nucell) {info = 2; break;} + // 1 <= itag <= natoms + if (itag < 1 || itag > static_cast(atom->natoms)) {info = 3; break;} + idx = ((ix*ny+iy)*nz+iz)*nucell + iu; + tag2surf[itag] = idx; + surf2tag[idx] = itag; + } + fclose(fp); + + if (tag2surf.size() != surf2tag.size() || tag2surf.size() != static_cast(ngroup) ) + error->all(FLERR,"The mapping is incomplete!"); + if (info) error->all(FLERR,"Error while reading mapping file!"); + + // check the correctness of mapping + int *mask = atom->mask; + int *tag = atom->tag; + int nlocal = atom->nlocal; + + for (int i = 0; i < nlocal; ++i) { + if (mask[i] & groupbit){ + itag = tag[i]; + idx = tag2surf[itag]; + if (itag != surf2tag[idx]) error->one(FLERR,"The mapping info read is incorrect!"); + } + } + +return; +} + +/* ---------------------------------------------------------------------- + * private method, to output the force constant matrix + * --------------------------------------------------------------------*/ +void FixPhonon::postprocess( ) +{ + if (neval < 1) return; + + ifreq = 0; + int idim, jdim, ndim; + double inv_neval = 1.0 /double(neval); + + // to get + for (idq = 0; idq < mynq; ++idq) + for (idim = 0; idim < fft_dim2; ++idim) Phi_q[idq][idim] = Rqsum[idq][idim]*inv_neval; + + // to get + for (idx = 0; idx < mynpt; ++idx) + for (idim = 0; idim < fft_dim; ++idim) Rnow[idx][idim] = Rsum[idx][idim] * inv_neval; + + // to get q + for (idim = 0; idim < fft_dim; ++idim){ + int m = 0; + for (idx = 0; idx < mynpt; ++idx){ + fft_data[m++] = Rnow[idx][idim]; + fft_data[m++] = 0.; + } + + fft->compute(fft_data,fft_data,-1); + + m = 0; + for (idq = 0; idq < mynq; ++idq){ + Rqnow[idq][idim] = std::complex(fft_data[m], fft_data[m+1]); + m += 2; + } + } + + // to get G(q) = - q.q + for (idq = 0; idq < mynq; ++idq){ + ndim = 0; + for (idim = 0; idim < fft_dim; ++idim) + for (jdim = 0; jdim < fft_dim; ++jdim) Phi_q[idq][ndim++] -= Rqnow[idq][idim]*conj(Rqnow[idq][jdim]); + } + + // to get Phi = KT.G^-1; normalization of FFTW data is done here + double boltz = force->boltz, kbtsqrt[sysdim], TempAve = 0.; + double TempFac = inv_neval*inv_nTemp; + double NormFac = TempFac*double(ntotal); + + for (idim = 0; idim < sysdim; ++idim){ + kbtsqrt[idim] = sqrt(TempSum[idim]*NormFac); + TempAve += TempSum[idim]*TempFac; + } + TempAve /= sysdim*boltz; + + for (idq = 0; idq < mynq; ++idq){ + GaussJordan(fft_dim, Phi_q[idq]); + ndim =0; + for (idim = 0; idim < fft_dim; ++idim) + for (jdim = 0; jdim < fft_dim; ++jdim) Phi_q[idq][ndim++] *= kbtsqrt[idim%sysdim]*kbtsqrt[jdim%sysdim]; + } + + // to collect all local Phi_q to root + displs[0]=0; + for (int i = 0; i < nprocs; ++i) recvcnts[i] = fft_cnts[i]*fft_dim*2; + for (int i = 1; i < nprocs; ++i) displs[i] = displs[i-1] + recvcnts[i-1]; + MPI_Gatherv(Phi_q[0],mynq*fft_dim2*2,MPI_DOUBLE,Phi_all[0],recvcnts,displs,MPI_DOUBLE,0,world); + + // to collect all basis info and averaged it on root + double basis_root[fft_dim]; + if (fft_dim > sysdim) MPI_Reduce(&basis[1][0], &basis_root[sysdim], fft_dim-sysdim, MPI_DOUBLE, MPI_SUM, 0, world); + + if (me == 0){ // output dynamic matrix by root + + // get basis info + for (idim = 0; idim < sysdim; ++idim) basis_root[idim] = 0.; + for (idim = sysdim; idim < fft_dim; ++idim) basis_root[idim] /= double(ntotal)*double(neval); + // get unit cell base vector info; might be incorrect if MD pbc and FixPhonon pbc mismatch. + double basevec[9]; + basevec[1] = basevec[2] = basevec[5] = 0.; + basevec[0] = hsum[0] * inv_neval / double(nx); + basevec[4] = hsum[1] * inv_neval / double(ny); + basevec[8] = hsum[2] * inv_neval / double(nz); + basevec[7] = hsum[3] * inv_neval / double(nz); + basevec[6] = hsum[4] * inv_neval / double(nz); + basevec[3] = hsum[5] * inv_neval / double(ny); + + // write binary file, in fact, it is the force constants matrix that is written + // Enforcement of ASR and the conversion of dynamical matrix is done in the postprocessing code + char fname[MAXLINE]; + sprintf(fname,"%s.bin." BIGINT_FORMAT,prefix,update->ntimestep); + FILE *fp_bin = fopen(fname,"wb"); + + fwrite(&sysdim, sizeof(int), 1, fp_bin); + fwrite(&nx, sizeof(int), 1, fp_bin); + fwrite(&ny, sizeof(int), 1, fp_bin); + fwrite(&nz, sizeof(int), 1, fp_bin); + fwrite(&nucell, sizeof(int), 1, fp_bin); + fwrite(&boltz, sizeof(double), 1, fp_bin); + + fwrite(Phi_all[0],sizeof(double),ntotal*fft_dim2*2,fp_bin); + + fwrite(&TempAve, sizeof(double),1, fp_bin); + fwrite(&basevec[0], sizeof(double),9, fp_bin); + fwrite(&basis_root[0],sizeof(double),fft_dim,fp_bin); + fwrite(basetype, sizeof(int), nucell, fp_bin); + fwrite(M_inv_sqrt, sizeof(double),nucell, fp_bin); + + fclose(fp_bin); + + // write log file, here however, it is the dynamical matrix that is written + for (int i = 0; i < 60; ++i) fprintf(flog,"#"); fprintf(flog,"\n"); + fprintf(flog, "# Current time step : " BIGINT_FORMAT "\n", update->ntimestep); + fprintf(flog, "# Total number of measurements : %d\n", neval); + fprintf(flog, "# Average temperature of the measurement : %lg\n", TempAve); + fprintf(flog, "# Boltzmann constant under current units : %lg\n", boltz); + fprintf(flog, "# basis vector A1 = [%lg %lg %lg]\n", basevec[0], basevec[1], basevec[2]); + fprintf(flog, "# basis vector A2 = [%lg %lg %lg]\n", basevec[3], basevec[4], basevec[5]); + fprintf(flog, "# basis vector A3 = [%lg %lg %lg]\n", basevec[6], basevec[7], basevec[8]); + for (int i = 0; i < 60; ++i) fprintf(flog,"#"); fprintf(flog,"\n"); + fprintf(flog, "# qx\t qy \t qz \t\t Phi(q)\n"); + + EnforceASR(); + + // to get D = 1/M x Phi + for (idq = 0; idq < ntotal; ++idq){ + ndim =0; + for (idim = 0; idim < fft_dim; ++idim) + for (jdim = 0; jdim < fft_dim; ++jdim) Phi_all[idq][ndim++] *= M_inv_sqrt[idim/sysdim]*M_inv_sqrt[jdim/sysdim]; + } + + idq =0; + for (int ix = 0; ix < nx; ++ix){ + double qx = double(ix)/double(nx); + for (int iy = 0; iy < ny; ++iy){ + double qy = double(iy)/double(ny); + for (int iz = 0; iz < nz; ++iz){ + double qz = double(iz)/double(nz); + fprintf(flog,"%lg %lg %lg", qx, qy, qz); + for (idim = 0; idim < fft_dim2; ++idim) fprintf(flog, " %lg %lg", real(Phi_all[idq][idim]), imag(Phi_all[idq][idim])); + fprintf(flog, "\n"); + ++idq; + } + } + } + fflush(flog); + } + +return; +} // end of postprocess + +/* ---------------------------------------------------------------------- + * private method, to get the inverse of a complex matrix by means of + * Gaussian-Jordan Elimination with full pivoting; square matrix required. + * + * Adapted from the Numerical Recipes in Fortran. + * --------------------------------------------------------------------*/ +void FixPhonon::GaussJordan(int n, std::complex *Mat) +{ + int i,icol,irow,j,k,l,ll,idr,idc; + int *indxc,*indxr,*ipiv; + double big, nmjk; + std::complex dum, pivinv; + + indxc = new int[n]; + indxr = new int[n]; + ipiv = new int[n]; + + for (i = 0; i < n; ++i) ipiv[i] = 0; + for (i = 0; i < n; ++i){ + big = 0.; + for (j = 0; j < n; ++j){ + if (ipiv[j] != 1){ + for (k = 0; k < n; ++k){ + if (ipiv[k] == 0){ + idr = j*n+k; + nmjk = norm(Mat[idr]); + if (nmjk >= big){ + big = nmjk; + irow = j; + icol = k; + } + } else if (ipiv[k] > 1) error->one(FLERR,"Singular matrix in complex GaussJordan!"); + } + } + } + ipiv[icol] += 1; + if (irow != icol){ + for (l = 0; l < n; ++l){ + idr = irow*n+l; + idc = icol*n+l; + dum = Mat[idr]; + Mat[idr] = Mat[idc]; + Mat[idc] = dum; + } + } + indxr[i] = irow; + indxc[i] = icol; + idr = icol*n+icol; + if (Mat[idr] == std::complex(0.,0.)) error->one(FLERR,"Singular matrix in complex GaussJordan!"); + + pivinv = 1./ Mat[idr]; + Mat[idr] = std::complex(1.,0.); + idr = icol*n; + for (l = 0; l < n; ++l) Mat[idr+l] *= pivinv; + for (ll = 0; ll < n; ++ll){ + if (ll != icol){ + idc = ll*n + icol; + dum = Mat[idc]; + Mat[idc] = 0.; + idc -= icol; + for (l = 0; l < n; ++l) Mat[idc+l] -= Mat[idr+l]*dum; + } + } + } + + for (l = n-1; l >= 0; --l){ + int rl = indxr[l]; + int cl = indxc[l]; + if (rl != cl){ + for (k = 0; k < n; ++k){ + idr = k*n + rl; + idc = k*n + cl; + dum = Mat[idr]; + Mat[idr] = Mat[idc]; + Mat[idc] = dum; + } + } + } + delete []indxr; + delete []indxc; + delete []ipiv; + +return; +} + +/* ---------------------------------------------------------------------- + * private method, to apply the acoustic sum rule on force constant matrix + * at gamma point. Should be executed on root only. + * --------------------------------------------------------------------*/ +void FixPhonon::EnforceASR() +{ + if (nasr < 1) return; + + for (int iit = 0; iit < nasr; ++iit){ + // simple ASR; the resultant matrix might not be symmetric + for (int a = 0; a < sysdim; ++a) + for (int b = 0; b < sysdim; ++b){ + for (int k = 0; k < nucell; ++k){ + double sum = 0.; + for (int kp = 0; kp < nucell; ++kp){ + int idx = (k*sysdim+a)*fft_dim + kp*sysdim + b; + sum += real(Phi_all[0][idx]); + } + sum /= double(nucell); + for (int kp = 0; kp < nucell; ++kp){ + int idx = (k*sysdim+a)*fft_dim + kp*sysdim + b; + real(Phi_all[0][idx]) -= sum; + } + } + } + + // symmetrize + for (int k = 0; k < nucell; ++k) + for (int kp = k; kp < nucell; ++kp){ + double csum = 0.; + for (int a = 0; a < sysdim; ++a) + for (int b = 0; b < sysdim; ++b){ + int idx = (k*sysdim+a)*fft_dim + kp*sysdim + b; + int jdx = (kp*sysdim+b)*fft_dim + k*sysdim + a; + csum = (real(Phi_all[0][idx])+real(Phi_all[0][jdx]))*0.5; + real(Phi_all[0][idx]) = real(Phi_all[0][jdx]) = csum; + } + } + } + + // symmetric ASR + for (int a = 0; a < sysdim; ++a) + for (int b = 0; b < sysdim; ++b){ + for (int k = 0; k < nucell; ++k){ + double sum = 0.; + for (int kp = 0; kp < nucell; ++kp){ + int idx = (k*sysdim+a)*fft_dim + kp*sysdim + b; + sum += real(Phi_all[0][idx]); + } + sum /= double(nucell-k); + for (int kp = k; kp < nucell; ++kp){ + int idx = (k*sysdim+a)*fft_dim + kp*sysdim + b; + int jdx = (kp*sysdim+b)*fft_dim + k*sysdim + a; + real(Phi_all[0][idx]) -= sum; + real(Phi_all[0][jdx]) = real(Phi_all[0][idx]); + } + } + } + +return; +} +/* --------------------------------------------------------------------*/ diff --git a/src/USER-PHONON/fix_phonon.h b/src/USER-PHONON/fix_phonon.h index 96bc04b91..e9e0aa79a 100644 --- a/src/USER-PHONON/fix_phonon.h +++ b/src/USER-PHONON/fix_phonon.h @@ -1,185 +1,185 @@ -/* ---------------------------------------------------------------------- - LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator - www.cs.sandia.gov/~sjplimp/lammps.html - Steve Plimpton, sjplimp@sandia.gov, Sandia National Laboratories - - Copyright (2003) Sandia Corporation. Under the terms of Contract - DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains - certain rights in this software. This software is distributed under - the GNU General Public License. - - See the README file in the top-level LAMMPS directory. -------------------------------------------------------------------------- */ -/* ---------------------------------------------------------------------- - Contributing authors: - Ling-Ti Kong - - Contact: - School of Materials Science and Engineering, - Shanghai Jiao Tong University, - 800 Dongchuan Road, Minhang, - Shanghai 200240, CHINA - - konglt@sjtu.edu.cn; konglt@gmail.com -------------------------------------------------------------------------- */ -#ifdef FIX_CLASS - -FixStyle(phonon,FixPhonon) - -#else - -#ifndef FIX_PHONON_H -#define FIX_PHONON_H - -#include -#include "fix.h" -#include -#include "stdio.h" -#include "stdlib.h" -#include "string.h" - -namespace LAMMPS_NS { - -class FixPhonon : public Fix { - public: - FixPhonon(class LAMMPS *, int, char **); - ~FixPhonon(); - - int setmask(); - void init(); - void setup(int); - void end_of_step(); - void post_run(); - double memory_usage(); - int modify_param(int, char **); - - private: - int me,nprocs; - bigint waitsteps; // wait these number of timesteps before recording atom positions - bigint prev_nstep; // number of steps from previous run(s); to judge if waitsteps is reached. - int nfreq, ifreq; // after this number of measurement (nfreq), the result will be output once - int nx,ny,nz,nucell,ntotal; // surface dimensions in x- and y-direction, number of atom per unit surface cell - int neval; // # of evaluations - int sysdim; // system dimension - int ngroup, nfind; // total number of atoms in group; total number of atoms on this proc - char *prefix, *logfile; // prefix of output file names - FILE *flog; - - double *M_inv_sqrt; - - class FFT3d *fft; // to do fft via the fft3d wraper - int nxlo,nxhi,mysize; // size info for local MPI_FFTW - int mynpt,mynq,fft_nsend; - int *fft_cnts, *fft_disp; - int fft_dim, fft_dim2; - double *fft_data; - - int itag, idx, idq; // index variables - std::map tag2surf, surf2tag; // Mapping info - - double **RIloc; // R(r) and index on local proc - double **RIall; // gathered R(r) and index - double **Rsort; // sorted R(r) - double **Rnow; // Current R(r) on local proc - double **Rsum; // Accumulated R(r) on local proc - - int *recvcnts, *displs; // MPI related variables - - std::complex **Rqnow; // Current R(q) on local proc - std::complex **Rqsum; // Accumulator for conj(R(q)_alpha)*R(q)_beta - std::complex **Phi_q; // Phi's on local proc - std::complex **Phi_all; // Phi for all - - void readmap(); // to read the mapping of gf atoms - char *mapfile; // file name of the map file - - void getmass(); // to get the mass of each atom in a unit cell - - int nasr; - void postprocess(); // to post process the data - void EnforceASR(); // to apply acoustic sum rule to gamma point force constant matrix - - char *id_temp; // compute id for temperature - double *TempSum; // to get the average temperature vector - double inv_nTemp; // inverse of number of atoms in temperature group - class Compute *temperature; // compute that computes the temperature - - double hsum[6], **basis; - int *basetype; - - // private methods to do matrix inversion - void GaussJordan(int, std::complex*); - -}; -} -#endif -#endif - -/* ERROR/WARNING messages: - -E: Illegal fix phonon command... - -Self-explanatory. Check the input script syntax and compare to the -documentation for the command. You can use -echo screen as a -command-line option when running LAMMPS to see the offending line. - -E: No atom found for fix phonon! - -Self-explanatory. Number of atoms in the group that was passed to -fix-phonon is less than 1. - -E: Can not open output file %s" - -Self-explanatory. - -E: Illegal fix_modify command - -Self-explanatory. - -E: Could not find fix_modify temp ID - -Self-explanatory. - -E: Fix_modify temp ID does not compute temperature - -Self-explanatory. - -E: Cannot open input map file %s - -Self-explanatory. - -E: Error while reading header of mapping file! - -Self-explanatory. The first line of the map file is expected to -contain 4 positive integer numbers. - -E: FFT mesh and number of atoms in group mismatch! - -Self-explanatory. The product of the 4 numbers should be exactly the -total number of atoms in the group that was passed to fix-phonon. - -E: Error while reading comment of mapping file! - -Self-explanatory. The second line of the map file should be a comment line. - -E: The mapping is incomplete! - -Self-explanatory. - -E: Error while reading mapping file! - -Self-explanatory. - -E: The mapping info read is incorrect! - -Self-explanatory. - -E: Singular matrix in complex GaussJordan! - -Self-explanatory. - -W: More than one fix phonon defined - -Self-explanatory. Just to warn that more than one fix-phonon is defined, but allowed. - -*/ +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + www.cs.sandia.gov/~sjplimp/lammps.html + Steve Plimpton, sjplimp@sandia.gov, Sandia National Laboratories + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. +------------------------------------------------------------------------- */ +/* ---------------------------------------------------------------------- + Contributing authors: + Ling-Ti Kong + + Contact: + School of Materials Science and Engineering, + Shanghai Jiao Tong University, + 800 Dongchuan Road, Minhang, + Shanghai 200240, CHINA + + konglt@sjtu.edu.cn; konglt@gmail.com +------------------------------------------------------------------------- */ +#ifdef FIX_CLASS + +FixStyle(phonon,FixPhonon) + +#else + +#ifndef FIX_PHONON_H +#define FIX_PHONON_H + +#include +#include "fix.h" +#include +#include "stdio.h" +#include "stdlib.h" +#include "string.h" + +namespace LAMMPS_NS { + +class FixPhonon : public Fix { + public: + FixPhonon(class LAMMPS *, int, char **); + ~FixPhonon(); + + int setmask(); + void init(); + void setup(int); + void end_of_step(); + void post_run(); + double memory_usage(); + int modify_param(int, char **); + + private: + int me,nprocs; + bigint waitsteps; // wait these number of timesteps before recording atom positions + bigint prev_nstep; // number of steps from previous run(s); to judge if waitsteps is reached. + int nfreq, ifreq; // after this number of measurement (nfreq), the result will be output once + int nx,ny,nz,nucell,ntotal; // surface dimensions in x- and y-direction, number of atom per unit surface cell + int neval; // # of evaluations + int sysdim; // system dimension + int ngroup, nfind; // total number of atoms in group; total number of atoms on this proc + char *prefix, *logfile; // prefix of output file names + FILE *flog; + + double *M_inv_sqrt; + + class FFT3d *fft; // to do fft via the fft3d wraper + int nxlo,nxhi,mysize; // size info for local MPI_FFTW + int mynpt,mynq,fft_nsend; + int *fft_cnts, *fft_disp; + int fft_dim, fft_dim2; + double *fft_data; + + int itag, idx, idq; // index variables + std::map tag2surf, surf2tag; // Mapping info + + double **RIloc; // R(r) and index on local proc + double **RIall; // gathered R(r) and index + double **Rsort; // sorted R(r) + double **Rnow; // Current R(r) on local proc + double **Rsum; // Accumulated R(r) on local proc + + int *recvcnts, *displs; // MPI related variables + + std::complex **Rqnow; // Current R(q) on local proc + std::complex **Rqsum; // Accumulator for conj(R(q)_alpha)*R(q)_beta + std::complex **Phi_q; // Phi's on local proc + std::complex **Phi_all; // Phi for all + + void readmap(); // to read the mapping of gf atoms + char *mapfile; // file name of the map file + + void getmass(); // to get the mass of each atom in a unit cell + + int nasr; + void postprocess(); // to post process the data + void EnforceASR(); // to apply acoustic sum rule to gamma point force constant matrix + + char *id_temp; // compute id for temperature + double *TempSum; // to get the average temperature vector + double inv_nTemp; // inverse of number of atoms in temperature group + class Compute *temperature; // compute that computes the temperature + + double hsum[6], **basis; + int *basetype; + + // private methods to do matrix inversion + void GaussJordan(int, std::complex*); + +}; +} +#endif +#endif + +/* ERROR/WARNING messages: + +E: Illegal fix phonon command... + +Self-explanatory. Check the input script syntax and compare to the +documentation for the command. You can use -echo screen as a +command-line option when running LAMMPS to see the offending line. + +E: No atom found for fix phonon! + +Self-explanatory. Number of atoms in the group that was passed to +fix-phonon is less than 1. + +E: Can not open output file %s" + +Self-explanatory. + +E: Illegal fix_modify command + +Self-explanatory. + +E: Could not find fix_modify temp ID + +Self-explanatory. + +E: Fix_modify temp ID does not compute temperature + +Self-explanatory. + +E: Cannot open input map file %s + +Self-explanatory. + +E: Error while reading header of mapping file! + +Self-explanatory. The first line of the map file is expected to +contain 4 positive integer numbers. + +E: FFT mesh and number of atoms in group mismatch! + +Self-explanatory. The product of the 4 numbers should be exactly the +total number of atoms in the group that was passed to fix-phonon. + +E: Error while reading comment of mapping file! + +Self-explanatory. The second line of the map file should be a comment line. + +E: The mapping is incomplete! + +Self-explanatory. + +E: Error while reading mapping file! + +Self-explanatory. + +E: The mapping info read is incorrect! + +Self-explanatory. + +E: Singular matrix in complex GaussJordan! + +Self-explanatory. + +W: More than one fix phonon defined + +Self-explanatory. Just to warn that more than one fix-phonon is defined, but allowed. + +*/ diff --git a/src/dump_cfg.cpp b/src/dump_cfg.cpp index e5adf3e25..05f33997c 100755 --- a/src/dump_cfg.cpp +++ b/src/dump_cfg.cpp @@ -1,237 +1,213 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- Contributing author: Liang Wan (Chinese Academy of Sciences) + Memory efficiency improved by Ray Shan (Sandia) ------------------------------------------------------------------------- */ #include "math.h" #include "stdlib.h" #include "string.h" #include "dump_cfg.h" #include "atom.h" #include "domain.h" #include "comm.h" #include "modify.h" #include "compute.h" #include "input.h" #include "fix.h" #include "variable.h" #include "memory.h" #include "error.h" #define UNWRAPEXPAND 10.0 using namespace LAMMPS_NS; -enum{INT,DOUBLE}; // same as in dump_custom.cpp +enum{INT,DOUBLE,STRING}; // same as in DumpCustom /* ---------------------------------------------------------------------- */ DumpCFG::DumpCFG(LAMMPS *lmp, int narg, char **arg) : DumpCustom(lmp, narg, arg) { if (narg < 10 || - strcmp(arg[5],"id") != 0 || strcmp(arg[6],"type") != 0 || + strcmp(arg[5],"mass") != 0 || strcmp(arg[6],"type") != 0 || (strcmp(arg[7],"xs") != 0 && strcmp(arg[7],"xsu") != 0) || (strcmp(arg[8],"ys") != 0 && strcmp(arg[8],"ysu") != 0) || (strcmp(arg[9],"zs") != 0 && strcmp(arg[9],"zsu") != 0)) error->all(FLERR,"Dump cfg arguments must start with " - "'id type xs ys zs' or 'id type xsu ysu zsu'"); + "'mass type xs ys zs' or 'mass type xsu ysu zsu'"); if (strcmp(arg[7],"xs") == 0) if (strcmp(arg[8],"ysu") == 0 || strcmp(arg[9],"zsu") == 0) - error->all(FLERR,"Dump cfg arguments can not mix xs|ys|zs with xsu|ysu|zsu"); + error->all(FLERR, + "Dump cfg arguments can not mix xs|ys|zs with xsu|ysu|zsu"); else unwrapflag = 0; else if (strcmp(arg[8],"ys") == 0 || strcmp(arg[9],"zs") == 0) - error->all(FLERR,"Dump cfg arguments can not mix xs|ys|zs with xsu|ysu|zsu"); + error->all(FLERR, + "Dump cfg arguments can not mix xs|ys|zs with xsu|ysu|zsu"); else unwrapflag = 1; - // arrays for data rearrangement - - rbuf = NULL; - nchosen = nlines = 0; - // setup auxiliary property name strings // convert 'X_ID[m]' (X=c,f,v) to 'ID_m' if (narg > 10) auxname = new char*[narg-10]; else auxname = NULL; int i = 0; for (int iarg = 10; iarg < narg; iarg++, i++) { if (strncmp(arg[iarg],"c_",2) == 0 || strncmp(arg[iarg],"f_",2) == 0 || strncmp(arg[iarg],"v_",2) == 0) { int n = strlen(arg[iarg]); char *suffix = new char[n]; strcpy(suffix,&arg[iarg][2]); char *ptr = strchr(suffix,'['); if (ptr) { if (suffix[strlen(suffix)-1] != ']') error->all(FLERR,"Invalid keyword in dump cfg command"); *ptr = '\0'; *(ptr+2) = '\0'; auxname[i] = new char[strlen(suffix) + 3]; strcpy(auxname[i],suffix); strcat(auxname[i],"_"); strcat(auxname[i],ptr+1); } else { auxname[i] = new char[strlen(suffix) + 1]; strcpy(auxname[i],suffix); } delete [] suffix; } else { auxname[i] = new char[strlen(arg[iarg]) + 1]; strcpy(auxname[i],arg[iarg]); } } } /* ---------------------------------------------------------------------- */ DumpCFG::~DumpCFG() { - if (rbuf) memory->destroy(rbuf); - if (auxname) { for (int i = 0; i < nfield-5; i++) delete [] auxname[i]; delete [] auxname; } } /* ---------------------------------------------------------------------- */ void DumpCFG::init_style() { - if (multifile == 0) error->all(FLERR,"Dump cfg requires one snapshot per file"); + if (multifile == 0) + error->all(FLERR,"Dump cfg requires one snapshot per file"); DumpCustom::init_style(); } /* ---------------------------------------------------------------------- */ void DumpCFG::write_header(bigint n) { // special handling for atom style peri // use average volume of particles to scale particles to mimic C atoms // scale box dimension to sc lattice for C with sigma = 1.44 Angstroms // special handling for unwrapped coordinates double scale; if (atom->peri_flag) { int nlocal = atom->nlocal; double vone = 0.0; for (int i = 0; i < nlocal; i++) vone += atom->vfrac[i]; double vave; MPI_Allreduce(&vone,&vave,1,MPI_DOUBLE,MPI_SUM,world); if (atom->natoms) vave /= atom->natoms; if (vave > 0.0) scale = 1.44 / pow(vave,1.0/3.0); } else if (unwrapflag == 1) scale = UNWRAPEXPAND; else scale = 1.0; char str[64]; sprintf(str,"Number of particles = %s\n",BIGINT_FORMAT); fprintf(fp,str,n); fprintf(fp,"A = %g Angstrom (basic length-scale)\n",scale); fprintf(fp,"H0(1,1) = %g A\n",domain->xprd); fprintf(fp,"H0(1,2) = 0 A \n"); fprintf(fp,"H0(1,3) = 0 A \n"); fprintf(fp,"H0(2,1) = %g A \n",domain->xy); fprintf(fp,"H0(2,2) = %g A\n",domain->yprd); fprintf(fp,"H0(2,3) = 0 A \n"); fprintf(fp,"H0(3,1) = %g A \n",domain->xz); fprintf(fp,"H0(3,2) = %g A \n",domain->yz); fprintf(fp,"H0(3,3) = %g A\n",domain->zprd); fprintf(fp,".NO_VELOCITY.\n"); fprintf(fp,"entry_count = %d\n",nfield-2); for (int i = 0; i < nfield-5; i++) fprintf(fp,"auxiliary[%d] = %s\n",i,auxname[i]); - - // allocate memory needed for data rearrangement - - nchosen = static_cast (n); - if (rbuf) memory->destroy(rbuf); - memory->create(rbuf,nchosen,size_one,"dump:rbuf"); } -/* ---------------------------------------------------------------------- - write data lines to file in a block-by-block style - write head of block (mass & element name) only if has atoms of the type -------------------------------------------------------------------------- */ +/* ---------------------------------------------------------------------- */ void DumpCFG::write_data(int n, double *mybuf) { - int i,j,m,itype; - - double *rmass = atom->rmass; - double *mass = atom->mass; - - // transfer data from buf to rbuf - // if write by proc 0, transfer chunk by chunk - - for (i = 0, m = 0; i < n; i++) { - for (j = 0; j < size_one; j++) - rbuf[nlines][j] = mybuf[m++]; - nlines++; - } - - // write data lines in rbuf to file after transfer is done - - double unwrap_coord; - - if (nlines == nchosen) { - for (itype = 1; itype <= ntypes; itype++) { - for (i = 0; i < nchosen; i++) - if (rbuf[i][1] == itype) break; - if (i < nchosen) { - if (rmass) fprintf(fp,"%g\n",rmass[i]); - else fprintf(fp,"%g\n",mass[itype]); - fprintf(fp,"%s\n",typenames[itype]); - for (; i < nchosen; i++) { - if (rbuf[i][1] == itype) { - if (unwrapflag == 0) - for (j = 2; j < size_one; j++) { - if (vtype[j] == INT) - fprintf(fp,vformat[j],static_cast (rbuf[i][j])); - else fprintf(fp,vformat[j],rbuf[i][j]); - } - else { - - // Unwrapped scaled coordinates are shifted to - // center of expanded box, to prevent - // rewrapping by AtomEye. Dividing by - // expansion factor restores correct - // interatomic distances. - - for (j = 2; j < 5; j++) { - unwrap_coord = (rbuf[i][j] - 0.5)/UNWRAPEXPAND + 0.5; - fprintf(fp,vformat[j],unwrap_coord); - } - for (j = 5; j < size_one; j++) { - if (vtype[j] == INT) - fprintf(fp,vformat[j],static_cast (rbuf[i][j])); - else fprintf(fp,vformat[j],rbuf[i][j]); - } - } - fprintf(fp,"\n"); - } + int i,j,m; + + if (unwrapflag == 0) { + m = 0; + for (i = 0; i < n; i++) { + for (j = 0; j < size_one; j++) { + if (j == 0) { + fprintf(fp,"%f \n",mybuf[m]); + } else if (j == 1) { + fprintf(fp,"%s \n",typenames[(int) mybuf[m]]); + } else if (j >= 2) { + if (vtype[j] == INT) + fprintf(fp,vformat[j],static_cast (mybuf[m])); + else if (vtype[j] == DOUBLE) + fprintf(fp,vformat[j],mybuf[m]); + else if (vtype[j] == STRING) + fprintf(fp,vformat[j],typenames[(int) mybuf[m]]); + } + m++; + } + fprintf(fp,"\n"); + } + } else if (unwrapflag == 1) { + m = 0; + double unwrap_coord; + for (i = 0; i < n; i++) { + for (j = 0; j < size_one; j++) { + if (j == 0) { + fprintf(fp,"%f \n",mybuf[m]); + } else if (j == 1) { + fprintf(fp,"%s \n",typenames[(int) mybuf[m]]); + } else if (j >= 2 && j <= 4) { + unwrap_coord = (mybuf[m] - 0.5)/UNWRAPEXPAND + 0.5; + fprintf(fp,vformat[j],unwrap_coord); + } else if (j >= 5 ) { + if (vtype[j] == INT) + fprintf(fp,vformat[j],static_cast (mybuf[m])); + else if (vtype[j] == DOUBLE) + fprintf(fp,vformat[j],mybuf[m]); + else if (vtype[j] == STRING) + fprintf(fp,vformat[j],typenames[(int) mybuf[m]]); } + m++; } + fprintf(fp,"\n"); } - nlines = 0; } } diff --git a/src/dump_cfg.h b/src/dump_cfg.h index 654582b1c..d686b2328 100755 --- a/src/dump_cfg.h +++ b/src/dump_cfg.h @@ -1,67 +1,65 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ #ifdef DUMP_CLASS DumpStyle(cfg,DumpCFG) #else #ifndef LMP_DUMP_CFG_H #define LMP_DUMP_CFG_H #include "dump_custom.h" namespace LAMMPS_NS { class DumpCFG : public DumpCustom { public: DumpCFG(class LAMMPS *, int, char **); ~DumpCFG(); private: char **auxname; // name strings of auxiliary properties - int nchosen; // # of lines to be written on a writing proc - int nlines; // # of lines transferred from buf to rbuf - double **rbuf; // buf of data lines for data lines rearrangement int unwrapflag; // 1 if unwrapped coordinates are requested void init_style(); void write_header(bigint); void write_data(int, double *); + }; } #endif #endif /* ERROR/WARNING messages: E: Dump cfg arguments must start with 'id type xs ys zs' or 'id type xsu ysu zsu' This is a requirement of the CFG output format. E: Dump cfg arguments can not mix xs|ys|zs with xsu|ysu|zsu Self-explanatory. E: Invalid keyword in dump cfg command Self-explanatory. E: Dump cfg requires one snapshot per file Use the wildcard "*" character in the filename. */ diff --git a/src/dump_custom.cpp b/src/dump_custom.cpp index 4e4b4224e..e3682bbac 100644 --- a/src/dump_custom.cpp +++ b/src/dump_custom.cpp @@ -1,2409 +1,2409 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ #include "math.h" #include "stdlib.h" #include "string.h" #include "dump_custom.h" #include "atom.h" #include "force.h" #include "domain.h" #include "region.h" #include "group.h" #include "input.h" #include "variable.h" #include "update.h" #include "modify.h" #include "compute.h" #include "fix.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; // customize by adding keyword // also customize compute_atom_property.cpp enum{ID,MOL,TYPE,ELEMENT,MASS, X,Y,Z,XS,YS,ZS,XSTRI,YSTRI,ZSTRI,XU,YU,ZU,XUTRI,YUTRI,ZUTRI, XSU,YSU,ZSU,XSUTRI,YSUTRI,ZSUTRI, IX,IY,IZ, VX,VY,VZ,FX,FY,FZ, Q,MUX,MUY,MUZ,MU,RADIUS,DIAMETER, OMEGAX,OMEGAY,OMEGAZ,ANGMOMX,ANGMOMY,ANGMOMZ, TQX,TQY,TQZ,SPIN,ERADIUS,ERVEL,ERFORCE, COMPUTE,FIX,VARIABLE}; enum{LT,LE,GT,GE,EQ,NEQ}; -enum{INT,DOUBLE,STRING}; +enum{INT,DOUBLE,STRING}; // same as in DumpCFG #define INVOKED_PERATOM 8 /* ---------------------------------------------------------------------- */ DumpCustom::DumpCustom(LAMMPS *lmp, int narg, char **arg) : Dump(lmp, narg, arg) { if (narg == 5) error->all(FLERR,"No dump custom arguments specified"); clearstep = 1; nevery = force->inumeric(FLERR,arg[3]); // size_one may be shrunk below if additional optional args exist size_one = nfield = narg - 5; pack_choice = new FnPtrPack[nfield]; vtype = new int[nfield]; iregion = -1; idregion = NULL; nthresh = 0; thresh_array = NULL; thresh_op = NULL; thresh_value = NULL; // computes, fixes, variables which the dump accesses memory->create(field2index,nfield,"dump:field2index"); memory->create(argindex,nfield,"dump:argindex"); ncompute = 0; id_compute = NULL; compute = NULL; nfix = 0; id_fix = NULL; fix = NULL; nvariable = 0; id_variable = NULL; variable = NULL; vbuf = NULL; // process attributes // ioptional = start of additional optional args // only dump image style processes optional args ioptional = parse_fields(narg,arg); if (ioptional < narg && strcmp(style,"image") != 0) error->all(FLERR,"Invalid attribute in dump custom command"); size_one = nfield = ioptional - 5; // atom selection arrays maxlocal = 0; choose = NULL; dchoose = NULL; clist = NULL; // element names ntypes = atom->ntypes; typenames = NULL; // setup format strings vformat = new char*[size_one]; format_default = new char[3*size_one+1]; format_default[0] = '\0'; for (int i = 0; i < size_one; i++) { if (vtype[i] == INT) strcat(format_default,"%d "); else if (vtype[i] == DOUBLE) strcat(format_default,"%g "); else if (vtype[i] == STRING) strcat(format_default,"%s "); vformat[i] = NULL; } // setup column string int n = 0; for (int iarg = 5; iarg < narg; iarg++) n += strlen(arg[iarg]) + 2; columns = new char[n]; columns[0] = '\0'; for (int iarg = 5; iarg < narg; iarg++) { strcat(columns,arg[iarg]); strcat(columns," "); } } /* ---------------------------------------------------------------------- */ DumpCustom::~DumpCustom() { delete [] pack_choice; delete [] vtype; memory->destroy(field2index); memory->destroy(argindex); delete [] idregion; memory->destroy(thresh_array); memory->destroy(thresh_op); memory->destroy(thresh_value); for (int i = 0; i < ncompute; i++) delete [] id_compute[i]; memory->sfree(id_compute); delete [] compute; for (int i = 0; i < nfix; i++) delete [] id_fix[i]; memory->sfree(id_fix); delete [] fix; for (int i = 0; i < nvariable; i++) delete [] id_variable[i]; memory->sfree(id_variable); delete [] variable; for (int i = 0; i < nvariable; i++) memory->destroy(vbuf[i]); delete [] vbuf; memory->destroy(choose); memory->destroy(dchoose); memory->destroy(clist); if (typenames) { for (int i = 1; i <= ntypes; i++) delete [] typenames[i]; delete [] typenames; } for (int i = 0; i < size_one; i++) delete [] vformat[i]; delete [] vformat; delete [] columns; } /* ---------------------------------------------------------------------- */ void DumpCustom::init_style() { delete [] format; char *str; if (format_user) str = format_user; else str = format_default; int n = strlen(str) + 1; format = new char[n]; strcpy(format,str); // default for element names = C if (typenames == NULL) { typenames = new char*[ntypes+1]; for (int itype = 1; itype <= ntypes; itype++) { typenames[itype] = new char[2]; strcpy(typenames[itype],"C"); } } // tokenize the format string and add space at end of each format element char *ptr; for (int i = 0; i < size_one; i++) { if (i == 0) ptr = strtok(format," \0"); else ptr = strtok(NULL," \0"); if (ptr == NULL) error->all(FLERR,"Dump_modify format string is too short"); delete [] vformat[i]; vformat[i] = new char[strlen(ptr) + 2]; strcpy(vformat[i],ptr); vformat[i] = strcat(vformat[i]," "); } // setup boundary string domain->boundary_string(boundstr); // setup function ptrs if (binary && domain->triclinic == 0) header_choice = &DumpCustom::header_binary; else if (binary && domain->triclinic == 1) header_choice = &DumpCustom::header_binary_triclinic; else if (!binary && domain->triclinic == 0) header_choice = &DumpCustom::header_item; else if (!binary && domain->triclinic == 1) header_choice = &DumpCustom::header_item_triclinic; if (binary) write_choice = &DumpCustom::write_binary; else write_choice = &DumpCustom::write_text; // find current ptr for each compute,fix,variable // check that fix frequency is acceptable int icompute; for (int i = 0; i < ncompute; i++) { icompute = modify->find_compute(id_compute[i]); if (icompute < 0) error->all(FLERR,"Could not find dump custom compute ID"); compute[i] = modify->compute[icompute]; } int ifix; for (int i = 0; i < nfix; i++) { ifix = modify->find_fix(id_fix[i]); if (ifix < 0) error->all(FLERR,"Could not find dump custom fix ID"); fix[i] = modify->fix[ifix]; if (nevery % modify->fix[ifix]->peratom_freq) error->all(FLERR,"Dump custom and fix not computed at compatible times"); } int ivariable; for (int i = 0; i < nvariable; i++) { ivariable = input->variable->find(id_variable[i]); if (ivariable < 0) error->all(FLERR,"Could not find dump custom variable name"); variable[i] = ivariable; } // set index and check validity of region if (iregion >= 0) { iregion = domain->find_region(idregion); if (iregion == -1) error->all(FLERR,"Region ID for dump custom does not exist"); } // open single file, one time only if (multifile == 0) openfile(); } /* ---------------------------------------------------------------------- */ void DumpCustom::write_header(bigint ndump) { if (multiproc) (this->*header_choice)(ndump); else if (me == 0) (this->*header_choice)(ndump); } /* ---------------------------------------------------------------------- */ void DumpCustom::header_binary(bigint ndump) { fwrite(&update->ntimestep,sizeof(bigint),1,fp); fwrite(&ndump,sizeof(bigint),1,fp); fwrite(&domain->triclinic,sizeof(int),1,fp); fwrite(&domain->boundary[0][0],6*sizeof(int),1,fp); fwrite(&boxxlo,sizeof(double),1,fp); fwrite(&boxxhi,sizeof(double),1,fp); fwrite(&boxylo,sizeof(double),1,fp); fwrite(&boxyhi,sizeof(double),1,fp); fwrite(&boxzlo,sizeof(double),1,fp); fwrite(&boxzhi,sizeof(double),1,fp); fwrite(&size_one,sizeof(int),1,fp); if (multiproc) fwrite(&nclusterprocs,sizeof(int),1,fp); else fwrite(&nprocs,sizeof(int),1,fp); } /* ---------------------------------------------------------------------- */ void DumpCustom::header_binary_triclinic(bigint ndump) { fwrite(&update->ntimestep,sizeof(bigint),1,fp); fwrite(&ndump,sizeof(bigint),1,fp); fwrite(&domain->triclinic,sizeof(int),1,fp); fwrite(&domain->boundary[0][0],6*sizeof(int),1,fp); fwrite(&boxxlo,sizeof(double),1,fp); fwrite(&boxxhi,sizeof(double),1,fp); fwrite(&boxylo,sizeof(double),1,fp); fwrite(&boxyhi,sizeof(double),1,fp); fwrite(&boxzlo,sizeof(double),1,fp); fwrite(&boxzhi,sizeof(double),1,fp); fwrite(&boxxy,sizeof(double),1,fp); fwrite(&boxxz,sizeof(double),1,fp); fwrite(&boxyz,sizeof(double),1,fp); fwrite(&size_one,sizeof(int),1,fp); if (multiproc) fwrite(&nclusterprocs,sizeof(int),1,fp); else fwrite(&nprocs,sizeof(int),1,fp); } /* ---------------------------------------------------------------------- */ void DumpCustom::header_item(bigint ndump) { fprintf(fp,"ITEM: TIMESTEP\n"); fprintf(fp,BIGINT_FORMAT "\n",update->ntimestep); fprintf(fp,"ITEM: NUMBER OF ATOMS\n"); fprintf(fp,BIGINT_FORMAT "\n",ndump); fprintf(fp,"ITEM: BOX BOUNDS %s\n",boundstr); fprintf(fp,"%g %g\n",boxxlo,boxxhi); fprintf(fp,"%g %g\n",boxylo,boxyhi); fprintf(fp,"%g %g\n",boxzlo,boxzhi); fprintf(fp,"ITEM: ATOMS %s\n",columns); } /* ---------------------------------------------------------------------- */ void DumpCustom::header_item_triclinic(bigint ndump) { fprintf(fp,"ITEM: TIMESTEP\n"); fprintf(fp,BIGINT_FORMAT "\n",update->ntimestep); fprintf(fp,"ITEM: NUMBER OF ATOMS\n"); fprintf(fp,BIGINT_FORMAT "\n",ndump); fprintf(fp,"ITEM: BOX BOUNDS xy xz yz %s\n",boundstr); fprintf(fp,"%g %g %g\n",boxxlo,boxxhi,boxxy); fprintf(fp,"%g %g %g\n",boxylo,boxyhi,boxxz); fprintf(fp,"%g %g %g\n",boxzlo,boxzhi,boxyz); fprintf(fp,"ITEM: ATOMS %s\n",columns); } /* ---------------------------------------------------------------------- */ int DumpCustom::count() { int i; // grow choose and variable vbuf arrays if needed int nlocal = atom->nlocal; if (nlocal > maxlocal) { maxlocal = atom->nmax; memory->destroy(choose); memory->destroy(dchoose); memory->destroy(clist); memory->create(choose,maxlocal,"dump:choose"); memory->create(dchoose,maxlocal,"dump:dchoose"); memory->create(clist,maxlocal,"dump:clist"); for (i = 0; i < nvariable; i++) { memory->destroy(vbuf[i]); memory->create(vbuf[i],maxlocal,"dump:vbuf"); } } // invoke Computes for per-atom quantities if (ncompute) { for (i = 0; i < ncompute; i++) if (!(compute[i]->invoked_flag & INVOKED_PERATOM)) { compute[i]->compute_peratom(); compute[i]->invoked_flag |= INVOKED_PERATOM; } } // evaluate atom-style Variables for per-atom quantities if (nvariable) for (i = 0; i < nvariable; i++) input->variable->compute_atom(variable[i],igroup,vbuf[i],1,0); // choose all local atoms for output for (i = 0; i < nlocal; i++) choose[i] = 1; // un-choose if not in group if (igroup) { int *mask = atom->mask; for (i = 0; i < nlocal; i++) if (!(mask[i] & groupbit)) choose[i] = 0; } // un-choose if not in region if (iregion >= 0) { Region *region = domain->regions[iregion]; double **x = atom->x; for (i = 0; i < nlocal; i++) if (choose[i] && region->match(x[i][0],x[i][1],x[i][2]) == 0) choose[i] = 0; } // un-choose if any threshhold criterion isn't met if (nthresh) { double *ptr; double value; int nstride; int nlocal = atom->nlocal; for (int ithresh = 0; ithresh < nthresh; ithresh++) { // customize by adding to if statement if (thresh_array[ithresh] == ID) { int *tag = atom->tag; for (i = 0; i < nlocal; i++) dchoose[i] = tag[i]; ptr = dchoose; nstride = 1; } else if (thresh_array[ithresh] == MOL) { if (!atom->molecule_flag) error->all(FLERR, "Threshhold for an atom property that isn't allocated"); int *molecule = atom->molecule; for (i = 0; i < nlocal; i++) dchoose[i] = molecule[i]; ptr = dchoose; nstride = 1; } else if (thresh_array[ithresh] == TYPE) { int *type = atom->type; for (i = 0; i < nlocal; i++) dchoose[i] = type[i]; ptr = dchoose; nstride = 1; } else if (thresh_array[ithresh] == ELEMENT) { int *type = atom->type; for (i = 0; i < nlocal; i++) dchoose[i] = type[i]; ptr = dchoose; nstride = 1; } else if (thresh_array[ithresh] == MASS) { if (atom->rmass) { ptr = atom->rmass; nstride = 1; } else { double *mass = atom->mass; int *type = atom->type; for (i = 0; i < nlocal; i++) dchoose[i] = mass[type[i]]; ptr = dchoose; nstride = 1; } } else if (thresh_array[ithresh] == X) { ptr = &atom->x[0][0]; nstride = 3; } else if (thresh_array[ithresh] == Y) { ptr = &atom->x[0][1]; nstride = 3; } else if (thresh_array[ithresh] == Z) { ptr = &atom->x[0][2]; nstride = 3; } else if (thresh_array[ithresh] == XS) { double **x = atom->x; double boxxlo = domain->boxlo[0]; double invxprd = 1.0/domain->xprd; for (i = 0; i < nlocal; i++) dchoose[i] = (x[i][0] - boxxlo) * invxprd; ptr = dchoose; nstride = 1; } else if (thresh_array[ithresh] == YS) { double **x = atom->x; double boxylo = domain->boxlo[1]; double invyprd = 1.0/domain->yprd; for (i = 0; i < nlocal; i++) dchoose[i] = (x[i][1] - boxylo) * invyprd; ptr = dchoose; nstride = 1; } else if (thresh_array[ithresh] == ZS) { double **x = atom->x; double boxzlo = domain->boxlo[2]; double invzprd = 1.0/domain->zprd; for (i = 0; i < nlocal; i++) dchoose[i] = (x[i][2] - boxzlo) * invzprd; ptr = dchoose; nstride = 1; } else if (thresh_array[ithresh] == XSTRI) { double **x = atom->x; double *boxlo = domain->boxlo; double *h_inv = domain->h_inv; for (i = 0; i < nlocal; i++) dchoose[i] = h_inv[0]*(x[i][0]-boxlo[0]) + h_inv[5]*(x[i][1]-boxlo[1]) + h_inv[4]*(x[i][2]-boxlo[2]); ptr = dchoose; nstride = 1; } else if (thresh_array[ithresh] == YSTRI) { double **x = atom->x; double *boxlo = domain->boxlo; double *h_inv = domain->h_inv; for (i = 0; i < nlocal; i++) dchoose[i] = h_inv[1]*(x[i][1]-boxlo[1]) + h_inv[3]*(x[i][2]-boxlo[2]); ptr = dchoose; nstride = 1; } else if (thresh_array[ithresh] == ZSTRI) { double **x = atom->x; double *boxlo = domain->boxlo; double *h_inv = domain->h_inv; for (i = 0; i < nlocal; i++) dchoose[i] = h_inv[2]*(x[i][2]-boxlo[2]); ptr = dchoose; nstride = 1; } else if (thresh_array[ithresh] == XU) { double **x = atom->x; tagint *image = atom->image; double xprd = domain->xprd; for (i = 0; i < nlocal; i++) dchoose[i] = x[i][0] + ((image[i] & IMGMASK) - IMGMAX) * xprd; ptr = dchoose; nstride = 1; } else if (thresh_array[ithresh] == YU) { double **x = atom->x; tagint *image = atom->image; double yprd = domain->yprd; for (i = 0; i < nlocal; i++) dchoose[i] = x[i][1] + ((image[i] >> IMGBITS & IMGMASK) - IMGMAX) * yprd; ptr = dchoose; nstride = 1; } else if (thresh_array[ithresh] == ZU) { double **x = atom->x; tagint *image = atom->image; double zprd = domain->zprd; for (i = 0; i < nlocal; i++) dchoose[i] = x[i][2] + ((image[i] >> IMG2BITS) - IMGMAX) * zprd; ptr = dchoose; nstride = 1; } else if (thresh_array[ithresh] == XUTRI) { double **x = atom->x; tagint *image = atom->image; double *h = domain->h; int xbox,ybox,zbox; for (i = 0; i < nlocal; i++) { xbox = (image[i] & IMGMASK) - IMGMAX; ybox = (image[i] >> IMGBITS & IMGMASK) - IMGMAX; zbox = (image[i] >> IMG2BITS) - IMGMAX; dchoose[i] = x[i][0] + h[0]*xbox + h[5]*ybox + h[4]*zbox; } ptr = dchoose; nstride = 1; } else if (thresh_array[ithresh] == YUTRI) { double **x = atom->x; tagint *image = atom->image; double *h = domain->h; int ybox,zbox; for (i = 0; i < nlocal; i++) { ybox = (image[i] >> IMGBITS & IMGMASK) - IMGMAX; zbox = (image[i] >> IMG2BITS) - IMGMAX; dchoose[i] = x[i][1] + h[1]*ybox + h[3]*zbox; } ptr = dchoose; nstride = 1; } else if (thresh_array[ithresh] == ZUTRI) { double **x = atom->x; tagint *image = atom->image; double *h = domain->h; int zbox; for (i = 0; i < nlocal; i++) { zbox = (image[i] >> IMG2BITS) - IMGMAX; dchoose[i] = x[i][2] + h[2]*zbox; } ptr = dchoose; nstride = 1; } else if (thresh_array[ithresh] == XSU) { double **x = atom->x; tagint *image = atom->image; double boxxlo = domain->boxlo[0]; double invxprd = 1.0/domain->xprd; for (i = 0; i < nlocal; i++) dchoose[i] = (x[i][0] - boxxlo) * invxprd + (image[i] & IMGMASK) - IMGMAX; ptr = dchoose; nstride = 1; } else if (thresh_array[ithresh] == YSU) { double **x = atom->x; tagint *image = atom->image; double boxylo = domain->boxlo[1]; double invyprd = 1.0/domain->yprd; for (i = 0; i < nlocal; i++) dchoose[i] = (x[i][1] - boxylo) * invyprd + (image[i] >> IMGBITS & IMGMASK) - IMGMAX; ptr = dchoose; nstride = 1; } else if (thresh_array[ithresh] == ZSU) { double **x = atom->x; tagint *image = atom->image; double boxzlo = domain->boxlo[2]; double invzprd = 1.0/domain->zprd; for (i = 0; i < nlocal; i++) dchoose[i] = (x[i][2] - boxzlo) * invzprd + (image[i] >> IMG2BITS) - IMGMAX; ptr = dchoose; nstride = 1; } else if (thresh_array[ithresh] == XSUTRI) { double **x = atom->x; tagint *image = atom->image; double *boxlo = domain->boxlo; double *h_inv = domain->h_inv; for (i = 0; i < nlocal; i++) dchoose[i] = h_inv[0]*(x[i][0]-boxlo[0]) + h_inv[5]*(x[i][1]-boxlo[1]) + h_inv[4]*(x[i][2]-boxlo[2]) + (image[i] & IMGMASK) - IMGMAX; ptr = dchoose; nstride = 1; } else if (thresh_array[ithresh] == YSUTRI) { double **x = atom->x; tagint *image = atom->image; double *boxlo = domain->boxlo; double *h_inv = domain->h_inv; for (i = 0; i < nlocal; i++) dchoose[i] = h_inv[1]*(x[i][1]-boxlo[1]) + h_inv[3]*(x[i][2]-boxlo[2]) + (image[i] >> IMGBITS & IMGMASK) - IMGMAX; ptr = dchoose; nstride = 1; } else if (thresh_array[ithresh] == ZSUTRI) { double **x = atom->x; tagint *image = atom->image; double *boxlo = domain->boxlo; double *h_inv = domain->h_inv; for (i = 0; i < nlocal; i++) dchoose[i] = h_inv[2]*(x[i][2]-boxlo[2]) + (image[i] >> IMG2BITS) - IMGMAX; ptr = dchoose; nstride = 1; } else if (thresh_array[ithresh] == IX) { tagint *image = atom->image; for (i = 0; i < nlocal; i++) dchoose[i] = (image[i] & IMGMASK) - IMGMAX; ptr = dchoose; nstride = 1; } else if (thresh_array[ithresh] == IY) { tagint *image = atom->image; for (i = 0; i < nlocal; i++) dchoose[i] = (image[i] >> IMGBITS & IMGMASK) - IMGMAX; ptr = dchoose; nstride = 1; } else if (thresh_array[ithresh] == IZ) { tagint *image = atom->image; for (i = 0; i < nlocal; i++) dchoose[i] = (image[i] >> IMG2BITS) - IMGMAX; ptr = dchoose; nstride = 1; } else if (thresh_array[ithresh] == VX) { ptr = &atom->v[0][0]; nstride = 3; } else if (thresh_array[ithresh] == VY) { ptr = &atom->v[0][1]; nstride = 3; } else if (thresh_array[ithresh] == VZ) { ptr = &atom->v[0][2]; nstride = 3; } else if (thresh_array[ithresh] == FX) { ptr = &atom->f[0][0]; nstride = 3; } else if (thresh_array[ithresh] == FY) { ptr = &atom->f[0][1]; nstride = 3; } else if (thresh_array[ithresh] == FZ) { ptr = &atom->f[0][2]; nstride = 3; } else if (thresh_array[ithresh] == Q) { if (!atom->q_flag) error->all(FLERR, "Threshhold for an atom property that isn't allocated"); ptr = atom->q; nstride = 1; } else if (thresh_array[ithresh] == MUX) { if (!atom->mu_flag) error->all(FLERR, "Threshhold for an atom property that isn't allocated"); ptr = &atom->mu[0][0]; nstride = 4; } else if (thresh_array[ithresh] == MUY) { if (!atom->mu_flag) error->all(FLERR, "Threshhold for an atom property that isn't allocated"); ptr = &atom->mu[0][1]; nstride = 4; } else if (thresh_array[ithresh] == MUZ) { if (!atom->mu_flag) error->all(FLERR, "Threshhold for an atom property that isn't allocated"); ptr = &atom->mu[0][2]; nstride = 4; } else if (thresh_array[ithresh] == MU) { if (!atom->mu_flag) error->all(FLERR, "Threshhold for an atom property that isn't allocated"); ptr = &atom->mu[0][3]; nstride = 4; } else if (thresh_array[ithresh] == RADIUS) { if (!atom->radius_flag) error->all(FLERR, "Threshhold for an atom property that isn't allocated"); ptr = atom->radius; nstride = 1; } else if (thresh_array[ithresh] == DIAMETER) { if (!atom->radius_flag) error->all(FLERR, "Threshhold for an atom property that isn't allocated"); double *radius = atom->radius; for (i = 0; i < nlocal; i++) dchoose[i] = 2.0*radius[i]; ptr = dchoose; nstride = 1; } else if (thresh_array[ithresh] == OMEGAX) { if (!atom->omega_flag) error->all(FLERR, "Threshhold for an atom property that isn't allocated"); ptr = &atom->omega[0][0]; nstride = 3; } else if (thresh_array[ithresh] == OMEGAY) { if (!atom->omega_flag) error->all(FLERR, "Threshhold for an atom property that isn't allocated"); ptr = &atom->omega[0][1]; nstride = 3; } else if (thresh_array[ithresh] == OMEGAZ) { if (!atom->omega_flag) error->all(FLERR, "Threshhold for an atom property that isn't allocated"); ptr = &atom->omega[0][2]; nstride = 3; } else if (thresh_array[ithresh] == ANGMOMX) { if (!atom->angmom_flag) error->all(FLERR, "Threshhold for an atom property that isn't allocated"); ptr = &atom->angmom[0][0]; nstride = 3; } else if (thresh_array[ithresh] == ANGMOMY) { if (!atom->angmom_flag) error->all(FLERR, "Threshhold for an atom property that isn't allocated"); ptr = &atom->angmom[0][1]; nstride = 3; } else if (thresh_array[ithresh] == ANGMOMZ) { if (!atom->angmom_flag) error->all(FLERR, "Threshhold for an atom property that isn't allocated"); ptr = &atom->angmom[0][2]; nstride = 3; } else if (thresh_array[ithresh] == TQX) { if (!atom->torque_flag) error->all(FLERR, "Threshhold for an atom property that isn't allocated"); ptr = &atom->torque[0][0]; nstride = 3; } else if (thresh_array[ithresh] == TQY) { if (!atom->torque_flag) error->all(FLERR, "Threshhold for an atom property that isn't allocated"); ptr = &atom->torque[0][1]; nstride = 3; } else if (thresh_array[ithresh] == TQZ) { if (!atom->torque_flag) error->all(FLERR, "Threshhold for an atom property that isn't allocated"); ptr = &atom->torque[0][2]; nstride = 3; } else if (thresh_array[ithresh] == SPIN) { if (!atom->spin_flag) error->all(FLERR, "Threshhold for an atom property that isn't allocated"); int *spin = atom->spin; for (i = 0; i < nlocal; i++) dchoose[i] = spin[i]; ptr = dchoose; nstride = 1; } else if (thresh_array[ithresh] == ERADIUS) { if (!atom->eradius_flag) error->all(FLERR, "Threshhold for an atom property that isn't allocated"); ptr = atom->eradius; nstride = 1; } else if (thresh_array[ithresh] == ERVEL) { if (!atom->ervel_flag) error->all(FLERR, "Threshhold for an atom property that isn't allocated"); ptr = atom->ervel; nstride = 1; } else if (thresh_array[ithresh] == ERFORCE) { if (!atom->erforce_flag) error->all(FLERR, "Threshhold for an atom property that isn't allocated"); ptr = atom->erforce; nstride = 1; } else if (thresh_array[ithresh] == COMPUTE) { i = nfield + ithresh; if (argindex[i] == 0) { ptr = compute[field2index[i]]->vector_atom; nstride = 1; } else { ptr = &compute[field2index[i]]->array_atom[0][argindex[i]-1]; nstride = compute[field2index[i]]->size_peratom_cols; } } else if (thresh_array[ithresh] == FIX) { i = nfield + ithresh; if (argindex[i] == 0) { ptr = fix[field2index[i]]->vector_atom; nstride = 1; } else { ptr = &fix[field2index[i]]->array_atom[0][argindex[i]-1]; nstride = fix[field2index[i]]->size_peratom_cols; } } else if (thresh_array[ithresh] == VARIABLE) { i = nfield + ithresh; ptr = vbuf[field2index[i]]; nstride = 1; } // unselect atoms that don't meet threshhold criterion value = thresh_value[ithresh]; if (thresh_op[ithresh] == LT) { for (i = 0; i < nlocal; i++, ptr += nstride) if (choose[i] && *ptr >= value) choose[i] = 0; } else if (thresh_op[ithresh] == LE) { for (i = 0; i < nlocal; i++, ptr += nstride) if (choose[i] && *ptr > value) choose[i] = 0; } else if (thresh_op[ithresh] == GT) { for (i = 0; i < nlocal; i++, ptr += nstride) if (choose[i] && *ptr <= value) choose[i] = 0; } else if (thresh_op[ithresh] == GE) { for (i = 0; i < nlocal; i++, ptr += nstride) if (choose[i] && *ptr < value) choose[i] = 0; } else if (thresh_op[ithresh] == EQ) { for (i = 0; i < nlocal; i++, ptr += nstride) if (choose[i] && *ptr != value) choose[i] = 0; } else if (thresh_op[ithresh] == NEQ) { for (i = 0; i < nlocal; i++, ptr += nstride) if (choose[i] && *ptr == value) choose[i] = 0; } } } // compress choose flags into clist // nchoose = # of selected atoms // clist[i] = local index of each selected atom nchoose = 0; for (i = 0; i < nlocal; i++) if (choose[i]) clist[nchoose++] = i; return nchoose; } /* ---------------------------------------------------------------------- */ void DumpCustom::pack(int *ids) { for (int n = 0; n < size_one; n++) (this->*pack_choice[n])(n); if (ids) { int *tag = atom->tag; for (int i = 0; i < nchoose; i++) ids[i] = tag[clist[i]]; } } /* ---------------------------------------------------------------------- */ void DumpCustom::write_data(int n, double *mybuf) { (this->*write_choice)(n,mybuf); } /* ---------------------------------------------------------------------- */ void DumpCustom::write_binary(int n, double *mybuf) { n *= size_one; fwrite(&n,sizeof(int),1,fp); fwrite(mybuf,sizeof(double),n,fp); } /* ---------------------------------------------------------------------- */ void DumpCustom::write_text(int n, double *mybuf) { int i,j; int m = 0; for (i = 0; i < n; i++) { for (j = 0; j < size_one; j++) { if (vtype[j] == INT) fprintf(fp,vformat[j],static_cast (mybuf[m])); else if (vtype[j] == DOUBLE) fprintf(fp,vformat[j],mybuf[m]); else if (vtype[j] == STRING) fprintf(fp,vformat[j],typenames[(int) mybuf[m]]); m++; } fprintf(fp,"\n"); } } /* ---------------------------------------------------------------------- */ int DumpCustom::parse_fields(int narg, char **arg) { // customize by adding to if statement int i; for (int iarg = 5; iarg < narg; iarg++) { i = iarg-5; if (strcmp(arg[iarg],"id") == 0) { pack_choice[i] = &DumpCustom::pack_id; vtype[i] = INT; } else if (strcmp(arg[iarg],"mol") == 0) { if (!atom->molecule_flag) error->all(FLERR,"Dumping an atom property that isn't allocated"); pack_choice[i] = &DumpCustom::pack_molecule; vtype[i] = INT; } else if (strcmp(arg[iarg],"type") == 0) { pack_choice[i] = &DumpCustom::pack_type; vtype[i] = INT; } else if (strcmp(arg[iarg],"element") == 0) { pack_choice[i] = &DumpCustom::pack_type; vtype[i] = STRING; } else if (strcmp(arg[iarg],"mass") == 0) { pack_choice[i] = &DumpCustom::pack_mass; vtype[i] = DOUBLE; } else if (strcmp(arg[iarg],"x") == 0) { pack_choice[i] = &DumpCustom::pack_x; vtype[i] = DOUBLE; } else if (strcmp(arg[iarg],"y") == 0) { pack_choice[i] = &DumpCustom::pack_y; vtype[i] = DOUBLE; } else if (strcmp(arg[iarg],"z") == 0) { pack_choice[i] = &DumpCustom::pack_z; vtype[i] = DOUBLE; } else if (strcmp(arg[iarg],"xs") == 0) { if (domain->triclinic) pack_choice[i] = &DumpCustom::pack_xs_triclinic; else pack_choice[i] = &DumpCustom::pack_xs; vtype[i] = DOUBLE; } else if (strcmp(arg[iarg],"ys") == 0) { if (domain->triclinic) pack_choice[i] = &DumpCustom::pack_ys_triclinic; else pack_choice[i] = &DumpCustom::pack_ys; vtype[i] = DOUBLE; } else if (strcmp(arg[iarg],"zs") == 0) { if (domain->triclinic) pack_choice[i] = &DumpCustom::pack_zs_triclinic; else pack_choice[i] = &DumpCustom::pack_zs; vtype[i] = DOUBLE; } else if (strcmp(arg[iarg],"xu") == 0) { if (domain->triclinic) pack_choice[i] = &DumpCustom::pack_xu_triclinic; else pack_choice[i] = &DumpCustom::pack_xu; vtype[i] = DOUBLE; } else if (strcmp(arg[iarg],"yu") == 0) { if (domain->triclinic) pack_choice[i] = &DumpCustom::pack_yu_triclinic; else pack_choice[i] = &DumpCustom::pack_yu; vtype[i] = DOUBLE; } else if (strcmp(arg[iarg],"zu") == 0) { if (domain->triclinic) pack_choice[i] = &DumpCustom::pack_zu_triclinic; else pack_choice[i] = &DumpCustom::pack_zu; vtype[i] = DOUBLE; } else if (strcmp(arg[iarg],"xsu") == 0) { if (domain->triclinic) pack_choice[i] = &DumpCustom::pack_xsu_triclinic; else pack_choice[i] = &DumpCustom::pack_xsu; vtype[i] = DOUBLE; } else if (strcmp(arg[iarg],"ysu") == 0) { if (domain->triclinic) pack_choice[i] = &DumpCustom::pack_ysu_triclinic; else pack_choice[i] = &DumpCustom::pack_ysu; vtype[i] = DOUBLE; } else if (strcmp(arg[iarg],"zsu") == 0) { if (domain->triclinic) pack_choice[i] = &DumpCustom::pack_zsu_triclinic; else pack_choice[i] = &DumpCustom::pack_zsu; vtype[i] = DOUBLE; } else if (strcmp(arg[iarg],"ix") == 0) { pack_choice[i] = &DumpCustom::pack_ix; vtype[i] = INT; } else if (strcmp(arg[iarg],"iy") == 0) { pack_choice[i] = &DumpCustom::pack_iy; vtype[i] = INT; } else if (strcmp(arg[iarg],"iz") == 0) { pack_choice[i] = &DumpCustom::pack_iz; vtype[i] = INT; } else if (strcmp(arg[iarg],"vx") == 0) { pack_choice[i] = &DumpCustom::pack_vx; vtype[i] = DOUBLE; } else if (strcmp(arg[iarg],"vy") == 0) { pack_choice[i] = &DumpCustom::pack_vy; vtype[i] = DOUBLE; } else if (strcmp(arg[iarg],"vz") == 0) { pack_choice[i] = &DumpCustom::pack_vz; vtype[i] = DOUBLE; } else if (strcmp(arg[iarg],"fx") == 0) { pack_choice[i] = &DumpCustom::pack_fx; vtype[i] = DOUBLE; } else if (strcmp(arg[iarg],"fy") == 0) { pack_choice[i] = &DumpCustom::pack_fy; vtype[i] = DOUBLE; } else if (strcmp(arg[iarg],"fz") == 0) { pack_choice[i] = &DumpCustom::pack_fz; vtype[i] = DOUBLE; } else if (strcmp(arg[iarg],"q") == 0) { if (!atom->q_flag) error->all(FLERR,"Dumping an atom property that isn't allocated"); pack_choice[i] = &DumpCustom::pack_q; vtype[i] = DOUBLE; } else if (strcmp(arg[iarg],"mux") == 0) { if (!atom->mu_flag) error->all(FLERR,"Dumping an atom property that isn't allocated"); pack_choice[i] = &DumpCustom::pack_mux; vtype[i] = DOUBLE; } else if (strcmp(arg[iarg],"muy") == 0) { if (!atom->mu_flag) error->all(FLERR,"Dumping an atom property that isn't allocated"); pack_choice[i] = &DumpCustom::pack_muy; vtype[i] = DOUBLE; } else if (strcmp(arg[iarg],"muz") == 0) { if (!atom->mu_flag) error->all(FLERR,"Dumping an atom property that isn't allocated"); pack_choice[i] = &DumpCustom::pack_muz; vtype[i] = DOUBLE; } else if (strcmp(arg[iarg],"mu") == 0) { if (!atom->mu_flag) error->all(FLERR,"Dumping an atom property that isn't allocated"); pack_choice[i] = &DumpCustom::pack_mu; vtype[i] = DOUBLE; } else if (strcmp(arg[iarg],"radius") == 0) { if (!atom->radius_flag) error->all(FLERR,"Dumping an atom property that isn't allocated"); pack_choice[i] = &DumpCustom::pack_radius; vtype[i] = DOUBLE; } else if (strcmp(arg[iarg],"diameter") == 0) { if (!atom->radius_flag) error->all(FLERR,"Dumping an atom property that isn't allocated"); pack_choice[i] = &DumpCustom::pack_diameter; vtype[i] = DOUBLE; } else if (strcmp(arg[iarg],"omegax") == 0) { if (!atom->omega_flag) error->all(FLERR,"Dumping an atom property that isn't allocated"); pack_choice[i] = &DumpCustom::pack_omegax; vtype[i] = DOUBLE; } else if (strcmp(arg[iarg],"omegay") == 0) { if (!atom->omega_flag) error->all(FLERR,"Dumping an atom property that isn't allocated"); pack_choice[i] = &DumpCustom::pack_omegay; vtype[i] = DOUBLE; } else if (strcmp(arg[iarg],"omegaz") == 0) { if (!atom->omega_flag) error->all(FLERR,"Dumping an atom property that isn't allocated"); pack_choice[i] = &DumpCustom::pack_omegaz; vtype[i] = DOUBLE; } else if (strcmp(arg[iarg],"angmomx") == 0) { if (!atom->angmom_flag) error->all(FLERR,"Dumping an atom property that isn't allocated"); pack_choice[i] = &DumpCustom::pack_angmomx; vtype[i] = DOUBLE; } else if (strcmp(arg[iarg],"angmomy") == 0) { if (!atom->angmom_flag) error->all(FLERR,"Dumping an atom property that isn't allocated"); pack_choice[i] = &DumpCustom::pack_angmomy; vtype[i] = DOUBLE; } else if (strcmp(arg[iarg],"angmomz") == 0) { if (!atom->angmom_flag) error->all(FLERR,"Dumping an atom property that isn't allocated"); pack_choice[i] = &DumpCustom::pack_angmomz; vtype[i] = DOUBLE; } else if (strcmp(arg[iarg],"tqx") == 0) { if (!atom->torque_flag) error->all(FLERR,"Dumping an atom property that isn't allocated"); pack_choice[i] = &DumpCustom::pack_tqx; vtype[i] = DOUBLE; } else if (strcmp(arg[iarg],"tqy") == 0) { if (!atom->torque_flag) error->all(FLERR,"Dumping an atom property that isn't allocated"); pack_choice[i] = &DumpCustom::pack_tqy; vtype[i] = DOUBLE; } else if (strcmp(arg[iarg],"tqz") == 0) { if (!atom->torque_flag) error->all(FLERR,"Dumping an atom property that isn't allocated"); pack_choice[i] = &DumpCustom::pack_tqz; vtype[i] = DOUBLE; } else if (strcmp(arg[iarg],"spin") == 0) { if (!atom->spin_flag) error->all(FLERR,"Dumping an atom quantity that isn't allocated"); pack_choice[i] = &DumpCustom::pack_spin; vtype[i] = INT; } else if (strcmp(arg[iarg],"eradius") == 0) { if (!atom->eradius_flag) error->all(FLERR,"Dumping an atom quantity that isn't allocated"); pack_choice[i] = &DumpCustom::pack_eradius; vtype[i] = DOUBLE; } else if (strcmp(arg[iarg],"ervel") == 0) { if (!atom->ervel_flag) error->all(FLERR,"Dumping an atom quantity that isn't allocated"); pack_choice[i] = &DumpCustom::pack_ervel; vtype[i] = DOUBLE; } else if (strcmp(arg[iarg],"erforce") == 0) { if (!atom->erforce_flag) error->all(FLERR,"Dumping an atom quantity that isn't allocated"); pack_choice[i] = &DumpCustom::pack_erforce; vtype[i] = DOUBLE; // compute value = c_ID // if no trailing [], then arg is set to 0, else arg is int between [] } else if (strncmp(arg[iarg],"c_",2) == 0) { pack_choice[i] = &DumpCustom::pack_compute; vtype[i] = DOUBLE; int n = strlen(arg[iarg]); char *suffix = new char[n]; strcpy(suffix,&arg[iarg][2]); char *ptr = strchr(suffix,'['); if (ptr) { if (suffix[strlen(suffix)-1] != ']') error->all(FLERR,"Invalid attribute in dump custom command"); argindex[i] = atoi(ptr+1); *ptr = '\0'; } else argindex[i] = 0; n = modify->find_compute(suffix); if (n < 0) error->all(FLERR,"Could not find dump custom compute ID"); if (modify->compute[n]->peratom_flag == 0) error->all(FLERR,"Dump custom compute does not compute per-atom info"); if (argindex[i] == 0 && modify->compute[n]->size_peratom_cols > 0) error->all(FLERR,"Dump custom compute does not calculate per-atom vector"); if (argindex[i] > 0 && modify->compute[n]->size_peratom_cols == 0) error->all(FLERR,"Dump custom compute does not calculate per-atom array"); if (argindex[i] > 0 && argindex[i] > modify->compute[n]->size_peratom_cols) error->all(FLERR,"Dump custom compute vector is accessed out-of-range"); field2index[i] = add_compute(suffix); delete [] suffix; // fix value = f_ID // if no trailing [], then arg is set to 0, else arg is between [] } else if (strncmp(arg[iarg],"f_",2) == 0) { pack_choice[i] = &DumpCustom::pack_fix; vtype[i] = DOUBLE; int n = strlen(arg[iarg]); char *suffix = new char[n]; strcpy(suffix,&arg[iarg][2]); char *ptr = strchr(suffix,'['); if (ptr) { if (suffix[strlen(suffix)-1] != ']') error->all(FLERR,"Invalid attribute in dump custom command"); argindex[i] = atoi(ptr+1); *ptr = '\0'; } else argindex[i] = 0; n = modify->find_fix(suffix); if (n < 0) error->all(FLERR,"Could not find dump custom fix ID"); if (modify->fix[n]->peratom_flag == 0) error->all(FLERR,"Dump custom fix does not compute per-atom info"); if (argindex[i] == 0 && modify->fix[n]->size_peratom_cols > 0) error->all(FLERR,"Dump custom fix does not compute per-atom vector"); if (argindex[i] > 0 && modify->fix[n]->size_peratom_cols == 0) error->all(FLERR,"Dump custom fix does not compute per-atom array"); if (argindex[i] > 0 && argindex[i] > modify->fix[n]->size_peratom_cols) error->all(FLERR,"Dump custom fix vector is accessed out-of-range"); field2index[i] = add_fix(suffix); delete [] suffix; // variable value = v_name } else if (strncmp(arg[iarg],"v_",2) == 0) { pack_choice[i] = &DumpCustom::pack_variable; vtype[i] = DOUBLE; int n = strlen(arg[iarg]); char *suffix = new char[n]; strcpy(suffix,&arg[iarg][2]); argindex[i] = 0; n = input->variable->find(suffix); if (n < 0) error->all(FLERR,"Could not find dump custom variable name"); if (input->variable->atomstyle(n) == 0) error->all(FLERR,"Dump custom variable is not atom-style variable"); field2index[i] = add_variable(suffix); delete [] suffix; } else return iarg; } return narg; } /* ---------------------------------------------------------------------- add Compute to list of Compute objects used by dump return index of where this Compute is in list if already in list, do not add, just return index, else add to list ------------------------------------------------------------------------- */ int DumpCustom::add_compute(char *id) { int icompute; for (icompute = 0; icompute < ncompute; icompute++) if (strcmp(id,id_compute[icompute]) == 0) break; if (icompute < ncompute) return icompute; id_compute = (char **) memory->srealloc(id_compute,(ncompute+1)*sizeof(char *),"dump:id_compute"); delete [] compute; compute = new Compute*[ncompute+1]; int n = strlen(id) + 1; id_compute[ncompute] = new char[n]; strcpy(id_compute[ncompute],id); ncompute++; return ncompute-1; } /* ---------------------------------------------------------------------- add Fix to list of Fix objects used by dump return index of where this Fix is in list if already in list, do not add, just return index, else add to list ------------------------------------------------------------------------- */ int DumpCustom::add_fix(char *id) { int ifix; for (ifix = 0; ifix < nfix; ifix++) if (strcmp(id,id_fix[ifix]) == 0) break; if (ifix < nfix) return ifix; id_fix = (char **) memory->srealloc(id_fix,(nfix+1)*sizeof(char *),"dump:id_fix"); delete [] fix; fix = new Fix*[nfix+1]; int n = strlen(id) + 1; id_fix[nfix] = new char[n]; strcpy(id_fix[nfix],id); nfix++; return nfix-1; } /* ---------------------------------------------------------------------- add Variable to list of Variables used by dump return index of where this Variable is in list if already in list, do not add, just return index, else add to list ------------------------------------------------------------------------- */ int DumpCustom::add_variable(char *id) { int ivariable; for (ivariable = 0; ivariable < nvariable; ivariable++) if (strcmp(id,id_variable[ivariable]) == 0) break; if (ivariable < nvariable) return ivariable; id_variable = (char **) memory->srealloc(id_variable,(nvariable+1)*sizeof(char *), "dump:id_variable"); delete [] variable; variable = new int[nvariable+1]; delete [] vbuf; vbuf = new double*[nvariable+1]; for (int i = 0; i <= nvariable; i++) vbuf[i] = NULL; int n = strlen(id) + 1; id_variable[nvariable] = new char[n]; strcpy(id_variable[nvariable],id); nvariable++; return nvariable-1; } /* ---------------------------------------------------------------------- */ int DumpCustom::modify_param(int narg, char **arg) { if (strcmp(arg[0],"region") == 0) { if (narg < 2) error->all(FLERR,"Illegal dump_modify command"); if (strcmp(arg[1],"none") == 0) iregion = -1; else { iregion = domain->find_region(arg[1]); if (iregion == -1) error->all(FLERR,"Dump_modify region ID does not exist"); int n = strlen(arg[1]) + 1; idregion = new char[n]; strcpy(idregion,arg[1]); } return 2; } if (strcmp(arg[0],"element") == 0) { if (narg < ntypes+1) error->all(FLERR,"Dump modify element names do not match atom types"); if (typenames) { for (int i = 1; i <= ntypes; i++) delete [] typenames[i]; delete [] typenames; typenames = NULL; } typenames = new char*[ntypes+1]; for (int itype = 1; itype <= ntypes; itype++) { int n = strlen(arg[itype]) + 1; typenames[itype] = new char[n]; strcpy(typenames[itype],arg[itype]); } return ntypes+1; } if (strcmp(arg[0],"thresh") == 0) { if (narg < 2) error->all(FLERR,"Illegal dump_modify command"); if (strcmp(arg[1],"none") == 0) { if (nthresh) { memory->destroy(thresh_array); memory->destroy(thresh_op); memory->destroy(thresh_value); thresh_array = NULL; thresh_op = NULL; thresh_value = NULL; } nthresh = 0; return 2; } if (narg < 4) error->all(FLERR,"Illegal dump_modify command"); // grow threshhold arrays memory->grow(thresh_array,nthresh+1,"dump:thresh_array"); memory->grow(thresh_op,(nthresh+1),"dump:thresh_op"); memory->grow(thresh_value,(nthresh+1),"dump:thresh_value"); // set attribute type of threshhold // customize by adding to if statement if (strcmp(arg[1],"id") == 0) thresh_array[nthresh] = ID; else if (strcmp(arg[1],"mol") == 0) thresh_array[nthresh] = MOL; else if (strcmp(arg[1],"type") == 0) thresh_array[nthresh] = TYPE; else if (strcmp(arg[1],"mass") == 0) thresh_array[nthresh] = MASS; else if (strcmp(arg[1],"x") == 0) thresh_array[nthresh] = X; else if (strcmp(arg[1],"y") == 0) thresh_array[nthresh] = Y; else if (strcmp(arg[1],"z") == 0) thresh_array[nthresh] = Z; else if (strcmp(arg[1],"xs") == 0 && domain->triclinic == 0) thresh_array[nthresh] = XS; else if (strcmp(arg[1],"xs") == 0 && domain->triclinic == 1) thresh_array[nthresh] = XSTRI; else if (strcmp(arg[1],"ys") == 0 && domain->triclinic == 0) thresh_array[nthresh] = YS; else if (strcmp(arg[1],"ys") == 0 && domain->triclinic == 1) thresh_array[nthresh] = YSTRI; else if (strcmp(arg[1],"zs") == 0 && domain->triclinic == 0) thresh_array[nthresh] = ZS; else if (strcmp(arg[1],"zs") == 0 && domain->triclinic == 1) thresh_array[nthresh] = ZSTRI; else if (strcmp(arg[1],"xu") == 0 && domain->triclinic == 0) thresh_array[nthresh] = XU; else if (strcmp(arg[1],"xu") == 0 && domain->triclinic == 1) thresh_array[nthresh] = XUTRI; else if (strcmp(arg[1],"yu") == 0 && domain->triclinic == 0) thresh_array[nthresh] = YU; else if (strcmp(arg[1],"yu") == 0 && domain->triclinic == 1) thresh_array[nthresh] = YUTRI; else if (strcmp(arg[1],"zu") == 0 && domain->triclinic == 0) thresh_array[nthresh] = ZU; else if (strcmp(arg[1],"zu") == 0 && domain->triclinic == 1) thresh_array[nthresh] = ZUTRI; else if (strcmp(arg[1],"xsu") == 0 && domain->triclinic == 0) thresh_array[nthresh] = XSU; else if (strcmp(arg[1],"xsu") == 0 && domain->triclinic == 1) thresh_array[nthresh] = XSUTRI; else if (strcmp(arg[1],"ysu") == 0 && domain->triclinic == 0) thresh_array[nthresh] = YSU; else if (strcmp(arg[1],"ysu") == 0 && domain->triclinic == 1) thresh_array[nthresh] = YSUTRI; else if (strcmp(arg[1],"zsu") == 0 && domain->triclinic == 0) thresh_array[nthresh] = ZSU; else if (strcmp(arg[1],"zsu") == 0 && domain->triclinic == 1) thresh_array[nthresh] = ZSUTRI; else if (strcmp(arg[1],"ix") == 0) thresh_array[nthresh] = IX; else if (strcmp(arg[1],"iy") == 0) thresh_array[nthresh] = IY; else if (strcmp(arg[1],"iz") == 0) thresh_array[nthresh] = IZ; else if (strcmp(arg[1],"vx") == 0) thresh_array[nthresh] = VX; else if (strcmp(arg[1],"vy") == 0) thresh_array[nthresh] = VY; else if (strcmp(arg[1],"vz") == 0) thresh_array[nthresh] = VZ; else if (strcmp(arg[1],"fx") == 0) thresh_array[nthresh] = FX; else if (strcmp(arg[1],"fy") == 0) thresh_array[nthresh] = FY; else if (strcmp(arg[1],"fz") == 0) thresh_array[nthresh] = FZ; else if (strcmp(arg[1],"q") == 0) thresh_array[nthresh] = Q; else if (strcmp(arg[1],"mux") == 0) thresh_array[nthresh] = MUX; else if (strcmp(arg[1],"muy") == 0) thresh_array[nthresh] = MUY; else if (strcmp(arg[1],"muz") == 0) thresh_array[nthresh] = MUZ; else if (strcmp(arg[1],"mu") == 0) thresh_array[nthresh] = MU; else if (strcmp(arg[1],"radius") == 0) thresh_array[nthresh] = RADIUS; else if (strcmp(arg[1],"diameter") == 0) thresh_array[nthresh] = DIAMETER; else if (strcmp(arg[1],"omegax") == 0) thresh_array[nthresh] = OMEGAX; else if (strcmp(arg[1],"omegay") == 0) thresh_array[nthresh] = OMEGAY; else if (strcmp(arg[1],"omegaz") == 0) thresh_array[nthresh] = OMEGAZ; else if (strcmp(arg[1],"angmomx") == 0) thresh_array[nthresh] = ANGMOMX; else if (strcmp(arg[1],"angmomy") == 0) thresh_array[nthresh] = ANGMOMY; else if (strcmp(arg[1],"angmomz") == 0) thresh_array[nthresh] = ANGMOMZ; else if (strcmp(arg[1],"tqx") == 0) thresh_array[nthresh] = TQX; else if (strcmp(arg[1],"tqy") == 0) thresh_array[nthresh] = TQY; else if (strcmp(arg[1],"tqz") == 0) thresh_array[nthresh] = TQZ; else if (strcmp(arg[1],"spin") == 0) thresh_array[nthresh] = SPIN; else if (strcmp(arg[1],"eradius") == 0) thresh_array[nthresh] = ERADIUS; else if (strcmp(arg[1],"ervel") == 0) thresh_array[nthresh] = ERVEL; else if (strcmp(arg[1],"erforce") == 0) thresh_array[nthresh] = ERFORCE; // compute value = c_ID // if no trailing [], then arg is set to 0, else arg is between [] // must grow field2index and argindex arrays, since access is beyond nfield else if (strncmp(arg[1],"c_",2) == 0) { thresh_array[nthresh] = COMPUTE; memory->grow(field2index,nfield+nthresh+1,"dump:field2index"); memory->grow(argindex,nfield+nthresh+1,"dump:argindex"); int n = strlen(arg[1]); char *suffix = new char[n]; strcpy(suffix,&arg[1][2]); char *ptr = strchr(suffix,'['); if (ptr) { if (suffix[strlen(suffix)-1] != ']') error->all(FLERR,"Invalid attribute in dump modify command"); argindex[nfield+nthresh] = atoi(ptr+1); *ptr = '\0'; } else argindex[nfield+nthresh] = 0; n = modify->find_compute(suffix); if (n < 0) error->all(FLERR,"Could not find dump modify compute ID"); if (modify->compute[n]->peratom_flag == 0) error->all(FLERR, "Dump modify compute ID does not compute per-atom info"); if (argindex[nfield+nthresh] == 0 && modify->compute[n]->size_peratom_cols > 0) error->all(FLERR, "Dump modify compute ID does not compute per-atom vector"); if (argindex[nfield+nthresh] > 0 && modify->compute[n]->size_peratom_cols == 0) error->all(FLERR, "Dump modify compute ID does not compute per-atom array"); if (argindex[nfield+nthresh] > 0 && argindex[nfield+nthresh] > modify->compute[n]->size_peratom_cols) error->all(FLERR,"Dump modify compute ID vector is not large enough"); field2index[nfield+nthresh] = add_compute(suffix); delete [] suffix; // fix value = f_ID // if no trailing [], then arg is set to 0, else arg is between [] // must grow field2index and argindex arrays, since access is beyond nfield } else if (strncmp(arg[1],"f_",2) == 0) { thresh_array[nthresh] = FIX; memory->grow(field2index,nfield+nthresh+1,"dump:field2index"); memory->grow(argindex,nfield+nthresh+1,"dump:argindex"); int n = strlen(arg[1]); char *suffix = new char[n]; strcpy(suffix,&arg[1][2]); char *ptr = strchr(suffix,'['); if (ptr) { if (suffix[strlen(suffix)-1] != ']') error->all(FLERR,"Invalid attribute in dump modify command"); argindex[nfield+nthresh] = atoi(ptr+1); *ptr = '\0'; } else argindex[nfield+nthresh] = 0; n = modify->find_fix(suffix); if (n < 0) error->all(FLERR,"Could not find dump modify fix ID"); if (modify->fix[n]->peratom_flag == 0) error->all(FLERR,"Dump modify fix ID does not compute per-atom info"); if (argindex[nfield+nthresh] == 0 && modify->fix[n]->size_peratom_cols > 0) error->all(FLERR,"Dump modify fix ID does not compute per-atom vector"); if (argindex[nfield+nthresh] > 0 && modify->fix[n]->size_peratom_cols == 0) error->all(FLERR,"Dump modify fix ID does not compute per-atom array"); if (argindex[nfield+nthresh] > 0 && argindex[nfield+nthresh] > modify->fix[n]->size_peratom_cols) error->all(FLERR,"Dump modify fix ID vector is not large enough"); field2index[nfield+nthresh] = add_fix(suffix); delete [] suffix; // variable value = v_ID // must grow field2index and argindex arrays, since access is beyond nfield } else if (strncmp(arg[1],"v_",2) == 0) { thresh_array[nthresh] = VARIABLE; memory->grow(field2index,nfield+nthresh+1,"dump:field2index"); memory->grow(argindex,nfield+nthresh+1,"dump:argindex"); int n = strlen(arg[1]); char *suffix = new char[n]; strcpy(suffix,&arg[1][2]); argindex[nfield+nthresh] = 0; n = input->variable->find(suffix); if (n < 0) error->all(FLERR,"Could not find dump modify variable name"); if (input->variable->atomstyle(n) == 0) error->all(FLERR,"Dump modify variable is not atom-style variable"); field2index[nfield+nthresh] = add_variable(suffix); delete [] suffix; } else error->all(FLERR,"Invalid dump_modify threshhold operator"); // set operation type of threshhold if (strcmp(arg[2],"<") == 0) thresh_op[nthresh] = LT; else if (strcmp(arg[2],"<=") == 0) thresh_op[nthresh] = LE; else if (strcmp(arg[2],">") == 0) thresh_op[nthresh] = GT; else if (strcmp(arg[2],">=") == 0) thresh_op[nthresh] = GE; else if (strcmp(arg[2],"==") == 0) thresh_op[nthresh] = EQ; else if (strcmp(arg[2],"!=") == 0) thresh_op[nthresh] = NEQ; else error->all(FLERR,"Invalid dump_modify threshhold operator"); // set threshhold value thresh_value[nthresh] = force->numeric(FLERR,arg[3]); nthresh++; return 4; } return 0; } /* ---------------------------------------------------------------------- return # of bytes of allocated memory in buf, choose, variable arrays ------------------------------------------------------------------------- */ bigint DumpCustom::memory_usage() { bigint bytes = Dump::memory_usage(); bytes += memory->usage(choose,maxlocal); bytes += memory->usage(dchoose,maxlocal); bytes += memory->usage(clist,maxlocal); bytes += memory->usage(vbuf,nvariable,maxlocal); return bytes; } /* ---------------------------------------------------------------------- extraction of Compute, Fix, Variable results ------------------------------------------------------------------------- */ void DumpCustom::pack_compute(int n) { double *vector = compute[field2index[n]]->vector_atom; double **array = compute[field2index[n]]->array_atom; int index = argindex[n]; if (index == 0) { for (int i = 0; i < nchoose; i++) { buf[n] = vector[clist[i]]; n += size_one; } } else { index--; for (int i = 0; i < nchoose; i++) { buf[n] = array[clist[i]][index]; n += size_one; } } } /* ---------------------------------------------------------------------- */ void DumpCustom::pack_fix(int n) { double *vector = fix[field2index[n]]->vector_atom; double **array = fix[field2index[n]]->array_atom; int index = argindex[n]; if (index == 0) { for (int i = 0; i < nchoose; i++) { buf[n] = vector[clist[i]]; n += size_one; } } else { index--; for (int i = 0; i < nchoose; i++) { buf[n] = array[clist[i]][index]; n += size_one; } } } /* ---------------------------------------------------------------------- */ void DumpCustom::pack_variable(int n) { double *vector = vbuf[field2index[n]]; for (int i = 0; i < nchoose; i++) { buf[n] = vector[clist[i]]; n += size_one; } } /* ---------------------------------------------------------------------- one method for every attribute dump custom can output the atom property is packed into buf starting at n with stride size_one customize a new attribute by adding a method ------------------------------------------------------------------------- */ void DumpCustom::pack_id(int n) { int *tag = atom->tag; for (int i = 0; i < nchoose; i++) { buf[n] = tag[clist[i]]; n += size_one; } } /* ---------------------------------------------------------------------- */ void DumpCustom::pack_molecule(int n) { int *molecule = atom->molecule; for (int i = 0; i < nchoose; i++) { buf[n] = molecule[clist[i]]; n += size_one; } } /* ---------------------------------------------------------------------- */ void DumpCustom::pack_type(int n) { int *type = atom->type; for (int i = 0; i < nchoose; i++) { buf[n] = type[clist[i]]; n += size_one; } } /* ---------------------------------------------------------------------- */ void DumpCustom::pack_mass(int n) { int *type = atom->type; double *mass = atom->mass; double *rmass = atom->rmass; if (rmass) { for (int i = 0; i < nchoose; i++) { buf[n] = rmass[clist[i]]; n += size_one; } } else { for (int i = 0; i < nchoose; i++) { buf[n] = mass[type[clist[i]]]; n += size_one; } } } /* ---------------------------------------------------------------------- */ void DumpCustom::pack_x(int n) { double **x = atom->x; for (int i = 0; i < nchoose; i++) { buf[n] = x[clist[i]][0]; n += size_one; } } /* ---------------------------------------------------------------------- */ void DumpCustom::pack_y(int n) { double **x = atom->x; for (int i = 0; i < nchoose; i++) { buf[n] = x[clist[i]][1]; n += size_one; } } /* ---------------------------------------------------------------------- */ void DumpCustom::pack_z(int n) { double **x = atom->x; for (int i = 0; i < nchoose; i++) { buf[n] = x[clist[i]][2]; n += size_one; } } /* ---------------------------------------------------------------------- */ void DumpCustom::pack_xs(int n) { double **x = atom->x; double boxxlo = domain->boxlo[0]; double invxprd = 1.0/domain->xprd; for (int i = 0; i < nchoose; i++) { buf[n] = (x[clist[i]][0] - boxxlo) * invxprd; n += size_one; } } /* ---------------------------------------------------------------------- */ void DumpCustom::pack_ys(int n) { double **x = atom->x; double boxylo = domain->boxlo[1]; double invyprd = 1.0/domain->yprd; for (int i = 0; i < nchoose; i++) { buf[n] = (x[clist[i]][1] - boxylo) * invyprd; n += size_one; } } /* ---------------------------------------------------------------------- */ void DumpCustom::pack_zs(int n) { double **x = atom->x; double boxzlo = domain->boxlo[2]; double invzprd = 1.0/domain->zprd; for (int i = 0; i < nchoose; i++) { buf[n] = (x[clist[i]][2] - boxzlo) * invzprd; n += size_one; } } /* ---------------------------------------------------------------------- */ void DumpCustom::pack_xs_triclinic(int n) { int j; double **x = atom->x; double *boxlo = domain->boxlo; double *h_inv = domain->h_inv; for (int i = 0; i < nchoose; i++) { j = clist[i]; buf[n] = h_inv[0]*(x[j][0]-boxlo[0]) + h_inv[5]*(x[j][1]-boxlo[1]) + h_inv[4]*(x[j][2]-boxlo[2]); n += size_one; } } /* ---------------------------------------------------------------------- */ void DumpCustom::pack_ys_triclinic(int n) { int j; double **x = atom->x; double *boxlo = domain->boxlo; double *h_inv = domain->h_inv; for (int i = 0; i < nchoose; i++) { j = clist[i]; buf[n] = h_inv[1]*(x[j][1]-boxlo[1]) + h_inv[3]*(x[j][2]-boxlo[2]); n += size_one; } } /* ---------------------------------------------------------------------- */ void DumpCustom::pack_zs_triclinic(int n) { double **x = atom->x; double *boxlo = domain->boxlo; double *h_inv = domain->h_inv; for (int i = 0; i < nchoose; i++) { buf[n] = h_inv[2]*(x[clist[i]][2]-boxlo[2]); n += size_one; } } /* ---------------------------------------------------------------------- */ void DumpCustom::pack_xu(int n) { int j; double **x = atom->x; tagint *image = atom->image; double xprd = domain->xprd; for (int i = 0; i < nchoose; i++) { j = clist[i]; buf[n] = x[j][0] + ((image[j] & IMGMASK) - IMGMAX) * xprd; n += size_one; } } /* ---------------------------------------------------------------------- */ void DumpCustom::pack_yu(int n) { int j; double **x = atom->x; tagint *image = atom->image; double yprd = domain->yprd; for (int i = 0; i < nchoose; i++) { j = clist[i]; buf[n] = x[j][1] + ((image[j] >> IMGBITS & IMGMASK) - IMGMAX) * yprd; n += size_one; } } /* ---------------------------------------------------------------------- */ void DumpCustom::pack_zu(int n) { int j; double **x = atom->x; tagint *image = atom->image; double zprd = domain->zprd; for (int i = 0; i < nchoose; i++) { j = clist[i]; buf[n] = x[j][2] + ((image[j] >> IMG2BITS) - IMGMAX) * zprd; n += size_one; } } /* ---------------------------------------------------------------------- */ void DumpCustom::pack_xu_triclinic(int n) { int j; double **x = atom->x; tagint *image = atom->image; double *h = domain->h; int xbox,ybox,zbox; for (int i = 0; i < nchoose; i++) { j = clist[i]; xbox = (image[j] & IMGMASK) - IMGMAX; ybox = (image[j] >> IMGBITS & IMGMASK) - IMGMAX; zbox = (image[j] >> IMG2BITS) - IMGMAX; buf[n] = x[j][0] + h[0]*xbox + h[5]*ybox + h[4]*zbox; n += size_one; } } /* ---------------------------------------------------------------------- */ void DumpCustom::pack_yu_triclinic(int n) { int j; double **x = atom->x; tagint *image = atom->image; double *h = domain->h; int ybox,zbox; for (int i = 0; i < nchoose; i++) { j = clist[i]; ybox = (image[j] >> IMGBITS & IMGMASK) - IMGMAX; zbox = (image[j] >> IMG2BITS) - IMGMAX; buf[n] = x[j][1] + h[1]*ybox + h[3]*zbox; n += size_one; } } /* ---------------------------------------------------------------------- */ void DumpCustom::pack_zu_triclinic(int n) { int j; double **x = atom->x; tagint *image = atom->image; double *h = domain->h; int zbox; for (int i = 0; i < nchoose; i++) { j = clist[i]; zbox = (image[j] >> IMG2BITS) - IMGMAX; buf[n] = x[j][2] + h[2]*zbox; n += size_one; } } /* ---------------------------------------------------------------------- */ void DumpCustom::pack_xsu(int n) { int j; double **x = atom->x; tagint *image = atom->image; double boxxlo = domain->boxlo[0]; double invxprd = 1.0/domain->xprd; for (int i = 0; i < nchoose; i++) { j = clist[i]; buf[n] = (x[j][0] - boxxlo) * invxprd + (image[j] & IMGMASK) - IMGMAX; n += size_one; } } /* ---------------------------------------------------------------------- */ void DumpCustom::pack_ysu(int n) { int j; double **x = atom->x; tagint *image = atom->image; double boxylo = domain->boxlo[1]; double invyprd = 1.0/domain->yprd; for (int i = 0; i < nchoose; i++) { j = clist[i]; buf[n] = (x[j][1] - boxylo) * invyprd + (image[j] >> IMGBITS & IMGMASK) - IMGMAX; n += size_one; } } /* ---------------------------------------------------------------------- */ void DumpCustom::pack_zsu(int n) { int j; double **x = atom->x; tagint *image = atom->image; double boxzlo = domain->boxlo[2]; double invzprd = 1.0/domain->zprd; for (int i = 0; i < nchoose; i++) { j = clist[i]; buf[n] = (x[j][2] - boxzlo) * invzprd + (image[j] >> IMG2BITS) - IMGMAX; n += size_one; } } /* ---------------------------------------------------------------------- */ void DumpCustom::pack_xsu_triclinic(int n) { int j; double **x = atom->x; tagint *image = atom->image; double *boxlo = domain->boxlo; double *h_inv = domain->h_inv; for (int i = 0; i < nchoose; i++) { j = clist[i]; buf[n] = h_inv[0]*(x[j][0]-boxlo[0]) + h_inv[5]*(x[j][1]-boxlo[1]) + h_inv[4]*(x[j][2]-boxlo[2]) + (image[j] & IMGMASK) - IMGMAX; n += size_one; } } /* ---------------------------------------------------------------------- */ void DumpCustom::pack_ysu_triclinic(int n) { int j; double **x = atom->x; tagint *image = atom->image; double *boxlo = domain->boxlo; double *h_inv = domain->h_inv; for (int i = 0; i < nchoose; i++) { j = clist[i]; buf[n] = h_inv[1]*(x[j][1]-boxlo[1]) + h_inv[3]*(x[j][2]-boxlo[2]) + (image[j] >> IMGBITS & IMGMASK) - IMGMAX; n += size_one; } } /* ---------------------------------------------------------------------- */ void DumpCustom::pack_zsu_triclinic(int n) { int j; double **x = atom->x; tagint *image = atom->image; double *boxlo = domain->boxlo; double *h_inv = domain->h_inv; for (int i = 0; i < nchoose; i++) { j = clist[i]; buf[n] = h_inv[2]*(x[j][2]-boxlo[2]) + (image[j] >> IMG2BITS) - IMGMAX; n += size_one; } } /* ---------------------------------------------------------------------- */ void DumpCustom::pack_ix(int n) { tagint *image = atom->image; for (int i = 0; i < nchoose; i++) { buf[n] = (image[clist[i]] & IMGMASK) - IMGMAX; n += size_one; } } /* ---------------------------------------------------------------------- */ void DumpCustom::pack_iy(int n) { tagint *image = atom->image; for (int i = 0; i < nchoose; i++) { buf[n] = (image[clist[i]] >> IMGBITS & IMGMASK) - IMGMAX; n += size_one; } } /* ---------------------------------------------------------------------- */ void DumpCustom::pack_iz(int n) { tagint *image = atom->image; for (int i = 0; i < nchoose; i++) { buf[n] = (image[clist[i]] >> IMG2BITS) - IMGMAX; n += size_one; } } /* ---------------------------------------------------------------------- */ void DumpCustom::pack_vx(int n) { double **v = atom->v; for (int i = 0; i < nchoose; i++) { buf[n] = v[clist[i]][0]; n += size_one; } } /* ---------------------------------------------------------------------- */ void DumpCustom::pack_vy(int n) { double **v = atom->v; for (int i = 0; i < nchoose; i++) { buf[n] = v[clist[i]][1]; n += size_one; } } /* ---------------------------------------------------------------------- */ void DumpCustom::pack_vz(int n) { double **v = atom->v; for (int i = 0; i < nchoose; i++) { buf[n] = v[clist[i]][2]; n += size_one; } } /* ---------------------------------------------------------------------- */ void DumpCustom::pack_fx(int n) { double **f = atom->f; for (int i = 0; i < nchoose; i++) { buf[n] = f[clist[i]][0]; n += size_one; } } /* ---------------------------------------------------------------------- */ void DumpCustom::pack_fy(int n) { double **f = atom->f; for (int i = 0; i < nchoose; i++) { buf[n] = f[clist[i]][1]; n += size_one; } } /* ---------------------------------------------------------------------- */ void DumpCustom::pack_fz(int n) { double **f = atom->f; for (int i = 0; i < nchoose; i++) { buf[n] = f[clist[i]][2]; n += size_one; } } /* ---------------------------------------------------------------------- */ void DumpCustom::pack_q(int n) { double *q = atom->q; for (int i = 0; i < nchoose; i++) { buf[n] = q[clist[i]]; n += size_one; } } /* ---------------------------------------------------------------------- */ void DumpCustom::pack_mux(int n) { double **mu = atom->mu; for (int i = 0; i < nchoose; i++) { buf[n] = mu[clist[i]][0]; n += size_one; } } /* ---------------------------------------------------------------------- */ void DumpCustom::pack_muy(int n) { double **mu = atom->mu; for (int i = 0; i < nchoose; i++) { buf[n] = mu[clist[i]][1]; n += size_one; } } /* ---------------------------------------------------------------------- */ void DumpCustom::pack_muz(int n) { double **mu = atom->mu; for (int i = 0; i < nchoose; i++) { buf[n] = mu[clist[i]][2]; n += size_one; } } /* ---------------------------------------------------------------------- */ void DumpCustom::pack_mu(int n) { double **mu = atom->mu; for (int i = 0; i < nchoose; i++) { buf[n] = mu[clist[i]][3]; n += size_one; } } /* ---------------------------------------------------------------------- */ void DumpCustom::pack_radius(int n) { double *radius = atom->radius; for (int i = 0; i < nchoose; i++) { buf[n] = radius[clist[i]]; n += size_one; } } /* ---------------------------------------------------------------------- */ void DumpCustom::pack_diameter(int n) { double *radius = atom->radius; for (int i = 0; i < nchoose; i++) { buf[n] = 2.0*radius[clist[i]]; n += size_one; } } /* ---------------------------------------------------------------------- */ void DumpCustom::pack_omegax(int n) { double **omega = atom->omega; for (int i = 0; i < nchoose; i++) { buf[n] = omega[clist[i]][0]; n += size_one; } } /* ---------------------------------------------------------------------- */ void DumpCustom::pack_omegay(int n) { double **omega = atom->omega; for (int i = 0; i < nchoose; i++) { buf[n] = omega[clist[i]][1]; n += size_one; } } /* ---------------------------------------------------------------------- */ void DumpCustom::pack_omegaz(int n) { double **omega = atom->omega; for (int i = 0; i < nchoose; i++) { buf[n] = omega[clist[i]][2]; n += size_one; } } /* ---------------------------------------------------------------------- */ void DumpCustom::pack_angmomx(int n) { double **angmom = atom->angmom; for (int i = 0; i < nchoose; i++) { buf[n] = angmom[clist[i]][0]; n += size_one; } } /* ---------------------------------------------------------------------- */ void DumpCustom::pack_angmomy(int n) { double **angmom = atom->angmom; for (int i = 0; i < nchoose; i++) { buf[n] = angmom[clist[i]][1]; n += size_one; } } /* ---------------------------------------------------------------------- */ void DumpCustom::pack_angmomz(int n) { double **angmom = atom->angmom; for (int i = 0; i < nchoose; i++) { buf[n] = angmom[clist[i]][2]; n += size_one; } } /* ---------------------------------------------------------------------- */ void DumpCustom::pack_tqx(int n) { double **torque = atom->torque; for (int i = 0; i < nchoose; i++) { buf[n] = torque[clist[i]][0]; n += size_one; } } /* ---------------------------------------------------------------------- */ void DumpCustom::pack_tqy(int n) { double **torque = atom->torque; for (int i = 0; i < nchoose; i++) { buf[n] = torque[clist[i]][1]; n += size_one; } } /* ---------------------------------------------------------------------- */ void DumpCustom::pack_tqz(int n) { double **torque = atom->torque; for (int i = 0; i < nchoose; i++) { buf[n] = torque[clist[i]][2]; n += size_one; } } /* ---------------------------------------------------------------------- */ void DumpCustom::pack_spin(int n) { int *spin = atom->spin; for (int i = 0; i < nchoose; i++) { buf[n] = spin[clist[i]]; n += size_one; } } /* ---------------------------------------------------------------------- */ void DumpCustom::pack_eradius(int n) { double *eradius = atom->eradius; for (int i = 0; i < nchoose; i++) { buf[n] = eradius[clist[i]]; n += size_one; } } /* ---------------------------------------------------------------------- */ void DumpCustom::pack_ervel(int n) { double *ervel = atom->ervel; for (int i = 0; i < nchoose; i++) { buf[n] = ervel[clist[i]]; n += size_one; } } /* ---------------------------------------------------------------------- */ void DumpCustom::pack_erforce(int n) { double *erforce = atom->erforce; for (int i = 0; i < nchoose; i++) { buf[n] = erforce[clist[i]]; n += size_one; } } diff --git a/tools/amber2lmp/README b/tools/amber2lmp/README index cf43a171a..0c712f54b 100644 --- a/tools/amber2lmp/README +++ b/tools/amber2lmp/README @@ -1,95 +1,103 @@ These Python scripts were written originally by Keir Novik, but he can no longer support them. See some documentation at the top of the files - they are supposed to be fairly self-explanatory. amber2lammps.py converts AMBER files into LAMMPS input format dump2trj.py converts LAMMPS dump files into AMBER format dump2try99.py same as dump2trj for LAMMPS 99 format ------------------------- +Modifications in file amber2lammps.py, by Vikas Varshney +Dated Nov 4, 2013 +Email address: vv0210@gmail.com + +added support for flags used in current version of AMBER + +------------------------- + Modifications in file amber2lammps.py, by Vikas Varshney Dated July 5, 2005 Email address : vv5@uakron.edu Lines 222-226: Undid the shifting of the atoms in the periodic box. LAMMPS is going to take care of it by image atoms. Make sure that when you dump the coordinates by LAMMPS to view in VMD, print them in the format mentioned in the dump2ptraj.py section later. Lines 378-391: Added an if statement to see whether .crd or .top file is being read. This if statement helps in assigning the title if the title is not present in the files. Line 394: Added an if statement, not to read lines which start with % in the topology file. Lines 430-432: Changed if statement condition to read the current simulation time from .crd file. I put the remainder condition instead of equal to condition. The simulation time adds one value to the length of the Item_list, so remainder condition can be applied easily to see if simulation time data is present in the .crd file or not. In general, the initial .crd files dont have simulation time information while restart files do have them. Some other minor additions: I added few lines to print the names which are being read currently. This helps in seeing current state of the programs which are listed below Lines 382, 389, 420, 428, 436, 490, 498, 550, 555, 560, 565, 570, 575, 580, 595, 600, 610, 615, 620, 631, 636, 648, 657, 666, 677, 688, 701, 720, 725, 730, 735, 740, 745, 750, 755, 767, 769, 771, 778, 785, 806, 821, 897. --------------------------- Modifications in file dump2trj.py, by Vikas Varshney Dated July 5, 2005 Email address: vv5@uakron.edu First, the atoms should be dumped in the following format. dump group-ID custom N tag type xs ys zs ix iy iz Modifications: Lines 117-119: I modified the lines to get the actual co-ordinates instead of box coordinates. If we dont do that and try to see the file in vmd, we observe long bond lengths of the molecules whose one part is on one side of periodic box and the other part is on other side of periodic box. Lines 239 & 244: Changed x to mdcrd. Once you do that. Open the original topology file in VMD (with parm7) and then mdcrd file (crdbox) to see the time evaluation of the problem. ---------------------------- Example input script, by Paul Crozier 1 Sept 2005 Here is an example of a typical LAMMPS input script for use with a data file built by amber2lammps.py: units real neigh_modify delay 5 every 1 atom_style full bond_style harmonic angle_style harmonic dihedral_style harmonic pair_style lj/cut/coul/long 10.0 pair_modify mix arithmetic kspace_style pppm 1e-4 read_data data.yourdata fix 1 all nve special_bonds amber thermo 1 thermo_style multi timestep 0.5 run 2 diff --git a/tools/amber2lmp/amber2lammps.py b/tools/amber2lmp/amber2lammps.py index 08bdf38d9..cc74cf2bb 100644 --- a/tools/amber2lmp/amber2lammps.py +++ b/tools/amber2lmp/amber2lammps.py @@ -1,993 +1,1009 @@ #! /usr/bin/python # # This is amber2lammps, a program written by Keir E. Novik to convert # Amber files to Lammps files. # # Copyright 1999, 2000 Keir E. Novik; all rights reserved. # # Modified by Vikas Varshney, U Akron, 5 July 2005, as described in README # Bug Fixed :Third argument in Dihedral Coeffs section is an integer - Ketan S Khare September 26, 2011 +# Modified by Vikas Varshney, Oct 8, 2013 to include additional flags (Atomic_Number, Coulombic and van der Waals 1-4 factors which are included in newer vesions of .top and .crd files in amber12. #============================================================ def Pop(S, I=-1): 'Pop item I from list' X = S[I] del S[I] return X #============================================================ class Lammps: #-------------------------------------------------------- def Dump(self): 'Write out contents of self (intended for debugging)' Name_list = self.__dict__.keys() Name_list.sort() for Name in Name_list: print Name + ':', self.__dict__[Name] #-------------------------------------------------------- def Write_data(self, Basename, Item_list): 'Write the Lammps data to file (used by Write_Lammps)' import os, sys Filename = 'data.' + Basename Dir_list = os.listdir('.') i = 1 while Filename in Dir_list: Filename = 'data' + `i` + '.' + Basename i = i +1 del i print 'Writing', Filename + '...', sys.stdout.flush() try: F = open(Filename, 'w') except IOError, Detail: print '(error:', Detail[1] + '!)' return try: F.writelines(Item_list) except IOError, Detail: print '(error:', Detail[1] + '!)' F.close() return F.close() print 'done.' #-------------------------------------------------------- def Write_Lammps(self, Basename): 'Write the Lammps data file, ignoring blank sections' import string L = [] L.append('LAMMPS data file for ' + self.name + '\n\n') L.append(`self.atoms` + ' atoms\n') L.append(`self.bonds` + ' bonds\n') L.append(`self.angles` + ' angles\n') L.append(`self.dihedrals` + ' dihedrals\n') L.append(`self.impropers` + ' impropers\n\n') L.append(`self.atom_types` + ' atom types\n') if self.bonds > 0: L.append(`self.bond_types` + ' bond types\n') if self.angles > 0: L.append(`self.angle_types` + ' angle types\n') if self.dihedrals > 0: L.append(`self.dihedral_types` + ' dihedral types\n') L.append('\n') L.append(`self.xlo` + ' ' + `self.xhi` + ' xlo xhi\n') L.append(`self.ylo` + ' ' + `self.yhi` + ' ylo yhi\n') L.append(`self.zlo` + ' ' + `self.zhi` + ' zlo zhi\n\n') if self.atom_types != 0: L.append('Masses\n\n') for i in range(self.atom_types): L.append(`i+1` + ' ' + `self.Masses[i]` + '\n') L.append('\n') L.append('Pair Coeffs\n\n') for i in range(self.atom_types): L.append(`i+1`) for j in range(len(self.Nonbond_Coeffs[0])): L.append(' ' + `self.Nonbond_Coeffs[i][j]`) L.append('\n') L.append('\n') if self.bonds != 0 and self.bond_types != 0: L.append('Bond Coeffs\n\n') for i in range(self.bond_types): L.append(`i+1`) for j in range(len(self.Bond_Coeffs[0])): L.append(' ' + `self.Bond_Coeffs[i][j]`) L.append('\n') L.append('\n') if self.angles != 0 and self.angle_types != 0: L.append('Angle Coeffs\n\n') for i in range(self.angle_types): L.append(`i+1`) for j in range(len(self.Angle_Coeffs[0])): L.append(' ' + `self.Angle_Coeffs[i][j]`) L.append('\n') L.append('\n') if self.dihedrals != 0 and self.dihedral_types != 0: L.append('Dihedral Coeffs\n\n') for i in range(self.dihedral_types): L.append(`i+1`) for j in range(len(self.Dihedral_Coeffs[0])): L.append(' ' + `self.Dihedral_Coeffs[i][j]`) L.append('\n') L.append('\n') if self.atoms != 0: L.append('Atoms\n\n') for i in range(self.atoms): L.append(`i+1`) for j in range(len(self.Atoms[0])): L.append(' ' + `self.Atoms[i][j]`) L.append('\n') L.append('\n') if self.bonds != 0 and self.bond_types != 0: L.append('Bonds\n\n') for i in range(self.bonds): L.append(`i+1`) for j in range(len(self.Bonds[0])): L.append(' ' + `self.Bonds[i][j]`) L.append('\n') L.append('\n') if self.angles != 0 and self.angle_types != 0: L.append('Angles\n\n') for i in range(self.angles): L.append(`i+1`) for j in range(len(self.Angles[0])): L.append(' ' + `self.Angles[i][j]`) L.append('\n') L.append('\n') if self.dihedrals != 0 and self.dihedral_types != 0: L.append('Dihedrals\n\n') for i in range(self.dihedrals): L.append(`i+1`) for j in range(len(self.Dihedrals[0])): L.append(' ' + `self.Dihedrals[i][j]`) L.append('\n') L.append('\n') self.Write_data(Basename, L) #============================================================ class Amber: def __init__(self): 'Initialise the Amber class' self.CRD_is_read = 0 self.TOP_is_read = 0 #-------------------------------------------------------- def Dump(self): 'Write out contents of self (intended for debugging)' Name_list = self.__dict__.keys() Name_list.sort() for Name in Name_list: print Name + ':', self.__dict__[Name] #-------------------------------------------------------- def Coerce_to_Lammps(self): 'Return the Amber data converted to Lammps format' import math if self.CRD_is_read and self.TOP_is_read: l = Lammps() print 'Converting...', l.name = self.ITITL l.atoms = self.NATOM l.bonds = self.NBONH + self.MBONA l.angles = self.NTHETH + self.MTHETA l.dihedrals = self.NPHIH + self.MPHIA l.impropers = 0 l.atom_types = self.NTYPES l.bond_types = self.NUMBND l.angle_types = self.NUMANG l.dihedral_types = self.NPTRA Shift = 0 if self.__dict__.has_key('BOX'): l.xlo = 0.0 l.xhi = self.BOX[0] l.ylo = 0.0 l.yhi = self.BOX[1] l.zlo = 0.0 l.zhi = self.BOX[2] if (l.xlo > min(self.X)) or (l.xhi < max(self.X)) or \ (l.ylo > min(self.Y)) or (l.yhi < max(self.Y)) or \ (l.zlo > min(self.Z)) or (l.zhi < max(self.Z)): # Vikas Modification: Disabling Shifting. This means I am intend to send exact coordinates of each atom and let LAMMPS # take care of imaging into periodic image cells. If one wants to shift all atoms in the periodic box, # please uncomment the below 2 lines. print '(warning: Currently not shifting the atoms to the periodic box)' #Shift = 1 else: print '(warning: Guessing at periodic box!)', l.xlo = min(self.X) l.xhi = max(self.X) l.ylo = min(self.Y) l.yhi = max(self.Y) l.zlo = min(self.Z) l.zhi = max(self.Z) # This doesn't check duplicate values l.Masses = [] for i in range(l.atom_types): l.Masses.append(0) for i in range(self.NATOM): l.Masses[self.IAC[i] - 1] = self.AMASS[i] l.Nonbond_Coeffs = [] for i in range(self.NTYPES): l.Nonbond_Coeffs.append([0,0]) for i in range(self.NTYPES): j = self.ICO[i * (self.NTYPES + 1)] - 1 if self.CN1[j] == 0.0: l.Nonbond_Coeffs[i][0] = 0.0 else: l.Nonbond_Coeffs[i][0] = \ 0.25 * (self.CN2[j])**2 / self.CN1[j] if self.CN2[j] == 0.0: l.Nonbond_Coeffs[i][1] = 0.0 else: l.Nonbond_Coeffs[i][1] = \ (self.CN1[j] / self.CN2[j])**(1.0/6.0) l.Bond_Coeffs = [] for i in range(self.NUMBND): l.Bond_Coeffs.append([0,0]) for i in range(self.NUMBND): l.Bond_Coeffs[i][0] = self.RK[i] l.Bond_Coeffs[i][1] = self.REQ[i] l.Angle_Coeffs = [] for i in range(self.NUMANG): l.Angle_Coeffs.append([0,0]) for i in range(self.NUMANG): l.Angle_Coeffs[i][0] = self.TK[i] l.Angle_Coeffs[i][1] = (180/math.pi) * self.TEQ[i] l.Dihedral_Coeffs = [] for i in range(self.NPTRA): l.Dihedral_Coeffs.append([0,0,0]) for i in range(self.NPTRA): l.Dihedral_Coeffs[i][0] = self.PK[i] if self.PHASE[i] == 0: l.Dihedral_Coeffs[i][1] = 1 else: l.Dihedral_Coeffs[i][1] = -1 l.Dihedral_Coeffs[i][2] = int(self.PN[i]) l.Atoms = [] for i in range(self.NATOM): x = self.X[i] y = self.Y[i] z = self.Z[i] if Shift: while x < l.xlo: x = x + self.BOX[0] while x > l.xhi: x = x - self.BOX[0] while y < l.ylo: y = y + self.BOX[1] while y > l.yhi: y = y - self.BOX[1] while z < l.zlo: z = z + self.BOX[2] while z > l.zhi: z = z - self.BOX[2] l.Atoms.append([0, self.IAC[i], self.CHRG[i]/18.2223, \ x, y, z]) l.Bonds = [] for i in range(l.bonds): l.Bonds.append([0,0,0]) for i in range(self.NBONH): l.Bonds[i][0] = self.ICBH[i] l.Bonds[i][1] = abs(self.IBH[i])/3 + 1 l.Bonds[i][2] = abs(self.JBH[i])/3 + 1 for i in range(self.NBONA): l.Bonds[self.NBONH + i][0] = self.ICB[i] l.Bonds[self.NBONH + i][1] = abs(self.IB[i])/3 + 1 l.Bonds[self.NBONH + i][2] = abs(self.JB[i])/3 + 1 l.Angles = [] for i in range(l.angles): l.Angles.append([0,0,0,0]) for i in range(self.NTHETH): l.Angles[i][0] = self.ICTH[i] l.Angles[i][1] = abs(self.ITH[i])/3 + 1 l.Angles[i][2] = abs(self.JTH[i])/3 + 1 l.Angles[i][3] = abs(self.KTH[i])/3 + 1 for i in range(self.NTHETA): l.Angles[self.NTHETH + i][0] = self.ICT[i] l.Angles[self.NTHETH + i][1] = abs(self.IT[i])/3 + 1 l.Angles[self.NTHETH + i][2] = abs(self.JT[i])/3 + 1 l.Angles[self.NTHETH + i][3] = abs(self.KT[i])/3 + 1 l.Dihedrals = [] for i in range(l.dihedrals): l.Dihedrals.append([0,0,0,0,0]) for i in range(self.NPHIH): l.Dihedrals[i][0] = self.ICPH[i] l.Dihedrals[i][1] = abs(self.IPH[i])/3 + 1 l.Dihedrals[i][2] = abs(self.JPH[i])/3 + 1 l.Dihedrals[i][3] = abs(self.KPH[i])/3 + 1 l.Dihedrals[i][4] = abs(self.LPH[i])/3 + 1 for i in range(self.NPHIA): l.Dihedrals[self.NPHIH + i][0] = self.ICP[i] l.Dihedrals[self.NPHIH + i][1] = abs(self.IP[i])/3 + 1 l.Dihedrals[self.NPHIH + i][2] = abs(self.JP[i])/3 + 1 l.Dihedrals[self.NPHIH + i][3] = abs(self.KP[i])/3 + 1 l.Dihedrals[self.NPHIH + i][4] = abs(self.LP[i])/3 + 1 print 'done.' return l else: print '(Error: Not all the Amber data has been read!)' #-------------------------------------------------------- def Read_data(self, Filename): 'Read the filename, returning a list of strings' import string, sys print 'Reading', Filename + '...', sys.stdout.flush() try: F = open(Filename) except IOError, Detail: print '(error:', Detail[1] + '!)' return try: Lines = F.readlines() except IOError, Detail: print '(error:', Detail[1] + '!)' F.close() return F.close() # If the first line is empty, use the Basename if Filename[-4:] == '.crd': if string.split(Lines[0]) == []: # This line corresponds to TITLE name in CRD file Basename = Filename[:string.find(Filename, '.')] Item_list = [Basename] print 'Warning: Title not present... Assigning Basename as Title' else: Item_list = [] else: if string.split(Lines[3]) == []: # This line corresponds to TITLE name in TOPOLOGY file Basename = Filename[:string.find(Filename, '.')] Item_list = [Basename] print 'Warning: Title not present... Assigning Basename as Title' else: Item_list = [] for Line in Lines: if Line[0]!='%': #Vikas' Modification: This condition ignores all the lines starting with % in the topology file. Item_list.extend(string.split(Line)) return Item_list #-------------------------------------------------------- def Read_CRD(self, Basename): 'Read the Amber coordinate/restart (.crd) file' # The optional velocities and periodic box size are not yet parsed. Item_list = self.Read_data(Basename + '.crd') if Item_list == None: return elif len(Item_list) < 2: print '(error: File too short!)' return # Parse the data if self.__dict__.has_key('ITITL'): if Pop(Item_list,0) != self.ITITL: print '(warning: ITITL differs!)', else: self.ITITL = Pop(Item_list,0) print self.ITITL #Vikas Modification : Priting the Title if self.__dict__.has_key('NATOM'): if eval(Pop(Item_list,0)) != self.NATOM: print '(error: NATOM differs!)' return else: self.NATOM = eval(Pop(Item_list,0)) print self.NATOM # Vikas' Modification: Printing number of atoms just to make sure that the program is reading the correct value. #if len(Item_list) == 1 + 3 * self.NATOM: # Vikas' Modification: I changed the condition. if (len(Item_list)%3) != 0: self.TIME = eval(Pop(Item_list,0)) else: self.TIME = 0 print self.TIME # Vikas' Modification : Printing simulation time, just to make sure that the program is readint the correct value. if len(Item_list) < 3 * self.NATOM: print '(error: File too short!)' return self.X = [] self.Y = [] self.Z = [] for i in range(self.NATOM): self.X.append(eval(Pop(Item_list,0))) self.Y.append(eval(Pop(Item_list,0))) self.Z.append(eval(Pop(Item_list,0))) if (self.NATOM == 1) and len(Item_list): print '(warning: Ambiguity!)', if len(Item_list) >= 3 * self.NATOM: self.VX = [] self.VY = [] self.VZ = [] for i in range(self.NATOM): self.VX.append(eval(Pop(Item_list,0))) self.VY.append(eval(Pop(Item_list,0))) self.VZ.append(eval(Pop(Item_list,0))) if len(Item_list) >= 3: self.BOX = [] for i in range(3): self.BOX.append(eval(Pop(Item_list,0))) if len(Item_list): print '(warning: File too large!)', print 'done.' self.CRD_is_read = 1 #-------------------------------------------------------- def Read_TOP(self, Basename): 'Read the Amber parameter/topology (.top) file' Item_list = self.Read_data(Basename + '.top') if Item_list == None: return elif len(Item_list) < 31: print '(error: File too short!)' return # Parse the data if self.__dict__.has_key('ITITL'): if Pop(Item_list,0) != self.ITITL: print '(warning: ITITL differs!)' else: self.ITITL = Pop(Item_list,0) print self.ITITL # Printing Self Title if self.__dict__.has_key('NATOM'): if eval(Pop(Item_list,0)) != self.NATOM: print '(error: NATOM differs!)' return else: self.NATOM = eval(Pop(Item_list,0)) print self.NATOM # Printing total number of atoms just to make sure that thing are going right self.NTYPES = eval(Pop(Item_list,0)) self.NBONH = eval(Pop(Item_list,0)) self.MBONA = eval(Pop(Item_list,0)) self.NTHETH = eval(Pop(Item_list,0)) self.MTHETA = eval(Pop(Item_list,0)) self.NPHIH = eval(Pop(Item_list,0)) self.MPHIA = eval(Pop(Item_list,0)) self.NHPARM = eval(Pop(Item_list,0)) self.NPARM = eval(Pop(Item_list,0)) self.NEXT = eval(Pop(Item_list,0)) self.NRES = eval(Pop(Item_list,0)) self.NBONA = eval(Pop(Item_list,0)) self.NTHETA = eval(Pop(Item_list,0)) self.NPHIA = eval(Pop(Item_list,0)) self.NUMBND = eval(Pop(Item_list,0)) self.NUMANG = eval(Pop(Item_list,0)) self.NPTRA = eval(Pop(Item_list,0)) self.NATYP = eval(Pop(Item_list,0)) self.NPHB = eval(Pop(Item_list,0)) self.IFPERT = eval(Pop(Item_list,0)) self.NBPER = eval(Pop(Item_list,0)) self.NGPER = eval(Pop(Item_list,0)) self.NDPER = eval(Pop(Item_list,0)) self.MBPER = eval(Pop(Item_list,0)) self.MGPER = eval(Pop(Item_list,0)) self.MDPER = eval(Pop(Item_list,0)) self.IFBOX = eval(Pop(Item_list,0)) self.NMXRS = eval(Pop(Item_list,0)) self.IFCAP = eval(Pop(Item_list,0)) #.................................................... if len(Item_list) < 5 * self.NATOM + self.NTYPES**2 + \ 2*(self.NRES + self.NUMBND + self.NUMANG) + \ 3*self.NPTRA + self.NATYP: print '(error: File too short!)' return -1 self.IGRAPH = [] Pop(Item_list,0) # A little kludge is needed here, since the IGRAPH strings are # not separated by spaces if 4 characters in length. for i in range(self.NATOM): if len(Item_list[0]) > 4: Item_list.insert(1, Item_list[0][4:]) Item_list.insert(1, Item_list[0][0:4]) del Item_list[0] self.IGRAPH.append(Pop(Item_list,0)) # Vikas' Modification : In the following section, I am printing out each quantity which is currently being read from the topology file. print 'Reading Charges...' self.CHRG = [] for i in range(self.NATOM): self.CHRG.append(eval(Pop(Item_list,0))) + print 'Reading Atomic Number...' + self.ANUMBER = [] + for i in range(self.NATOM): + self.ANUMBER.append(eval(Pop(Item_list,0))) + print 'Reading Atomic Masses...' self.AMASS = [] for i in range(self.NATOM): self.AMASS.append(eval(Pop(Item_list,0))) print 'Reading Atom Types...' self.IAC = [] for i in range(self.NATOM): self.IAC.append(eval(Pop(Item_list,0))) print 'Reading Excluded Atoms...' self.NUMEX = [] for i in range(self.NATOM): self.NUMEX.append(eval(Pop(Item_list,0))) print 'Reading Non-bonded Parameter Index...' self.ICO = [] for i in range(self.NTYPES**2): self.ICO.append(eval(Pop(Item_list,0))) print 'Reading Residue Labels...' self.LABRES = [] for i in range(self.NRES): self.LABRES.append(Pop(Item_list,0)) print 'Reading Residues Starting Pointers...' self.IPRES = [] for i in range(self.NRES): self.IPRES.append(eval(Pop(Item_list,0))) print 'Reading Bond Force Constants...' self.RK = [] for i in range(self.NUMBND): self.RK.append(eval(Pop(Item_list,0))) print 'Reading Equilibrium Bond Values...' self.REQ = [] for i in range(self.NUMBND): self.REQ.append(eval(Pop(Item_list,0))) print 'Reading Angle Force Constants...' self.TK = [] for i in range(self.NUMANG): self.TK.append(eval(Pop(Item_list,0))) print 'Reading Equilibrium Angle Values...' self.TEQ = [] for i in range(self.NUMANG): self.TEQ.append(eval(Pop(Item_list,0))) print 'Reading Dihedral Force Constants...' self.PK = [] for i in range(self.NPTRA): self.PK.append(eval(Pop(Item_list,0))) print 'Reading Dihedral Periodicity...' self.PN = [] for i in range(self.NPTRA): self.PN.append(eval(Pop(Item_list,0))) print 'Reading Dihedral Phase...' self.PHASE = [] for i in range(self.NPTRA): self.PHASE.append(eval(Pop(Item_list,0))) + print 'Reading 1-4 Electrostatic Scaling Factor...' + self.SCEEFAC = [] + for i in range(self.NPTRA): + self.SCEEFAC.append(eval(Pop(Item_list,0))) + + print 'Reading 1-4 Van der Waals Scaling Factor...' + self.SCNBFAC = [] + for i in range(self.NPTRA): + self.SCNBFAC.append(eval(Pop(Item_list,0))) + print 'Reading Solty...' #I think this is currently not used in AMBER. Check it out, though self.SOLTY = [] for i in range(self.NATYP): self.SOLTY.append(eval(Pop(Item_list,0))) #.................................................... if len(Item_list) < 2 * self.NTYPES * (self.NTYPES + 1) / 2: print '(error: File too short!)' return -1 print 'Reading LJ A Coefficient...' self.CN1 = [] for i in range(self.NTYPES * (self.NTYPES + 1) / 2): self.CN1.append(eval(Pop(Item_list,0))) print 'Reading LJ B Coefficient...' self.CN2 = [] for i in range(self.NTYPES * (self.NTYPES + 1) / 2): self.CN2.append(eval(Pop(Item_list,0))) #.................................................... if len(Item_list) < 3 * (self.NBONH + self.NBONA) + \ 4 * (self.NTHETH + self.NTHETA) + 5 * (self.NPHIH + self.NPHIA): print '(error: File too short!)' return -1 print 'Reading Bonds which include hydrogen...' self.IBH = [] self.JBH = [] self.ICBH = [] for i in range(self.NBONH): self.IBH.append(eval(Pop(Item_list,0))) self.JBH.append(eval(Pop(Item_list,0))) self.ICBH.append(eval(Pop(Item_list,0))) print 'Reading Bonds which dont include hydrogen...' self.IB = [] self.JB = [] self.ICB = [] for i in range(self.NBONA): self.IB.append(eval(Pop(Item_list,0))) self.JB.append(eval(Pop(Item_list,0))) self.ICB.append(eval(Pop(Item_list,0))) print 'Reading Angles which include hydrogen...' self.ITH = [] self.JTH = [] self.KTH = [] self.ICTH = [] for i in range(self.NTHETH): self.ITH.append(eval(Pop(Item_list,0))) self.JTH.append(eval(Pop(Item_list,0))) self.KTH.append(eval(Pop(Item_list,0))) self.ICTH.append(eval(Pop(Item_list,0))) print 'Reading Angles which dont include hydrogen...' self.IT = [] self.JT = [] self.KT = [] self.ICT = [] for i in range(self.NTHETA): self.IT.append(eval(Pop(Item_list,0))) self.JT.append(eval(Pop(Item_list,0))) self.KT.append(eval(Pop(Item_list,0))) self.ICT.append(eval(Pop(Item_list,0))) print 'Reading Dihedrals which include hydrogen...' self.IPH = [] self.JPH = [] self.KPH = [] self.LPH = [] self.ICPH = [] for i in range(self.NPHIH): self.IPH.append(eval(Pop(Item_list,0))) self.JPH.append(eval(Pop(Item_list,0))) self.KPH.append(eval(Pop(Item_list,0))) self.LPH.append(eval(Pop(Item_list,0))) self.ICPH.append(eval(Pop(Item_list,0))) print 'Reading Dihedrals which dont include hydrogen...' self.IP = [] self.JP = [] self.KP = [] self.LP = [] self.ICP = [] for i in range(self.NPHIA): self.IP.append(eval(Pop(Item_list,0))) self.JP.append(eval(Pop(Item_list,0))) self.KP.append(eval(Pop(Item_list,0))) self.LP.append(eval(Pop(Item_list,0))) self.ICP.append(eval(Pop(Item_list,0))) #.................................................... if len(Item_list) < self.NEXT + 3 * self.NPHB + 4 * self.NATOM: print '(error: File too short!)' return -1 print 'Reading Excluded Atom List...' self.NATEX = [] for i in range(self.NEXT): self.NATEX.append(eval(Pop(Item_list,0))) print 'Reading H-Bond A Coefficient, corresponding to r**12 term for all possible types...' self.ASOL = [] for i in range(self.NPHB): self.ASOL.append(eval(Pop(Item_list,0))) print 'Reading H-Bond B Coefficient, corresponding to r**10 term for all possible types...' self.BSOL = [] for i in range(self.NPHB): self.BSOL.append(eval(Pop(Item_list,0))) print 'Reading H-Bond Cut...' # I think it is not being used nowadays self.HBCUT = [] for i in range(self.NPHB): self.HBCUT.append(eval(Pop(Item_list,0))) print 'Reading Amber Atom Types for each atom...' self.ISYMBL = [] for i in range(self.NATOM): self.ISYMBL.append(Pop(Item_list,0)) print 'Reading Tree Chain Classification...' self.ITREE = [] for i in range(self.NATOM): self.ITREE.append(Pop(Item_list,0)) print 'Reading Join Array: Tree joining information' # Currently unused in Sander, an AMBER module self.JOIN = [] for i in range(self.NATOM): self.JOIN.append(eval(Pop(Item_list,0))) print 'Reading IRotate...' # Currently unused in Sander and Gibbs self.IROTAT = [] for i in range(self.NATOM): self.IROTAT.append(eval(Pop(Item_list,0))) #.................................................... if self.IFBOX > 0: if len(Item_list) < 3: print '(error: File too short!)' return -1 print 'Reading final residue which is part of solute...' self.IPTRES = eval(Pop(Item_list,0)) print 'Reading total number of molecules...' self.NSPM = eval(Pop(Item_list,0)) print 'Reading first solvent moleule index...' self.NSPSOL = eval(Pop(Item_list,0)) if len(Item_list) < self.NSPM + 4: print '(error: File too short!)' return -1 print 'Reading atom per molecule...' self.NSP = [] for i in range(self.NSPM): self.NSP.append(eval(Pop(Item_list,0))) self.BETA = eval(Pop(Item_list,0)) print 'Reading Box Dimensions...' if self.__dict__.has_key('BOX'): BOX = [] for i in range(3): BOX.append(eval(Pop(Item_list,0))) for i in range(3): if BOX[i] != self.BOX[i]: print '(warning: BOX differs!)', break del BOX else: self.BOX = [] for i in range(3): self.BOX.append(eval(Pop(Item_list,0))) #.................................................... if self.IFCAP > 0: if len(Item_list) < 5: print '(error: File too short!)' return -1 print 'Reading ICAP variables::: For details, refer to online AMBER format manual' self.NATCAP = eval(Pop(Item_list,0)) self.CUTCAP = eval(Pop(Item_list,0)) self.XCAP = eval(Pop(Item_list,0)) self.YCAP = eval(Pop(Item_list,0)) self.ZCAP = eval(Pop(Item_list,0)) #.................................................... if self.IFPERT > 0: if len(Item_list) < 4 * self.NBPER + 5 * self.NGPER + \ 6 * self.NDPER + self.NRES + 6 * self.NATOM: print '(error: File too short!)' return -1 print 'Reading perturb variables, 1. Bond, 2. Angles, 3. Dihedrals, etc etc.::: For details, refer to online AMBER format manual' self.IBPER = [] self.JBPER = [] for i in range(self.NBPER): self.IBPER.append(eval(Pop(Item_list,0))) self.JBPER.append(eval(Pop(Item_list,0))) self.ICBPER = [] for i in range(2 * self.NBPER): self.ICBPER.append(eval(Pop(Item_list,0))) self.ITPER = [] self.JTPER = [] self.KTPER = [] for i in range(self.NGPER): self.ITPER.append(eval(Pop(Item_list,0))) self.JTPER.append(eval(Pop(Item_list,0))) self.KTPER.append(eval(Pop(Item_list,0))) self.ICTPER = [] for i in range(2 * self.NGPER): self.ICTPER.append(eval(Pop(Item_list,0))) self.IPPER = [] self.JPPER = [] self.KPPER = [] self.LPPER = [] for i in range(self.NDPER): self.IPPER.append(eval(Pop(Item_list,0))) self.JPPER.append(eval(Pop(Item_list,0))) self.KPPER.append(eval(Pop(Item_list,0))) self.LPPER.append(eval(Pop(Item_list,0))) self.ICPPER = [] for i in range(2 * self.NDPER): self.ICPPER.append(eval(Pop(Item_list,0))) LABRES = [] for i in range(self.NRES): LABRES.append(Pop(Item_list,0)) for i in range(self.NRES): if LABRES[i] != self.LABRES[i]: print '(warning: BOX differs!)', break self.IGRPER = [] for i in range(self.NATOM): self.IGRPER.append(eval(Pop(Item_list,0))) self.ISMPER = [] for i in range(self.NATOM): self.ISMPER.append(eval(Pop(Item_list,0))) self.ALMPER = [] for i in range(self.NATOM): self.ALMPER.append(eval(Pop(Item_list,0))) self.IAPER = [] for i in range(self.NATOM): self.IAPER.append(eval(Pop(Item_list,0))) self.IACPER = [] for i in range(self.NATOM): self.IACPER.append(eval(Pop(Item_list,0))) self.CGPER = [] for i in range(self.NATOM): self.CGPER.append(eval(Pop(Item_list,0))) #.................................................... self.IPOL = 0 if self.IPOL == 1: if len(Item_list) < self.NATOM: print '(error: File too short!)' return -1 print 'Reading Polarizability Data. For details, refer to online AMBER format manual' self.ATPOL = [] for i in range(self.NATOM): self.ATPOL.append(eval(Pop(Item_list,0))) if self.IFPERT == 1: if len(Item_list) < self.NATOM: print '(error: File too short!)' return -1 self.ATPOL1 = [] for i in range(self.NATOM): self.ATPOL1.append(eval(Pop(Item_list,0))) #.................................................... if len(Item_list): print '(warning: File too large!)', print 'done.' self.TOP_is_read = 1 #============================================================ def Find_Amber_files(): 'Look for sets of Amber files to process' '''If not passed anything on the command line, look for pairs of Amber files (.crd and .top) in the current directory. For each set if there is no corresponding Lammps file (data.), or it is older than any of the Amber files, add its basename to a list of strings. This list is returned by the function''' # Date and existence checks not yet implemented import os, sys Basename_list = [] # Extract basenames from command line for Name in sys.argv[1:]: if Name[-4:] == '.crd': Basename_list.append(Name[:-4]) else: if Name[-4:] == '.top': Basename_list.append(Name[:-4]) else: Basename_list.append(Name) # Remove duplicate basenames for Basename in Basename_list[:]: while Basename_list.count(Basename) > 1: Basename_list.remove(Basename) if Basename_list == []: print 'Looking for Amber files...', Dir_list = os.listdir('.') Dir_list.sort() for File in Dir_list: if File[-4:] == '.top': Basename = File[:-4] if (Basename + '.crd') in Dir_list: Basename_list.append(Basename) if Basename_list != []: print 'found', for i in range(len(Basename_list)-1): print Basename_list[i] + ',', print Basename_list[-1] + '\n' if Basename_list == []: print 'none.\n' return Basename_list #============================================================ def Convert_Amber_files(): 'Handle the whole conversion process' print print 'Welcome to amber2lammps, a program to convert Amber files to Lammps format!' print Basename_list = Find_Amber_files() for Basename in Basename_list: a = Amber() a.Read_CRD(Basename) if a.CRD_is_read: a.Read_TOP(Basename) if a.TOP_is_read: l = a.Coerce_to_Lammps() l.Write_Lammps(Basename) del l del a print #============================================================ Convert_Amber_files() diff --git a/tools/msi2lmp/README b/tools/msi2lmp/README index ebb52f6bd..a70fc3471 100644 --- a/tools/msi2lmp/README +++ b/tools/msi2lmp/README @@ -1,173 +1,180 @@ Stephanie Teich-McGoldrick (Sandai) is the current maintainer of the msi2lmp tool. She can be contacted at steichm at sandia.gov +08 Oct 2013 Axel Kohlmeyer + +Fixed a memory access violation with Class 2 force fields. +Free all allocated memory to better detection of memory errors. +Print out version number and data with all print levels > 0. +Added valgrind checks to the regression tests + 02 Aug 2013 Axel Kohlmeyer Added rudimentary support for OPLS-AA based on input provided by jeff greathouse. 18 Jul 2013 Axel Kohlmeyer Added support for writing out image flags Improved accuracy of atom masses Added flag for shifting the entire system Fixed some minor logic bugs and prepared for supporting other force fields and morse style bonds. 12 Jul 2013 Axel Kohlmeyer Fixed the bug that caused improper coefficients to be wrong Cleaned up the handling of box parameters and center the box by default around the system/molecule. Added a flag to make this step optional and center the box around the origin instead. Added a regression test script with examples. 1 Jul 2013 Axel Kohlmeyer Cleanup and improved port to windows. Removed some more static string limits. Added print level 3 for additional output. Make code stop at missing force field parameters and added -i flag to override this. Safer argument checking. Provide short versions for all flags. 23 Sep 2011 added support for triclinic boxes see msi2lmp/TriclinicModification.pdf doc for details ----------------------------- msi2lmp V3.6 4/10/2005 This program uses the .car and .mdf files from MSI/Biosyms's INSIGHT program to produce a LAMMPS data file. 1. Building msi2lmp3 Use the Makefile in the src directory. It is currently set up for gcc. You will have to modify it to use a different compiler. 2. Testing the program There are several pairs of input test files in the format generated by materials studio or compatible programs (one .car and one .mdf file each) in the test directory. There is also a LAMMPS input to run a minimization for each and write out the resulting system as a data file. With the runtests.sh script all of those inputs are converted via msi2lmp, then the minimization with LAMMPS is run and the generated data files are compared with the corresponding files in the reference folder. This script assumes you are on a unix/linux system and that you have compile a serial LAMMPS executable called lmp_serial with make serial. The tests are groups by the force fields they use. 3. To run the program The program is started by supplying information at the command prompt according to the usage described below. USAGE: msi2lmp.exe {-print #} {-class #} {-frc FRC_FILE} {-ignore} {-nocenter} {-shift # # #} -- msi2lmp.exe is the name of the executable -- is the base name of the .car and .mdf files -- -2001 Output lammps files for LAMMPS version 2001 (F90 version) Default is to write output for the C++ version of LAMMPS -- -print (or -p) # is the print level 0 - silent except for error messages 1 - minimal (default) 2 - verbose (usual for developing and checking new data files for consistency) 3 - even more verbose (additional debug info) -- -ignore (or -i) ignore errors about missing force field parameters and treat them as warnings instead. -- -nocenter (or -n) do not recenter the simulation box around the geometrical center of the provided geometry but rather around the origin -- -shift (or -s) translate the entire system (box and coordinates) by a vector (default: 0.0 0.0 0.0) -- -class (or -c) # is the class of forcefield to use (I or 1 = Class I e.g., CVFF) (O or 0 = OPLS-AA) (II or 2 = Class II e.g., CFFx) default is -class I -- -frc (or -f) specifies name of the forcefield file (e.g., cff91) If the file name includes a directory component (or drive letter on Windows), then the name is used as is. Otherwise, the program looks for the forcefield file in $MSI2LMP_LIBRARY (or %MSI2LMP_LIBRARY% on Windows). If $MSI2LMP_LIBRARY is not set, ../frc_files is used (for testing). If the file name does not end in .frc, then .frc is appended to the name. For example, -frc cvff (assumes cvff.frc is in $MSI2LMP_LIBRARY or ../frc_files) -frc cff/cff91 (assumes cff91.frc is in cff) -frc /usr/local/forcefields/cff95 (assumes cff95.frc is in /usr/local/forcefields/) By default, the program uses $MSI2LMP_LIBRARY/cvff.frc or ../frc_files/cvff.frc depending on whether MSI2LMP_LIBRARY is set. -- the LAMMPS data file is written to .data protocol and error information is written to the screen. **************************************************************** * * Msi2lmp3 * * This is the third version of a program that generates a LAMMPS * data file based on the information in MSI .car (atom * coordinates), .mdf (molecular topology) and .frc (forcefield) * files. The .car and .mdf files are specific to a molecular * system while the .frc file is specific to a forcefield version. * The only coherency needed between .frc and .car/.mdf files are * the atom types. * * The first version was written by Steve Lustig at Dupont, but * required using Discover to derive internal coordinates and * forcefield parameters * * The second version was written by Michael Peachey while an * intern in the Cray Chemistry Applications Group managed * by John Carpenter. This version derived internal coordinates * from the mdf file and looked up parameters in the frc file * thus eliminating the need for Discover. * * The third version was written by John Carpenter to optimize * the performance of the program for large molecular systems * (the original code for deriving atom numbers was quadratic in time) * and to make the program fully dynamic. The second version used * fixed dimension arrays for the internal coordinates. * * The current maintainer is only reluctantly doing so because John Mayo no longer * needs this code. * * V3.2 corresponds to adding code to MakeLists.c to gracefully deal with * systems that may only be molecules of 1 to 3 atoms. In V3.1, the values * for number_of_dihedrals, etc. could be unpredictable in these systems. * * V3.3 was generated in response to a strange error reading a MDF file generated by * Accelys' Materials Studio GUI. Simply rewriting the input part of ReadMdfFile.c * seems to have fixed the problem. * * V3.4 and V3.5 are minor upgrades to fix bugs associated mostly with .car and .mdf files * written by Accelys' Materials Studio GUI. * * V3.6 outputs to LAMMPS 2005 (C++ version). * * Contact: Kelly L. Anderson, kelly.anderson@cantab.net * * April 2005 diff --git a/tools/msi2lmp/TriclinicModification.pdf b/tools/msi2lmp/TriclinicModification.pdf deleted file mode 100644 index a88bb902f..000000000 Binary files a/tools/msi2lmp/TriclinicModification.pdf and /dev/null differ