\(\renewcommand{\AA}{\text{Å}}\)

# 1.3.1. The :f:mod:`LIBLAMMPS` Fortran Module

The :f:mod:`LIBLAMMPS` module provides an interface to call LAMMPS from Fortran. It is based on the LAMMPS C library interface and requires a fully Fortran 2003-compatible compiler to be compiled. It is designed to be self-contained and not require any support functions written in C, C++, or Fortran other than those in the C library interface and the LAMMPS Fortran module itself.

While C libraries have a defined binary interface (ABI) and can thus be used from multiple compiler versions from different vendors as long as they are compatible with the hosting operating system, the same is not true for Fortran programs. Thus, the LAMMPS Fortran module needs to be compiled alongside the code using it from the source code in `fortran/lammps.f90` and with the same compiler used to build the rest of the Fortran code that interfaces to LAMMPS. When linking, you also need to link to the LAMMPS library. A typical command for a simple program using the Fortran interface would be:

    mpifort -o testlib.x lammps.f90 testlib.f90 -L. -llammps

Please note that the MPI compiler wrapper is only required when the calling the library from an MPI-parallelized program. Otherwise, using the plain Fortran compiler (gfortran, ifort, flang, etc.) will suffice, since there are no direct references to MPI library features, definitions and subroutine calls; MPI communicators are referred to by their integer index representation as required by the Fortran MPI interface. It may be necessary to link to additional libraries, depending on how LAMMPS was configured and whether the LAMMPS library was compiled as a static or dynamic library.

If the LAMMPS library itself has been compiled with MPI support, the resulting executable will be able to run LAMMPS in parallel with `mpirun`, `mpiexec`, or equivalent. This may be either on the “world” communicator or a sub-communicator created by the calling Fortran code. If, on the other hand, the LAMMPS library has been compiled without MPI support, each LAMMPS instance will run independently using just one processor.

Please also note that the order of the source files matters: the `lammps.f90` file needs to be compiled first, since it provides the :f:mod:`LIBLAMMPS` module that would need to be imported by the calling Fortran code in order to uses the Fortran interface. A working example can be found together with equivalent examples in C and C++ in the `examples/COUPLE/simple` folder of the LAMMPS distribution.

Fortran compiler compatibility

A fully Fortran 2003 compatible Fortran compiler is required. This means that currently only GNU Fortran 9 and later are compatible and thus the default compilers of Red Hat or CentOS 7 and Ubuntu 18.04 LTS and not compatible. Either newer compilers need to be installed or the Linux updated.

# 1.3.2. Creating or deleting a LAMMPS object

With the Fortran interface, the creation of a `LAMMPS` instance is included in the constructor for creating the :f:func:`lammps` derived type. To import the definition of that type and its type-bound procedures, you need to add a `USE LIBLAMMPS` statement. Internally, it will call either `lammps_open_fortran()` or `lammps_open_no_mpi()` from the C library API to create the class instance. All arguments are optional and `lammps_mpi_init()` will be called automatically if it is needed. Similarly, optional calls to `lammps_mpi_finalize()`, `lammps_kokkos_finalize()`, `lammps_python_finalize()`, and `lammps_plugin_finalize()` are integrated into the :f:func:`close` function and triggered with the optional logical argument set to `.TRUE.`. Here is a simple example:

    PROGRAM testlib
      USE LIBLAMMPS                 ! include the LAMMPS library interface
      IMPLICIT NONE
      TYPE(lammps) :: lmp           ! derived type to hold LAMMPS instance
      CHARACTER(LEN=12), PARAMETER :: args(3) = &
          [ CHARACTER(LEN=12) :: 'liblammps', '-log', 'none' ]

      ! create a LAMMPS instance (and initialize MPI)
      lmp = lammps(args)
      ! get and print numerical version code
      PRINT*, 'LAMMPS Version: ', lmp%version()
      ! delete LAMMPS instance (and shutdown MPI)
      CALL lmp%close(.TRUE.)
    END PROGRAM testlib

It is also possible to pass command-line flags from Fortran to C/C++ and thus make the resulting executable behave similarly to the standalone executable (it will ignore the -in/-i flag, though). This allows using the command-line to configure accelerator and suffix settings, configure screen and logfile output, or to set index style variables from the command-line and more. Here is a correspondingly adapted version of the previous example:

    PROGRAM testlib2
      USE LIBLAMMPS                 ! include the LAMMPS library interface
      IMPLICIT NONE
      TYPE(lammps) :: lmp           ! derived type to hold LAMMPS instance
      CHARACTER(LEN=128), ALLOCATABLE :: command_args(:)
      INTEGER :: i, argc

      ! copy command-line flags to `command_args()`
      argc = COMMAND_ARGUMENT_COUNT()
      ALLOCATE(command_args(0:argc))
      DO i=0, argc
        CALL GET_COMMAND_ARGUMENT(i, command_args(i))
      END DO

      ! create a LAMMPS instance (and initialize MPI)
      lmp = lammps(command_args)
      ! get and print numerical version code
      PRINT*, 'Program name:   ', command_args(0)
      PRINT*, 'LAMMPS Version: ', lmp%version()
      ! delete LAMMPS instance (and shuts down MPI)
      CALL lmp%close(.TRUE.)
      DEALLOCATE(command_args)
    END PROGRAM testlib2

# 1.3.3. Executing LAMMPS commands

Once a LAMMPS instance is created, it is possible to “drive” the LAMMPS simulation by telling LAMMPS to read commands from a file or to pass individual or multiple commands from strings or lists of strings. This is done similarly to how it is implemented in the C library interface. Before handing off the calls to the C library interface, the corresponding Fortran versions of the calls (:f:func:`file`, :f:func:`command`, :f:func:`commands_list`, and :f:func:`commands_string`) have to make copies of the strings passed as arguments so that they can be modified to be compatible with the requirements of strings in C without affecting the original strings. Those copies are automatically deleted after the functions return. Below is a small demonstration of the uses of the different functions.

    PROGRAM testcmd
      USE LIBLAMMPS
      TYPE(lammps) :: lmp
      CHARACTER(LEN=512) :: cmds
      CHARACTER(LEN=40), ALLOCATABLE :: cmdlist(:)
      CHARACTER(LEN=10) :: trimmed
      INTEGER :: i

      lmp = lammps()
      CALL lmp%file('in.melt')
      CALL lmp%command('variable zpos index 1.0')
      ! define 10 groups of 10 atoms each
      ALLOCATE(cmdlist(10))
      DO i=1, 10
        WRITE(trimmed,'(I10)') 10*i
        WRITE(cmdlist(i),'(A,I1,A,I10,A,A)')       &
            'group g', i-1, ' id ', 10*(i-1)+1, ':', ADJUSTL(trimmed)
      END DO
      CALL lmp%commands_list(cmdlist)
      ! run multiple commands from multi-line string
      cmds = 'clear' // NEW_LINE('A') //                       &
          'region  box block 0 2 0 2 0 2' // NEW_LINE('A') //  &
          'create_box 1 box' // NEW_LINE('A') //               &
          'create_atoms 1 single 1.0 1.0 ${zpos}'
      CALL lmp%commands_string(cmds)
      CALL lmp%close(.TRUE.)
    END PROGRAM testcmd

# 1.3.4. Accessing system properties

The C library interface allows the extraction of different kinds of information about the active simulation instance and also—in some cases—to apply modifications to it, and the Fortran interface provides access to the same data using Fortran-style, C-interoperable data types. In some cases, the Fortran library interface makes pointers to internal LAMMPS data structures accessible; when accessing them through the library interfaces, special care is needed to avoid data corruption and crashes. Please see the documentation of the individual type-bound procedures for details.

Below is an example demonstrating some of the possible uses.

    PROGRAM testprop
      USE LIBLAMMPS
      USE, INTRINSIC :: ISO_C_BINDING, ONLY : c_double, c_int64_t, c_int
      USE, INTRINSIC :: ISO_FORTRAN_ENV, ONLY : OUTPUT_UNIT
      TYPE(lammps) :: lmp
      INTEGER(KIND=c_int64_t), POINTER :: natoms, ntimestep, bval
      REAL(KIND=c_double), POINTER :: dt, dval
      INTEGER(KIND=c_int), POINTER :: nfield, typ, ival
      INTEGER(KIND=c_int) :: i
      CHARACTER(LEN=11) :: key
      REAL(KIND=c_double) :: pe, ke

      lmp = lammps()
      CALL lmp%file('in.sysinit')
      natoms = lmp%extract_global('natoms')
      WRITE(OUTPUT_UNIT,'(A,I0,A)') 'Running a simulation with ', natoms, ' atoms'
      WRITE(OUTPUT_UNIT,'(I0,A,I0,A,I0,A)') lmp%extract_setting('nlocal'), &
          ' local and ', lmp%extract_setting('nghost'), ' ghost atoms. ', &
          lmp%extract_setting('ntypes'), ' atom types'

      CALL lmp%command('run 2 post no')

      ntimestep = lmp%last_thermo('step', 0)
      nfield = lmp%last_thermo('num', 0)
      WRITE(OUTPUT_UNIT,'(A,I0,A,I0)') 'Last thermo output on step: ', ntimestep, &
          ',  number of fields: ', nfield
      DO i=1, nfield
          key = lmp%last_thermo('keyword',i)
          typ = lmp%last_thermo('type',i)
          IF (typ == lmp%dtype%i32) THEN
              ival = lmp%last_thermo('data',i)
              WRITE(OUTPUT_UNIT,*) key, ':', ival
          ELSE IF (typ == lmp%dtype%i64) THEN
              bval = lmp%last_thermo('data',i)
              WRITE(OUTPUT_UNIT,*) key, ':', bval
          ELSE IF (typ == lmp%dtype%r64) THEN
              dval = lmp%last_thermo('data',i)
              WRITE(OUTPUT_UNIT,*) key, ':', dval
          END IF
      END DO

      dt = lmp%extract_global('dt')
      ntimestep = lmp%extract_global('ntimestep')
      WRITE(OUTPUT_UNIT,'(A,I0,A,F4.1,A)') 'At step: ', ntimestep, &
          '  Changing timestep from', dt, ' to 0.5'
      dt = 0.5_c_double
      CALL lmp%command('run 2 post no')

      WRITE(OUTPUT_UNIT,'(A,I0)') 'At step: ', ntimestep
      pe = lmp%get_thermo('pe')
      ke = lmp%get_thermo('ke')
      WRITE(OUTPUT_UNIT,*) 'PE = ', pe
      WRITE(OUTPUT_UNIT,*) 'KE = ', ke

      CALL lmp%close(.TRUE.)
    END PROGRAM testprop

# 1.3.5. The :f:mod:`LIBLAMMPS` module API

Below are the detailed descriptions of definitions and interfaces of the contents of the :f:mod:`LIBLAMMPS` Fortran interface to LAMMPS.

## Procedures Bound to the :f:type:`lammps` Derived Type

Note

Note that a frequent use case of this function is to extract only one or more of the options rather than all seven. For example, assuming “lmp” represents a properly-initialized LAMMPS instance, the following code will extract the periodic box settings into the variable “periodic”:

    ! code to start up
    LOGICAL :: periodic(3)
    ! code to initialize LAMMPS / run things / etc.
    CALL lmp%extract_box(pflags = periodic)

Note

LAMMPS cannot easily check if it is valid to access the data referenced by the variables (e.g., computes, fixes, or thermodynamic info), so it may fail with an error. The caller has to make certain that the data are extracted only when it is safe to evaluate the variable and thus an error and crash are avoided.