Merge pull request #3396 from hammondkd/fortran-tinkering

Expanding the Fortran interface
This commit is contained in:
Axel Kohlmeyer 2022-09-26 13:02:30 -04:00 committed by GitHub
commit a4796dd872
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 2459 additions and 171 deletions

View File

@ -3,7 +3,9 @@ The ``LIBLAMMPS`` Fortran Module
The ``LIBLAMMPS`` module provides an interface to call LAMMPS from a
Fortran code. It is based on the LAMMPS C-library interface and
requires a Fortran 2003 compatible compiler to be compiled.
requires a 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.
While C libraries have a defined binary interface (ABI) and can thus be
used from multiple compiler versions from different vendors for as long
@ -19,12 +21,20 @@ 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 parallel code. Please also note the
order of the source files: the ``lammps.f90`` file needs to be compiled
first, since it provides the ``LIBLAMMPS`` module that is imported by
the Fortran code using the interface. A working example code can be
found together with equivalent examples in C and C++ in the
``examples/COUPLE/simple`` folder of the LAMMPS distribution.
calling the library from an MPI parallel code. Otherwise, using the
fortran compiler (gfortran, ifort, flang, etc.) will suffice. It may be
necessary to link to additional libraries depending on how LAMMPS was
configured and whether the LAMMPS library :doc:`was compiled as a static
or shared library <Build_link>`.
If the LAMMPS library itself has been compiled with MPI support, the
resulting executable will still be able to run LAMMPS in parallel with
``mpirun`` or equivalent. Please also note that the order of the source
files matters: the ``lammps.f90`` file needs to be compiled first, since
it provides the ``LIBLAMMPS`` module that is imported by the Fortran
code using the interface. A working example code can be found together
with equivalent examples in C and C++ in the ``examples/COUPLE/simple``
folder of the LAMMPS distribution.
.. versionadded:: 9Oct2020
@ -49,17 +59,18 @@ found together with equivalent examples in C and C++ in the
Creating or deleting a LAMMPS object
************************************
With the Fortran interface the creation of a :cpp:class:`LAMMPS
With the Fortran interface, the creation of a :cpp:class:`LAMMPS
<LAMMPS_NS::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
that type and its type bound procedures, you need to add a ``USE
LIBLAMMPS`` statement. Internally it will call either
:cpp:func:`lammps_open_fortran` or :cpp:func:`lammps_open_no_mpi` from
the C library API to create the class instance. All arguments are
optional and :cpp:func:`lammps_mpi_init` will be called automatically,
if it is needed. Similarly, a possible call to :cpp:func:`lammps_finalize`
is integrated into the :f:func:`close` function and triggered with
the optional logical argument set to ``.true.``. Here is a simple example:
if it is needed. Similarly, a possible call to
:cpp:func:`lammps_mpi_finalize` is integrated into the :f:func:`close`
function and triggered with the optional logical argument set to
``.true.``. Here is a simple example:
.. code-block:: fortran
@ -80,11 +91,11 @@ the optional logical argument set to ``.true.``. Here is a simple example:
END PROGRAM testlib
It is also possible to pass command line flags from Fortran to C/C++ and
thus make the resulting executable behave similar to the standalone
executable (it will ignore the `-in/-i` flag, though). This allows to
use the command line to configure accelerator and suffix settings,
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
from the command line and more. Here is a correspondingly adapted
version of the previous example:
.. code-block:: fortran
@ -117,13 +128,13 @@ version of the previous example:
--------------------
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 pass
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 similar to how it is implemented in the `C-library
<pg_lib_execute>` interface. Before handing off the calls to the
is done similarly to how it is implemented in the :doc:`C-library
interface <Library_execute>`. 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 a copy of the strings passed as
@ -165,6 +176,57 @@ Below is a small demonstration of the uses of the different functions:
---------------
Accessing system properties
***************************
The C-library interface allows the :doc:`extraction of different kinds
of information <Library_properties>` about the active simulation
instance and also - in some cases - to apply modifications to it. In
some cases, the C-library interface makes pointers to internal data
structures accessible, thus when accessing them from Fortran, special
care is needed to avoid data corruption and crashes. Thus please see
the documentation of the individual type bound procedures for details.
Below is an example demonstrating some of the possible uses.
.. code-block:: fortran
PROGRAM testprop
USE LIBLAMMPS
USE, INTRINSIC :: ISO_C_BINDING, ONLY : c_double, c_int64_t
TYPE(lammps) :: lmp
INTEGER(kind=8) :: natoms
REAL(c_double), POINTER :: dt
INTEGER(c_int64_t), POINTER :: ntimestep
REAL(kind=8) :: pe, ke
lmp = lammps()
CALL lmp%file('in.sysinit')
natoms = INT(lmp%get_natoms(),8)
WRITE(6,'(A,I8,A)') 'Running a simulation with', natoms, ' atoms'
WRITE(6,'(I8,A,I8,A,I3,A)') lmp%extract_setting('nlocal'), ' local and', &
lmp%extract_setting('nghost'), ' ghost atom. ', &
lmp%extract_setting('ntypes'), ' atom types'
CALL lmp%command('run 2 post no')
dt = lmp%extract_global('dt')
ntimestep = lmp%extract_global('ntimestep')
WRITE(6,'(A,I4,A,F4.1,A)') 'At step:', ntimestep, ' Changing timestep from', dt, ' to 0.5'
dt = 0.5
CALL lmp%command('run 2 post no')
WRITE(6,'(A,I4)') 'At step:', ntimestep
pe = lmp%get_thermo('pe')
ke = lmp%get_thermo('ke')
PRINT*, 'PE = ', pe
PRINT*, 'KE = ', ke
CALL lmp%close(.TRUE.)
END PROGRAM testprop
---------------
The ``LIBLAMMPS`` module API
****************************
@ -178,14 +240,24 @@ of the contents of the ``LIBLAMMPS`` Fortran interface to LAMMPS.
class instance that any of the included calls are forwarded to.
:f c_ptr handle: reference to the LAMMPS class
:f close: :f:func:`close`
:f version: :f:func:`version`
:f file: :f:func:`file`
:f command: :f:func:`command`
:f commands_list: :f:func:`commands_list`
:f commands_string: :f:func:`commands_string`
:f subroutine close: :f:func:`close`
:f subroutine error: :f:func:`error`
:f function version: :f:func:`version`
:f subroutine file: :f:func:`file`
:f subroutine command: :f:func:`command`
:f subroutine commands_list: :f:func:`commands_list`
:f subroutine commands_string: :f:func:`commands_string`
:f function get_natoms: :f:func:`get_natoms`
:f function get_thermo: :f:func:`get_thermo`
:f subroutine extract_box: :f:func:`extract_box`
:f subroutine reset_box: :f:func:`reset_box`
:f subroutine memory_usage: :f:func:`memory_usage`
:f function extract_setting: :f:func:`extract_setting`
:f function extract_global: :f:func:`extract_global`
.. f:function:: lammps(args[,comm])
--------
.. f:function:: lammps([args][,comm])
This is the constructor for the Fortran class and will forward
the arguments to a call to either :cpp:func:`lammps_open_fortran`
@ -198,10 +270,31 @@ of the contents of the ``LIBLAMMPS`` Fortran interface to LAMMPS.
If *comm* is not provided, ``MPI_COMM_WORLD`` is assumed. For
more details please see the documentation of :cpp:func:`lammps_open`.
:p character(len=*) args(*) [optional]: arguments as list of strings
:o character(len=\*) args(\*) [optional]: arguments as list of strings
:o integer comm [optional]: MPI communicator
:r lammps: an instance of the :f:type:`lammps` derived type
.. note::
The ``MPI_F08`` module, which defines Fortran 2008 bindings for MPI,
is not directly supported by this interface due to the complexities of
supporting both the ``MPI_F08`` and ``MPI`` modules at the same time.
However, you should be able to use the ``MPI_VAL`` member of the
``MPI_comm`` derived type to access the integer value of the
communicator, such as in
.. code-block:: Fortran
PROGRAM testmpi
USE LIBLAMMPS
USE MPI_F08
TYPE(lammps) :: lmp
lmp = lammps(MPI_COMM_SELF%MPI_VAL)
END PROGRAM testmpi
Procedures Bound to the lammps Derived Type
===========================================
.. f:subroutine:: close([finalize])
This method will close down the LAMMPS instance through calling
@ -211,6 +304,20 @@ of the contents of the ``LIBLAMMPS`` Fortran interface to LAMMPS.
:o logical finalize [optional]: shut down the MPI environment of the LAMMPS library if true.
--------
.. f:subroutine:: error(error_type, error_text)
This method is a wrapper around the :cpp:func:`lammps_error` function and will dispatch
an error through the LAMMPS Error class.
.. versionadded:: TBD
:p integer error_type: constant to select which Error class function to call
:p character(len=\*) error_text: error message
--------
.. f:function:: version()
This method returns the numeric LAMMPS version like :cpp:func:`lammps_version`
@ -224,25 +331,243 @@ of the contents of the ``LIBLAMMPS`` Fortran interface to LAMMPS.
This method will call :cpp:func:`lammps_file` to have LAMMPS read
and process commands from a file.
:p character(len=*) filename: name of file with LAMMPS commands
:p character(len=\*) filename: name of file with LAMMPS commands
--------
.. f:subroutine:: command(cmd)
This method will call :cpp:func:`lammps_command` to have LAMMPS
execute a single command.
:p character(len=*) cmd: single LAMMPS command
:p character(len=\*) cmd: single LAMMPS command
--------
.. f:subroutine:: commands_list(cmds)
This method will call :cpp:func:`lammps_commands_list` to have LAMMPS
execute a list of input lines.
:p character(len=*) cmd(:): list of LAMMPS input lines
:p character(len=\*) cmd(:): list of LAMMPS input lines
--------
.. f:subroutine:: commands_string(str)
This method will call :cpp:func:`lammps_commands_string` to have LAMMPS
execute a block of commands from a string.
:p character(len=*) str: LAMMPS input in string
:p character(len=\*) str: LAMMPS input in string
--------
.. f:function:: get_natoms()
This function will call :cpp:func:`lammps_get_natoms` and return the number
of atoms in the system.
:r real(c_double): number of atoms
--------
.. f:function:: get_thermo(name)
This function will call :cpp:func:`lammps_get_thermo` and return the value
of the corresponding thermodynamic keyword.
.. versionadded:: TBD
:p character(len=\*) name: string with the name of the thermo keyword
:r real(c_double): value of the requested thermo property or `0.0_c_double`
--------
.. f:subroutine:: extract_box([boxlo][, boxhi][, xy][, yz][, xz][, pflags][, boxflag])
This subroutine will call :cpp:func:`lammps_extract_box`. All
parameters are optional, though obviously at least one should be
present. The parameters *pflags* and *boxflag* are stored in LAMMPS
as integers, but should be declared as ``LOGICAL`` variables when
calling from Fortran.
.. versionadded:: TBD
:o real(c_double) boxlo [dimension(3),optional]: vector in which to store
lower-bounds of simulation box
:o real(c_double) boxhi [dimension(3),optional]: vector in which to store
upper-bounds of simulation box
:o real(c_double) xy [optional]: variable in which to store *xy* tilt factor
:o real(c_double) yz [optional]: variable in which to store *yz* tilt factor
:o real(c_double) xz [optional]: variable in which to store *xz* tilt factor
:o logical pflags [dimension(3),optional]: vector in which to store
periodicity flags (``.TRUE.`` means periodic in that dimension)
:o logical boxflag [optional]: variable in which to store boolean denoting
whether the box will change during a simulation
(``.TRUE.`` means box will change)
.. 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-block:: Fortran
! code to start up
logical :: periodic(3)
! code to initialize LAMMPS / run things / etc.
call lmp%extract_box(pflags = periodic)
--------
.. f:subroutine:: reset_box(boxlo, boxhi, xy, yz, xz)
This subroutine will call :cpp:func:`lammps_reset_box`. All parameters
are required.
.. versionadded:: TBD
:p real(c_double) boxlo [dimension(3)]: vector of three doubles containing
the lower box boundary
:p real(c_double) boxhi [dimension(3)]: vector of three doubles containing
the upper box boundary
:p real(c_double) xy: *x--y* tilt factor
:p real(c_double) yz: *y--z* tilt factor
:p real(c_double) xz: *x--z* tilt factor
--------
.. f:subroutine:: memory_usage(meminfo)
This subroutine will call :cpp:func:`lammps_memory_usage` and store the
result in the three-element array *meminfo*.
.. versionadded:: TBD
:p real(c_double) meminfo [dimension(3)]: vector of three doubles in which
to store memory usage data
--------
.. f:function:: get_mpi_comm()
This function returns a Fortran representation of the LAMMPS "world"
communicator.
.. versionadded:: TBD
:r integer: Fortran integer equivalent to the MPI communicator LAMMPS is
using
.. note::
The C library interface currently returns type ``int`` instead of
type ``MPI_Fint``, which is the C type corresponding to Fortran
``INTEGER`` types of the default kind. On most compilers, these
are the same anyway, but this interface exchanges values this way
to avoid warning messages.
.. note::
The `MPI_F08` module, which defines Fortran 2008 bindings for MPI,
is not directly supported by this function. However, you should be
able to convert between the two using the `MPI_VAL` member of the
communicator. For example,
.. code-block:: fortran
USE MPI_F08
USE LIBLAMMPS
TYPE (LAMMPS) :: lmp
TYPE (MPI_Comm) :: comm
! ... [commands to set up LAMMPS/etc.]
comm%MPI_VAL = lmp%get_mpi_comm()
should assign an `MPI_F08` communicator properly.
--------
.. f:function:: extract_setting(keyword)
Query LAMMPS about global settings. See the documentation for the
:cpp:func:`lammps_extract_setting` function from the C library.
.. versionadded:: TBD
:p character(len=\*) keyword: string containing the name of the thermo keyword
:r integer(c_int): value of the queried setting or :math:`-1` if unknown
--------
.. f:function:: extract_global(name)
This function calls :cpp:func:`lammps_extract_global` and returns
either a string or a pointer to internal global LAMMPS data,
depending on the data requested through *name*.
.. versionadded:: TBD
Note that this function actually does not return a value, but rather
associates the pointer on the left side of the assignment to point to
internal LAMMPS data (with the exception of string data, which are
copied and returned as ordinary Fortran strings). Pointers must be of
the correct data type to point to said data (typically
``INTEGER(c_int)``, ``INTEGER(c_int64_t)``, or ``REAL(c_double)``)
and have compatible kind and rank. The pointer being associated with
LAMMPS data is type-, kind-, and rank-checked at run-time via an
overloaded assignment operator. The pointers returned by this
function are generally persistent; therefore it is not necessary to
call the function again, unless a :doc:`clear` command has been
issued, which wipes out and recreates the contents of the
:cpp:class:`LAMMPS <LAMMPS_NS::LAMMPS>` class.
For example,
.. code-block:: fortran
PROGRAM demo
USE, INTRINSIC :: ISO_C_BINDING, ONLY : c_int64_t
USE LIBLAMMPS
TYPE(lammps) :: lmp
INTEGER(c_int), POINTER :: nlocal
INTEGER(c_int64_t), POINTER :: ntimestep
CHARACTER(LEN=10) :: units
REAL(c_double), POINTER :: dt
lmp = lammps()
! other commands
nlocal = lmp%extract_global('nlocal')
ntimestep = lmp%extract_global('ntimestep')
dt = lmp%extract_global('dt')
units = lmp%extract_global('units')
! more commands
lmp.close(.TRUE.)
END PROGRAM demo
would extract the number of atoms on this processor, the current time step,
the size of the current time step, and the units being used into the
variables *nlocal*, *ntimestep*, *dt*, and *units*, respectively.
.. note::
if this function returns a string, the string must have
length greater than or equal to the length of the string (not including the
terminal NULL character) that LAMMPS returns. If the variable's length is
too short, the string will be truncated. As usual in Fortran, strings
are padded with spaces at the end.
:p character(len=\*) name: string with the name of the extracted property
:r polymorphic: pointer to LAMMPS data. The left-hand side of the assignment
should be either a string (if expecting string data) or a C-compatible
pointer (e.g., ``INTEGER (c_int), POINTER :: nlocal``) to the extracted
property. If expecting vector data, the pointer should have dimension ":".
.. warning::
Modifying the data in the location pointed to by the returned pointer
may lead to inconsistent internal data and thus may cause failures or
crashes or bogus simulations. In general it is thus usually better
to use a LAMMPS input command that sets or changes these parameters.
Those will take care of all side effects and necessary updates of
settings derived from such settings.

View File

@ -11,6 +11,7 @@ This section documents the following functions:
- :cpp:func:`lammps_mpi_finalize`
- :cpp:func:`lammps_kokkos_finalize`
- :cpp:func:`lammps_python_finalize`
- :cpp:func:`lammps_error`
--------------------
@ -115,3 +116,8 @@ calling program.
.. doxygenfunction:: lammps_python_finalize
:project: progguide
-----------------------
.. doxygenfunction:: lammps_error
:project: progguide

View File

@ -15,21 +15,21 @@ This section documents the following functions:
--------------------
The library interface allows extraction of different kinds of
information about the active simulation instance and also
modifications to it. This enables combining of a LAMMPS simulation
with other processing and simulation methods computed by the calling
code, or by another code that is coupled to LAMMPS via the library
interface. In some cases the data returned is direct reference to the
original data inside LAMMPS, cast to a void pointer. In that case the
data needs to be cast to a suitable pointer for the calling program to
access it, and you may need to know the correct dimensions and
lengths. This also means you can directly change those value(s) from
the calling program, e.g. to modify atom positions. Of course, this
should be done with care. When accessing per-atom data, please note
that this data is the per-processor **local** data and is indexed
accordingly. Per-atom data can change sizes and ordering at every
neighbor list rebuild or atom sort event as atoms migrate between
The 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. This enables combining of a
LAMMPS simulation with other processing and simulation methods computed
by the calling code, or by another code that is coupled to LAMMPS via
the library interface. In some cases the data returned is direct
reference to the original data inside LAMMPS, cast to a void pointer.
In that case the data needs to be cast to a suitable pointer for the
calling program to access it, and you may need to know the correct
dimensions and lengths. This also means you can directly change those
value(s) from the calling program, e.g. to modify atom positions. Of
course, this should be done with care. When accessing per-atom data,
please note that this data is the per-processor **local** data and is
indexed accordingly. Per-atom data can change sizes and ordering at
every neighbor list rebuild or atom sort event as atoms migrate between
sub-domains and processors.
.. code-block:: C

View File

@ -1081,6 +1081,7 @@ filesystems
Fily
Fincham
Finchham
Fint
fingerprintconstants
fingerprintsperelement
Finnis
@ -1093,6 +1094,7 @@ flagHI
flaglog
flagN
flagVF
flang
fld
floralwhite
Florez

View File

@ -3,9 +3,9 @@ and allows the LAMMPS library interface to be invoked from Fortran codes.
It requires a Fortran compiler that supports the Fortran 2003 standard.
This interface is based on and supersedes the previous Fortran interfaces
in the examples/COUPLE/fortran* folders. But is fully supported by the
in the examples/COUPLE/fortran* folders, but is fully supported by the
LAMMPS developers and included in the documentation and unit testing.
Details on this Fortran interface and how to build programs using it
are in the manual in the doc/html/pg_fortran.html file.
are in the manual in the doc/html/Fortran.html file.

View File

@ -19,117 +19,358 @@
! Karl D. Hammond <hammondkd@missouri.edu>
! University of Missouri, 2012-2020
!
! The Fortran module tries to follow the API of the C-library interface
! closely, but like the Python wrapper it employs an object oriented
! approach. To accommodate the object oriented approach, all exported
! subroutine and functions have to be implemented in Fortran to then
! call the interfaced C style functions with adapted calling conventions
! as needed. The C-library interfaced functions retain their names
! starting with "lammps_" while the Fortran versions start with "lmp_".
! The Fortran module tries to follow the API of the C library interface
! closely, but like the Python wrapper it employs an object-oriented
! approach. To accommodate the object-oriented approach, all exported
! subroutines and functions have to be implemented in Fortran and
! call the interfaced C-style functions with adapted calling conventions
! as needed. The C library interface functions retain their names
! starting with "lammps_", while the Fortran versions start with "lmp_".
!
MODULE LIBLAMMPS
USE, INTRINSIC :: ISO_C_BINDING, ONLY: c_ptr, c_null_ptr, c_loc, &
c_int, c_char, c_null_char, c_double, c_size_t, c_f_pointer
c_int, c_int64_t, c_char, c_null_char, c_double, c_size_t, c_f_pointer
USE, INTRINSIC :: ISO_FORTRAN_ENV, ONLY : ERROR_UNIT
IMPLICIT NONE
PRIVATE
PUBLIC :: lammps
PUBLIC :: lammps, ASSIGNMENT(=)
! Data type constants for extracting data from global, atom, compute, and fix
!
! Must be kept in sync with the equivalent declarations in
! src/library.h and python/lammps/constants.py
!
! NOT part of the API (the part the user sees)
INTEGER (c_int), PARAMETER :: &
LAMMPS_INT = 0, & ! 32-bit integer (array)
LAMMPS_INT_2D = 1, & ! two-dimensional 32-bit integer array
LAMMPS_DOUBLE = 2, & ! 64-bit double (array)
LAMMPS_DOUBLE_2D = 3, & ! two-dimensional 64-bit double array
LAMMPS_INT64 = 4, & ! 64-bit integer (array)
LAMMPS_INT64_2D = 5, & ! two-dimensional 64-bit integer array
LAMMPS_STRING = 6 ! C-String
TYPE lammps
TYPE(c_ptr) :: handle
CONTAINS
PROCEDURE :: close => lmp_close
PROCEDURE :: error => lmp_error
PROCEDURE :: file => lmp_file
PROCEDURE :: command => lmp_command
PROCEDURE :: commands_list => lmp_commands_list
PROCEDURE :: commands_string => lmp_commands_string
PROCEDURE :: version => lmp_version
PROCEDURE :: get_natoms => lmp_get_natoms
PROCEDURE :: get_thermo => lmp_get_thermo
PROCEDURE :: extract_box => lmp_extract_box
PROCEDURE :: reset_box => lmp_reset_box
PROCEDURE :: memory_usage => lmp_memory_usage
PROCEDURE :: get_mpi_comm => lmp_get_mpi_comm
PROCEDURE :: extract_setting => lmp_extract_setting
PROCEDURE :: extract_global => lmp_extract_global
PROCEDURE :: version => lmp_version
PROCEDURE :: is_running => lmp_is_running
END TYPE lammps
INTERFACE lammps
MODULE PROCEDURE lmp_open
MODULE PROCEDURE lmp_open
END INTERFACE lammps
! Constants to use in working with lammps_data
ENUM, BIND(C)
ENUMERATOR :: DATA_INT, DATA_INT_1D, DATA_INT_2D
ENUMERATOR :: DATA_INT64, DATA_INT64_1D, DATA_INT64_2D
ENUMERATOR :: DATA_DOUBLE, DATA_DOUBLE_1D, DATA_DOUBLE_2D
ENUMERATOR :: DATA_STRING
END ENUM
! Derived type for receiving LAMMPS data (in lieu of the ability to type cast
! pointers)
TYPE lammps_data
INTEGER(c_int) :: datatype
INTEGER(c_int), POINTER :: i32
INTEGER(c_int), DIMENSION(:), POINTER :: i32_vec
INTEGER(c_int64_t), POINTER :: i64
INTEGER(c_int64_t), DIMENSION(:), POINTER :: i64_vec
REAL(c_double), POINTER :: r64
REAL(c_double), DIMENSION(:), POINTER :: r64_vec
CHARACTER(LEN=:), ALLOCATABLE :: str
END TYPE lammps_data
! This overloads the assignment operator (=) so that assignments of the
! form
! nlocal = extract_global('nlocal')
! which are of the form "pointer to double = type(lammps_data)" result in
! re-associating the pointer on the left with the appropriate piece of
! LAMMPS data (after checking type-compatibility)
INTERFACE ASSIGNMENT(=)
MODULE PROCEDURE assign_int_to_lammps_data, assign_int64_to_lammps_data, &
assign_intvec_to_lammps_data, &
assign_double_to_lammps_data, assign_doublevec_to_lammps_data, &
assign_string_to_lammps_data
END INTERFACE
! interface definitions for calling functions in library.cpp
INTERFACE
FUNCTION lammps_open(argc, argv, comm) BIND(C, name='lammps_open_fortran')
IMPORT :: c_ptr, c_int
INTEGER(c_int), VALUE, INTENT(in) :: argc, comm
TYPE(c_ptr), DIMENSION(*), INTENT(in) :: argv
TYPE(c_ptr) :: lammps_open
END FUNCTION lammps_open
FUNCTION lammps_open(argc, argv, comm) BIND(C,name='lammps_open_fortran')
IMPORT :: c_ptr, c_int
IMPLICIT NONE
INTEGER(c_int), VALUE, INTENT(IN) :: argc, comm
TYPE(c_ptr), DIMENSION(*), INTENT(IN) :: argv
TYPE(c_ptr) :: lammps_open
END FUNCTION lammps_open
FUNCTION lammps_open_no_mpi(argc, argv, handle) BIND(C, name='lammps_open_no_mpi')
IMPORT :: c_ptr, c_int
INTEGER(c_int), VALUE, INTENT(in) :: argc
TYPE(c_ptr), DIMENSION(*), INTENT(in) :: argv
TYPE(c_ptr), VALUE, INTENT(in) :: handle
TYPE(c_ptr) :: lammps_open_no_mpi
END FUNCTION lammps_open_no_mpi
FUNCTION lammps_open_no_mpi(argc, argv, handle) BIND(C)
IMPORT :: c_ptr, c_int
IMPLICIT NONE
INTEGER(c_int), VALUE, INTENT(IN) :: argc
TYPE(c_ptr), DIMENSION(*), INTENT(IN) :: argv
TYPE(c_ptr), VALUE, INTENT(IN) :: handle
TYPE(c_ptr) :: lammps_open_no_mpi
END FUNCTION lammps_open_no_mpi
SUBROUTINE lammps_close(handle) BIND(C, name='lammps_close')
IMPORT :: c_ptr
TYPE(c_ptr), VALUE :: handle
END SUBROUTINE lammps_close
SUBROUTINE lammps_close(handle) BIND(C)
IMPORT :: c_ptr
IMPLICIT NONE
TYPE(c_ptr), VALUE :: handle
END SUBROUTINE lammps_close
SUBROUTINE lammps_mpi_init() BIND(C, name='lammps_mpi_init')
END SUBROUTINE lammps_mpi_init
SUBROUTINE lammps_mpi_init() BIND(C)
END SUBROUTINE lammps_mpi_init
SUBROUTINE lammps_mpi_finalize() BIND(C, name='lammps_mpi_finalize')
END SUBROUTINE lammps_mpi_finalize
SUBROUTINE lammps_mpi_finalize() BIND(C)
END SUBROUTINE lammps_mpi_finalize
SUBROUTINE lammps_kokkos_finalize() BIND(C, name='lammps_kokkos_finalize')
END SUBROUTINE lammps_kokkos_finalize
SUBROUTINE lammps_kokkos_finalize() BIND(C)
END SUBROUTINE lammps_kokkos_finalize
SUBROUTINE lammps_file(handle, filename) BIND(C, name='lammps_file')
IMPORT :: c_ptr
TYPE(c_ptr), VALUE :: handle
TYPE(c_ptr), VALUE :: filename
END SUBROUTINE lammps_file
SUBROUTINE lammps_error(handle, error_type, error_text) BIND(C)
IMPORT :: c_ptr, c_int
IMPLICIT NONE
TYPE(c_ptr), VALUE :: handle
INTEGER(c_int), VALUE :: error_type
TYPE(c_ptr), VALUE :: error_text
END SUBROUTINE lammps_error
SUBROUTINE lammps_command(handle, cmd) BIND(C, name='lammps_command')
IMPORT :: c_ptr
TYPE(c_ptr), VALUE :: handle
TYPE(c_ptr), VALUE :: cmd
END SUBROUTINE lammps_command
SUBROUTINE lammps_file(handle, filename) BIND(C)
IMPORT :: c_ptr
IMPLICIT NONE
TYPE(c_ptr), VALUE :: handle
TYPE(c_ptr), VALUE :: filename
END SUBROUTINE lammps_file
SUBROUTINE lammps_commands_list(handle, ncmd, cmds) BIND(C, name='lammps_commands_list')
IMPORT :: c_ptr, c_int
TYPE(c_ptr), VALUE :: handle
INTEGER(c_int), VALUE, INTENT(in) :: ncmd
TYPE(c_ptr), DIMENSION(*), INTENT(in) :: cmds
END SUBROUTINE lammps_commands_list
SUBROUTINE lammps_command(handle, cmd) BIND(C)
IMPORT :: c_ptr
IMPLICIT NONE
TYPE(c_ptr), VALUE :: handle
TYPE(c_ptr), VALUE :: cmd
END SUBROUTINE lammps_command
SUBROUTINE lammps_commands_string(handle, str) BIND(C, name='lammps_commands_string')
IMPORT :: c_ptr
TYPE(c_ptr), VALUE :: handle
TYPE(c_ptr), VALUE :: str
END SUBROUTINE lammps_commands_string
SUBROUTINE lammps_commands_list(handle, ncmd, cmds) BIND(C)
IMPORT :: c_ptr, c_int
IMPLICIT NONE
TYPE(c_ptr), VALUE :: handle
INTEGER(c_int), VALUE, INTENT(IN) :: ncmd
TYPE(c_ptr), DIMENSION(*), INTENT(IN) :: cmds
END SUBROUTINE lammps_commands_list
FUNCTION lammps_malloc(size) BIND(C, name='malloc')
IMPORT :: c_ptr, c_size_t
INTEGER(c_size_t), value :: size
TYPE(c_ptr) :: lammps_malloc
END FUNCTION lammps_malloc
SUBROUTINE lammps_commands_string(handle, str) BIND(C)
IMPORT :: c_ptr
IMPLICIT NONE
TYPE(c_ptr), VALUE :: handle
TYPE(c_ptr), VALUE :: str
END SUBROUTINE lammps_commands_string
SUBROUTINE lammps_free(ptr) BIND(C, name='lammps_free')
IMPORT :: c_ptr
TYPE(c_ptr), VALUE :: ptr
END SUBROUTINE lammps_free
FUNCTION lammps_get_natoms(handle) BIND(C)
IMPORT :: c_ptr, c_double
IMPLICIT NONE
TYPE(c_ptr), VALUE :: handle
REAL(c_double) :: lammps_get_natoms
END FUNCTION lammps_get_natoms
FUNCTION lammps_version(handle) BIND(C, name='lammps_version')
IMPORT :: c_ptr, c_int
TYPE(c_ptr), VALUE :: handle
INTEGER(c_int) :: lammps_version
END FUNCTION lammps_version
FUNCTION lammps_get_thermo(handle,name) BIND(C)
IMPORT :: c_ptr, c_double
IMPLICIT NONE
REAL(c_double) :: lammps_get_thermo
TYPE(c_ptr), VALUE :: handle
TYPE(c_ptr), VALUE :: name
END FUNCTION lammps_get_thermo
SUBROUTINE lammps_extract_box(handle,boxlo,boxhi,xy,yz,xz,pflags, &
boxflag) BIND(C)
IMPORT :: c_ptr, c_double, c_int
IMPLICIT NONE
TYPE(c_ptr), VALUE :: handle, boxlo, boxhi, xy, yz, xz, pflags, &
boxflag
END SUBROUTINE lammps_extract_box
SUBROUTINE lammps_reset_box(handle,boxlo,boxhi,xy,yz,xz) BIND(C)
IMPORT :: c_ptr, c_double
IMPLICIT NONE
TYPE(c_ptr), VALUE :: handle
REAL(c_double), DIMENSION(3) :: boxlo, boxhi
REAL(c_double), VALUE :: xy, yz, xz
END SUBROUTINE lammps_reset_box
SUBROUTINE lammps_memory_usage(handle,meminfo) BIND(C)
IMPORT :: c_ptr, c_double
IMPLICIT NONE
TYPE(c_ptr), VALUE :: handle
REAL(c_double), DIMENSION(*) :: meminfo
END SUBROUTINE lammps_memory_usage
FUNCTION lammps_get_mpi_comm(handle) BIND(C)
IMPORT :: c_ptr, c_int
IMPLICIT NONE
TYPE(c_ptr), VALUE :: handle
INTEGER(c_int) :: lammps_get_mpi_comm
END FUNCTION lammps_get_mpi_comm
FUNCTION lammps_extract_setting(handle,keyword) BIND(C)
IMPORT :: c_ptr, c_int
IMPLICIT NONE
TYPE(c_ptr), VALUE :: handle, keyword
INTEGER(c_int) :: lammps_extract_setting
END FUNCTION lammps_extract_setting
FUNCTION lammps_extract_global_datatype(handle,name) BIND(C)
IMPORT :: c_ptr, c_int
IMPLICIT NONE
TYPE(c_ptr), VALUE :: handle, name
INTEGER(c_int) :: lammps_extract_global_datatype
END FUNCTION lammps_extract_global_datatype
FUNCTION c_strlen (str) BIND(C,name='strlen')
IMPORT :: c_ptr, c_size_t
IMPLICIT NONE
TYPE(c_ptr), VALUE :: str
INTEGER(c_size_t) :: c_strlen
END FUNCTION c_strlen
FUNCTION lammps_extract_global(handle, name) BIND(C)
IMPORT :: c_ptr
IMPLICIT NONE
TYPE(c_ptr), VALUE :: handle, name
TYPE(c_ptr) :: lammps_extract_global
END FUNCTION lammps_extract_global
!INTEGER (c_int) FUNCTION lammps_extract_atom_datatype
!(generic) lammps_extract_atom
!(generic) lammps_extract_compute
!(generic) lammps_extract_fix
!(generic) lammps_extract_variable
!INTEGER (c_int) lammps_set_variable
!SUBROUTINE lammps_gather_atoms
!SUBROUTINE lammps_gather_atoms_concat
!SUBROUTINE lammps_gather_atoms_subset
!SUBROUTINE lammps_scatter_atoms
!SUBROUTINE lammps_scatter_atoms_subset
!SUBROUTINE lammps_gather_bonds
!SUBROUTINE lammps_gather
!SUBROUTINE lammps_gather_concat
!SUBROUTINE lammps_gather_subset
!SUBROUTINE lammps_scatter_subset
!(generic / id, type, and image are special) / requires LAMMPS_BIGBIG
!INTEGER (C_int) FUNCTION lammps_create_atoms
!INTEGER (C_int) FUNCTION lammps_find_pair_neighlist
!INTEGER (C_int) FUNCTION lammps_find_fix_neighlist
!INTEGER (C_int) FUNCTION lammps_find_compute_neighlist
!INTEGER (C_int) FUNCTION lammps_neighlist_num_elements
!SUBROUTINE lammps_neighlist_element_neighbors
FUNCTION lammps_version(handle) BIND(C)
IMPORT :: c_ptr, c_int
IMPLICIT NONE
TYPE(c_ptr), VALUE :: handle
INTEGER(c_int) :: lammps_version
END FUNCTION lammps_version
!SUBROUTINE lammps_get_os_info
!LOGICAL FUNCTION lammps_config_has_mpi_support
!LOGICAL FUNCTION lammps_config_has_gzip_support
!LOGICAL FUNCTION lammps_config_has_png_support
!LOGICAL FUNCTION lammps_config_has_jpeg_support
!LOGICAL FUNCTION lammps_config_has_ffmpeg_support
!LOGICAL FUNCTION lammps_config_has_exceptions
!LOGICAL FUNCTION lammps_config_has_package
!INTEGER (C_int) FUNCTION lammps_config_package_count
!SUBROUTINE lammps_config_package_name
!LOGICAL FUNCTION lammps_config_accelerator
!LOGICAL FUNCTION lammps_has_gpu_device
!SUBROUTINE lammps_get_gpu_device
!LOGICAL FUNCTION lammps_has_id
!INTEGER (C_int) FUNCTION lammps_id_count
!SUBROUTINE lammps_id_name
!INTEGER (C_int) FUNCTION lammps_plugin_count
!SUBROUTINE lammps_plugin_name
!Both of these use LAMMPS_BIGBIG
!INTEGER (LAMMPS_imageint) FUNCTION lammps_encode_image_flags
!SUBROUTINE lammps_decode_image_flags
!SUBROUTINE lammps_set_fix_external_callback ! may have trouble....
!FUNCTION lammps_fix_external_get_force() ! returns real(c_double) (:)
!SUBROUTINE lammps_fix_external_set_energy_global
!SUBROUTINE lammps_fix_external_set_energy_peratom
!SUBROUTINE lammps_fix_external_set_virial_global
!SUBROUTINE lammps_fix_external_set_virial_peratom
!SUBROUTINE lammps_fix_external_set_vector_length
!SUBROUTINE lammps_fix_external_set_vector
!SUBROUTINE lammps_flush_buffers
FUNCTION lammps_malloc(size) BIND(C, name='malloc')
IMPORT :: c_ptr, c_size_t
IMPLICIT NONE
INTEGER(c_size_t), VALUE :: size
TYPE(c_ptr) :: lammps_malloc
END FUNCTION lammps_malloc
SUBROUTINE lammps_free(ptr) BIND(C)
IMPORT :: c_ptr
IMPLICIT NONE
TYPE(c_ptr), VALUE :: ptr
END SUBROUTINE lammps_free
INTEGER(c_int) FUNCTION lammps_is_running(handle) BIND(C)
IMPORT :: c_ptr, c_int
IMPLICIT NONE
TYPE(c_ptr), VALUE :: handle
END FUNCTION lammps_is_running
!SUBROUTINE lammps_force_timeout
!LOGICAL FUNCTION lammps_has_error
!INTEGER (c_int) FUNCTION lammps_get_last_error_message
FUNCTION lammps_get_natoms(handle) BIND(C, name='lammps_get_natoms')
IMPORT :: c_ptr, c_double
TYPE(c_ptr), VALUE :: handle
REAL(c_double) :: lammps_get_natoms
END FUNCTION lammps_get_natoms
END INTERFACE
CONTAINS
@ -138,9 +379,8 @@ CONTAINS
! Constructor for the LAMMPS class.
! Combined wrapper around lammps_open_fortran() and lammps_open_no_mpi()
TYPE(lammps) FUNCTION lmp_open(args, comm)
IMPLICIT NONE
INTEGER, INTENT(in), OPTIONAL :: comm
CHARACTER(len=*), INTENT(in), OPTIONAL :: args(:)
INTEGER, INTENT(IN), OPTIONAL :: comm
CHARACTER(LEN=*), INTENT(IN), OPTIONAL :: args(:)
TYPE(c_ptr), ALLOCATABLE :: argv(:)
INTEGER(c_int) :: i, c_comm, argc
@ -173,9 +413,8 @@ CONTAINS
! Combined Fortran wrapper around lammps_close() and lammps_mpi_finalize()
SUBROUTINE lmp_close(self, finalize)
IMPLICIT NONE
CLASS(lammps) :: self
LOGICAL, INTENT(in), OPTIONAL :: finalize
LOGICAL, INTENT(IN), OPTIONAL :: finalize
CALL lammps_close(self%handle)
@ -187,22 +426,20 @@ CONTAINS
END IF
END SUBROUTINE lmp_close
INTEGER FUNCTION lmp_version(self)
IMPLICIT NONE
! equivalent function to lammps_error()
SUBROUTINE lmp_error(self, error_type, error_text)
CLASS(lammps) :: self
INTEGER :: error_type
CHARACTER(len=*) :: error_text
TYPE(c_ptr) :: str
lmp_version = lammps_version(self%handle)
END FUNCTION lmp_version
DOUBLE PRECISION FUNCTION lmp_get_natoms(self)
IMPLICIT NONE
CLASS(lammps) :: self
lmp_get_natoms = lammps_get_natoms(self%handle)
END FUNCTION lmp_get_natoms
str = f2c_string(error_text)
CALL lammps_error(self%handle, error_type, str)
CALL lammps_free(str)
END SUBROUTINE lmp_error
! equivalent function to lammps_file()
SUBROUTINE lmp_file(self, filename)
IMPLICIT NONE
CLASS(lammps) :: self
CHARACTER(len=*) :: filename
TYPE(c_ptr) :: str
@ -214,7 +451,6 @@ CONTAINS
! equivalent function to lammps_command()
SUBROUTINE lmp_command(self, cmd)
IMPLICIT NONE
CLASS(lammps) :: self
CHARACTER(len=*) :: cmd
TYPE(c_ptr) :: str
@ -226,9 +462,8 @@ CONTAINS
! equivalent function to lammps_commands_list()
SUBROUTINE lmp_commands_list(self, cmds)
IMPLICIT NONE
CLASS(lammps) :: self
CHARACTER(len=*), INTENT(in), OPTIONAL :: cmds(:)
CHARACTER(LEN=*), INTENT(IN), OPTIONAL :: cmds(:)
TYPE(c_ptr), ALLOCATABLE :: cmdv(:)
INTEGER :: i, ncmd
@ -250,7 +485,6 @@ CONTAINS
! equivalent function to lammps_commands_string()
SUBROUTINE lmp_commands_string(self, str)
IMPLICIT NONE
CLASS(lammps) :: self
CHARACTER(len=*) :: str
TYPE(c_ptr) :: tmp
@ -260,13 +494,274 @@ CONTAINS
CALL lammps_free(tmp)
END SUBROUTINE lmp_commands_string
! equivalent function to lammps_get_natoms
DOUBLE PRECISION FUNCTION lmp_get_natoms(self)
CLASS(lammps) :: self
lmp_get_natoms = lammps_get_natoms(self%handle)
END FUNCTION lmp_get_natoms
! equivalent function to lammps_get_thermo
REAL (C_double) FUNCTION lmp_get_thermo(self,name)
CLASS(lammps), INTENT(IN) :: self
CHARACTER(LEN=*) :: name
TYPE(C_ptr) :: Cname
Cname = f2c_string(name)
lmp_get_thermo = lammps_get_thermo(self%handle, Cname)
CALL lammps_free(Cname)
END FUNCTION lmp_get_thermo
! equivalent subroutine to lammps_extract_box
SUBROUTINE lmp_extract_box(self, boxlo, boxhi, xy, yz, xz, pflags, boxflag)
CLASS(lammps), INTENT(IN) :: self
REAL(c_double), INTENT(OUT), TARGET, OPTIONAL :: boxlo(3), boxhi(3)
REAL(c_double), INTENT(OUT), TARGET, OPTIONAL :: xy, yz, xz
LOGICAL, INTENT(OUT), OPTIONAL :: pflags(3), boxflag
INTEGER(c_int), TARGET :: C_pflags(3), C_boxflag
TYPE (c_ptr) :: ptr(7)
ptr = c_null_ptr
IF ( PRESENT(boxlo) ) ptr(1) = C_LOC(boxlo(1))
IF ( PRESENT(boxhi) ) ptr(2) = C_LOC(boxhi(1))
IF ( PRESENT(xy) ) ptr(3) = C_LOC(xy)
IF ( PRESENT(yz) ) ptr(4) = C_LOC(yz)
IF ( PRESENT(xz) ) ptr(5) = C_LOC(xz)
IF ( PRESENT(pflags) ) ptr(6) = C_LOC(C_pflags(1))
IF ( PRESENT(boxflag) ) ptr(7) = C_LOC(C_boxflag)
CALL lammps_extract_box(self%handle, ptr(1), ptr(2), ptr(3), ptr(4), &
ptr(5), ptr(6), ptr(7))
IF ( PRESENT(pflags) ) pflags = ( C_pflags /= 0_C_int )
IF ( PRESENT(boxflag) ) boxflag = ( C_boxflag /= 0_C_int )
END SUBROUTINE lmp_extract_box
! equivalent function to lammps_reset_box
SUBROUTINE lmp_reset_box(self, boxlo, boxhi, xy, yz, xz)
CLASS(lammps), INTENT(IN) :: self
REAL(C_double), INTENT(IN) :: boxlo(3), boxhi(3), xy, yz, xz
CALL lammps_reset_box(self%handle, boxlo, boxhi, xy, yz, xz)
END SUBROUTINE lmp_reset_box
! equivalent function to lammps_memory_usage
SUBROUTINE lmp_memory_usage(self,meminfo)
CLASS(lammps), INTENT(IN) :: self
INTEGER, PARAMETER :: MEMINFO_ELEM = 3
REAL (c_double), DIMENSION(MEMINFO_ELEM), INTENT(OUT) :: meminfo
CALL lammps_memory_usage(self%handle,meminfo)
END SUBROUTINE lmp_memory_usage
! equivalent function to lammps_get_mpi_comm
INTEGER FUNCTION lmp_get_mpi_comm(self)
CLASS(lammps), INTENT(IN) :: self
lmp_get_mpi_comm = lammps_get_mpi_comm(self%handle)
END FUNCTION lmp_get_mpi_comm
! equivalent function to lammps_extract_setting
INTEGER (c_int) FUNCTION lmp_extract_setting(self, keyword)
CLASS(lammps), INTENT(IN) :: self
CHARACTER(LEN=*), INTENT(IN) :: keyword
TYPE(c_ptr) :: Ckeyword
Ckeyword = f2c_string(keyword)
lmp_extract_setting = lammps_extract_setting(self%handle, Ckeyword)
CALL lammps_free(Ckeyword)
END FUNCTION lmp_extract_setting
! equivalent function to lammps_extract_global
! the assignment is actually overloaded so as to bind the pointers to
! lammps data based on the information available from LAMMPS
FUNCTION lmp_extract_global(self, name) RESULT (global_data)
CLASS(lammps), INTENT(IN) :: self
CHARACTER(LEN=*), INTENT(IN) :: name
TYPE(lammps_data) :: global_data
INTEGER(c_int) :: datatype
TYPE(c_ptr) :: Cname, Cptr
INTEGER(c_size_t) :: length, i
CHARACTER(KIND=c_char, LEN=1), DIMENSION(:), POINTER :: Fptr
! Determine vector length
! FIXME Is there a way to get the length of the vector from C rather
! than defining it here AND in the Python API?
SELECT CASE (name)
CASE ('boxlo','boxhi','sublo','subhi','sublo_lambda','subhi_lambda', &
'periodicity')
length = 3
CASE DEFAULT
length = 1
! string cases are overridden later
END SELECT
Cname = f2c_string(name)
datatype = lammps_extract_global_datatype(self%handle, Cname)
! above could be c_null_ptr in place of self%handle...doesn't matter
Cptr = lammps_extract_global(self%handle, Cname)
CALL lammps_free(Cname)
SELECT CASE (datatype)
CASE (LAMMPS_INT)
IF ( length == 1 ) THEN
global_data%datatype = DATA_INT
CALL C_F_POINTER(Cptr, global_data%i32)
ELSE
global_data%datatype = DATA_INT_1D
CALL C_F_POINTER(Cptr, global_data%i32_vec, [length])
END IF
CASE (LAMMPS_INT64)
IF ( length == 1 ) THEN
global_data%datatype = DATA_INT64
CALL C_F_POINTER(Cptr, global_data%i64)
ELSE
global_data%datatype = DATA_INT64_1D
CALL C_F_POINTER(Cptr, global_data%i64_vec, [length])
END IF
CASE (LAMMPS_DOUBLE)
IF ( length == 1 ) THEN
global_data%datatype = DATA_DOUBLE
CALL C_F_POINTER(Cptr, global_data%r64)
ELSE
global_data%datatype = DATA_DOUBLE_1D
CALL C_F_POINTER(Cptr, global_data%r64_vec, [length])
END IF
CASE (LAMMPS_STRING)
global_data%datatype = DATA_STRING
length = c_strlen(Cptr)
CALL C_F_POINTER(Cptr, Fptr, [length])
ALLOCATE ( CHARACTER(LEN=length) :: global_data%str )
FORALL ( I=1:length )
global_data%str(i:i) = Fptr(i)
END FORALL
CASE DEFAULT
! FIXME convert to use symbolic constants later
CALL lmp_error(self, 6, 'Unknown pointer type in extract_global')
END SELECT
END FUNCTION
! equivalent function to lammps_version()
INTEGER FUNCTION lmp_version(self)
CLASS(lammps) :: self
lmp_version = lammps_version(self%handle)
END FUNCTION lmp_version
! equivalent function to lammps_is_running
LOGICAL FUNCTION lmp_is_running(self)
CLASS(lammps) :: self
lmp_is_running = ( lammps_is_running(self%handle) /= 0_C_int )
END FUNCTION lmp_is_running
! ----------------------------------------------------------------------
! functions to assign user-space pointers to LAMMPS data
! ----------------------------------------------------------------------
SUBROUTINE assign_int_to_lammps_data (lhs, rhs)
INTEGER(c_int), INTENT(OUT), POINTER :: lhs
CLASS(lammps_data), INTENT(IN) :: rhs
IF ( rhs%datatype == DATA_INT ) THEN
lhs => rhs%i32
ELSE
CALL assignment_error(rhs%datatype, 'scalar int')
END IF
END SUBROUTINE assign_int_to_lammps_data
SUBROUTINE assign_int64_to_lammps_data (lhs, rhs)
INTEGER(c_int64_t), INTENT(OUT), POINTER :: lhs
CLASS(lammps_data), INTENT(IN) :: rhs
IF ( rhs%datatype == DATA_INT64 ) THEN
lhs => rhs%i64
ELSE
CALL assignment_error(rhs%datatype, 'scalar long int')
END IF
END SUBROUTINE assign_int64_to_lammps_data
SUBROUTINE assign_intvec_to_lammps_data (lhs, rhs)
INTEGER(c_int), DIMENSION(:), INTENT(OUT), POINTER :: lhs
CLASS(lammps_data), INTENT(IN) :: rhs
IF ( rhs%datatype == DATA_INT_1D ) THEN
lhs => rhs%i32_vec
ELSE
CALL assignment_error(rhs%datatype, 'vector of ints')
END IF
END SUBROUTINE assign_intvec_to_lammps_data
SUBROUTINE assign_double_to_lammps_data (lhs, rhs)
REAL(c_double), INTENT(OUT), POINTER :: lhs
CLASS(lammps_data), INTENT(IN) :: rhs
IF ( rhs%datatype == DATA_DOUBLE ) THEN
lhs => rhs%r64
ELSE
CALL assignment_error(rhs%datatype, 'scalar double')
END IF
END SUBROUTINE assign_double_to_lammps_data
SUBROUTINE assign_doublevec_to_lammps_data (lhs, rhs)
REAL(c_double), DIMENSION(:), INTENT(OUT), POINTER :: lhs
CLASS(lammps_data), INTENT(IN) :: rhs
IF ( rhs%datatype == DATA_DOUBLE_1D ) THEN
lhs => rhs%r64_vec
ELSE
CALL assignment_error(rhs%datatype, 'vector of doubles')
END IF
END SUBROUTINE assign_doublevec_to_lammps_data
SUBROUTINE assign_string_to_lammps_data (lhs, rhs)
CHARACTER(LEN=*), INTENT(OUT) :: lhs
CLASS(lammps_data), INTENT(IN) :: rhs
IF ( rhs%datatype == DATA_STRING ) THEN
lhs = rhs%str
ELSE
CALL assignment_error(rhs%datatype, 'string')
END IF
END SUBROUTINE assign_string_to_lammps_data
SUBROUTINE assignment_error (type1, type2)
INTEGER (c_int) :: type1
CHARACTER (LEN=*) :: type2
INTEGER, PARAMETER :: ERROR_CODE = 1
CHARACTER (LEN=:), ALLOCATABLE :: str1
SELECT CASE (type1)
CASE (DATA_INT)
str1 = 'scalar int'
CASE (DATA_INT_1D)
str1 = 'vector of ints'
CASE (DATA_INT_2D)
str1 = 'matrix of ints'
CASE (DATA_INT64)
str1 = 'scalar long int'
CASE (DATA_INT64_1D)
str1 = 'vector of long ints'
CASE (DATA_INT64_2D)
str1 = 'matrix of long ints'
CASE (DATA_DOUBLE)
str1 = 'scalar double'
CASE (DATA_DOUBLE_1D)
str1 = 'vector of doubles'
CASE (DATA_DOUBLE_2D)
str1 = 'matrix of doubles'
CASE DEFAULT
str1 = 'that type'
END SELECT
WRITE (ERROR_UNIT,'(A)') 'Cannot associate ' // str1 // ' with ' // type2
STOP ERROR_CODE
END SUBROUTINE assignment_error
! ----------------------------------------------------------------------
! local helper functions
! copy fortran string to zero terminated c string
! ----------------------------------------------------------------------
FUNCTION f2c_string(f_string) RESULT(ptr)
CHARACTER (len=*), INTENT(in) :: f_string
CHARACTER (len=1, kind=c_char), POINTER :: c_string(:)
CHARACTER(LEN=*), INTENT(IN) :: f_string
CHARACTER(LEN=1, KIND=c_char), POINTER :: c_string(:)
TYPE(c_ptr) :: ptr
INTEGER(c_size_t) :: i, n
@ -279,3 +774,5 @@ CONTAINS
c_string(n+1) = c_null_char
END FUNCTION f2c_string
END MODULE LIBLAMMPS
! vim: ts=2 sts=2 sw=2 et

View File

@ -13,29 +13,35 @@
# various symbolic constants to be used
# in certain calls to select data formats
LAMMPS_AUTODETECT = None
LAMMPS_INT = 0
LAMMPS_INT_2D = 1
LAMMPS_DOUBLE = 2
LAMMPS_DOUBLE_2D = 3
LAMMPS_INT64 = 4
LAMMPS_INT64_2D = 5
LAMMPS_STRING = 6
LAMMPS_AUTODETECT = None
LAMMPS_INT = 0
LAMMPS_INT_2D = 1
LAMMPS_DOUBLE = 2
LAMMPS_DOUBLE_2D = 3
LAMMPS_INT64 = 4
LAMMPS_INT64_2D = 5
LAMMPS_STRING = 6
# these must be kept in sync with the enums in library.h
LMP_STYLE_GLOBAL = 0
LMP_STYLE_ATOM = 1
LMP_STYLE_LOCAL = 2
LMP_STYLE_GLOBAL = 0
LMP_STYLE_ATOM = 1
LMP_STYLE_LOCAL = 2
LMP_TYPE_SCALAR = 0
LMP_TYPE_VECTOR = 1
LMP_TYPE_ARRAY = 2
LMP_SIZE_VECTOR = 3
LMP_SIZE_ROWS = 4
LMP_SIZE_COLS = 5
LMP_TYPE_SCALAR = 0
LMP_TYPE_VECTOR = 1
LMP_TYPE_ARRAY = 2
LMP_SIZE_VECTOR = 3
LMP_SIZE_ROWS = 4
LMP_SIZE_COLS = 5
LMP_VAR_EQUAL = 0
LMP_VAR_ATOM = 1
LMP_ERROR_WARNING = 0
LMP_ERROR_ONE = 1
LMP_ERROR_ALL = 2
LMP_ERROR_WORLD = 4
LMP_ERROR_UNIVERSE = 8
LMP_VAR_EQUAL = 0
LMP_VAR_ATOM = 1
# -------------------------------------------------------------------------

View File

@ -167,6 +167,8 @@ class lammps(object):
self.lib.lammps_flush_buffers.argtypes = [c_void_p]
self.lib.lammps_free.argtypes = [c_void_p]
self.lib.lammps_error.argtypes = [c_void_p, c_int, c_char_p]
self.lib.lammps_file.argtypes = [c_void_p, c_char_p]
self.lib.lammps_file.restype = None
@ -486,6 +488,26 @@ class lammps(object):
# -------------------------------------------------------------------------
def error(self, error_type, error_text):
"""Forward error to the LAMMPS Error class.
This is a wrapper around the :cpp:func:`lammps_error` function of the C-library interface.
.. versionadded:: TBD
:param error_type:
:type error_type: int
:param error_text:
:type error_text: string
"""
if error_text: error_text = error_text.encode()
else: error_text = "(unknown error)".encode()
with ExceptionCheck(self):
self.lib.lammps_error(self.lmp, error_type, error_text)
# -------------------------------------------------------------------------
def version(self):
"""Return a numerical representation of the LAMMPS version in use.
@ -1622,8 +1644,8 @@ class lammps(object):
"""Return a string with detailed information about any devices that are
usable by the GPU package.
This is a wrapper around the :cpp:func:`lammps_get_gpu_device_info`
function of the C-library interface.
This is a wrapper around the :cpp:func:`lammps_get_gpu_device_info`
function of the C-library interface.
:return: GPU device info string
:rtype: string

View File

@ -416,6 +416,89 @@ void lammps_python_finalize()
Python::finalize();
}
/* ---------------------------------------------------------------------- */
/** Call a LAMMPS Error class function
*
\verbatim embed:rst
This function is a wrapper around functions in the ``Error`` to print an
error message and then stop LAMMPS.
The *error_type* parameter selects which function to call. It is a sum
of constants from :cpp:enum:`_LMP_ERROR_CONST`. If the value does not
match any valid combination of constants a warning is printed and the
function returns.
.. versionadded:: TBD
\endverbatim
*
* \param handle pointer to a previously created LAMMPS instance
* \param error_type parameter to select function in the Error class
* \param error_text error message */
void lammps_error(void *handle, int error_type, const char *error_text)
{
auto lmp = (LAMMPS *) handle;
BEGIN_CAPTURE
{
switch (error_type) {
case LMP_ERROR_WARNING:
lmp->error->warning("(library)", 0, error_text);
break;
case LMP_ERROR_ONE:
lmp->error->one("(library)", 0, error_text);
break;
case LMP_ERROR_ALL:
lmp->error->all("(library)", 0, error_text);
break;
case LMP_ERROR_WARNING|LMP_ERROR_WORLD:
lmp->error->warning("(library)", 0, error_text);
break;
case LMP_ERROR_ONE|LMP_ERROR_WORLD:
lmp->error->one("(library)", 0, error_text);
break;
case LMP_ERROR_ALL|LMP_ERROR_WORLD:
lmp->error->all("(library)", 0, error_text);
break;
case LMP_ERROR_WARNING|LMP_ERROR_UNIVERSE:
lmp->error->universe_warn("(library)", 0, error_text);
break;
case LMP_ERROR_ONE|LMP_ERROR_UNIVERSE:
lmp->error->universe_one("(library)", 0, error_text);
break;
case LMP_ERROR_ALL|LMP_ERROR_UNIVERSE:
lmp->error->universe_all("(library)", 0, error_text);
break;
default:
auto mesg = fmt::format("Unknown error type {} for message: {}", error_type, error_text);
lmp->error->warning("(library)", 0, mesg);
}
}
END_CAPTURE
#if defined(LAMMPS_EXCEPTIONS)
// with enabled exceptions the above code will simply throw an
// exception and record the error message. So we have to explicitly
// stop here like we do in main.cpp
if (lammps_has_error(handle)) {
if (error_type & 1) {
lammps_kokkos_finalize();
lammps_python_finalize();
MPI_Abort(lmp->universe->uworld, 1);
} else if (error_type & 2) {
lammps_kokkos_finalize();
lammps_python_finalize();
lammps_mpi_finalize();
exit(1);
}
}
#endif
}
// ----------------------------------------------------------------------
// Library functions to process commands
// ----------------------------------------------------------------------
@ -1156,8 +1239,8 @@ Please also see :cpp:func:`lammps_extract_setting`,
may lead to inconsistent internal data and thus may cause failures or
crashes or bogus simulations. In general it is thus usually better
to use a LAMMPS input command that sets or changes these parameters.
Those will takes care of all side effects and necessary updates of
settings derived from such settings. Where possible a reference to
Those will take care of all side effects and necessary updates of
settings derived from such settings. Where possible, a reference to
such a command or a relevant section of the manual is given below.
The following tables list the supported names, their data types, length

View File

@ -75,6 +75,18 @@ enum _LMP_TYPE_CONST {
LMP_SIZE_COLS = 5 /*!< return number of columns */
};
/** Error codes to select the suitable function in the Error class
*
* Must be kept in sync with the equivalent constants in lammps/constants.py */
enum _LMP_ERROR_CONST {
LMP_ERROR_WARNING = 0, /*!< call Error::warning() */
LMP_ERROR_ONE = 1, /*!< called from one MPI rank */
LMP_ERROR_ALL = 2, /*!< called from all MPI ranks */
LMP_ERROR_WORLD = 4, /*!< error on Comm::world */
LMP_ERROR_UNIVERSE = 8 /*!< error on Comm::universe */
};
/* Ifdefs to allow this file to be included in C and C++ programs */
#ifdef __cplusplus
@ -97,6 +109,8 @@ void lammps_mpi_finalize();
void lammps_kokkos_finalize();
void lammps_python_finalize();
void lammps_error(void *handle, int error_type, const char *error_text);
/* ----------------------------------------------------------------------
* Library functions to process commands
* ---------------------------------------------------------------------- */

View File

@ -198,3 +198,32 @@ TEST(lammps_open_fortran, no_args)
if (verbose) std::cout << output;
MPI_Comm_free(&mycomm);
}
TEST(lammps_open_no_mpi, lammps_error)
{
const char *args[] = {"liblammps", "-log", "none", "-nocite"};
char **argv = (char **)args;
int argc = sizeof(args) / sizeof(char *);
::testing::internal::CaptureStdout();
void *alt_ptr;
void *handle = lammps_open_no_mpi(argc, argv, &alt_ptr);
std::string output = ::testing::internal::GetCapturedStdout();
EXPECT_EQ(handle, alt_ptr);
LAMMPS_NS::LAMMPS *lmp = (LAMMPS_NS::LAMMPS *)handle;
EXPECT_EQ(lmp->world, MPI_COMM_WORLD);
EXPECT_EQ(lmp->infile, stdin);
EXPECT_NE(lmp->screen, nullptr);
EXPECT_EQ(lmp->logfile, nullptr);
EXPECT_EQ(lmp->citeme, nullptr);
EXPECT_EQ(lmp->suffix_enable, 0);
EXPECT_STREQ(lmp->exename, "liblammps");
EXPECT_EQ(lmp->num_package, 0);
::testing::internal::CaptureStdout();
lammps_error(handle, 0, "test_warning");
output = ::testing::internal::GetCapturedStdout();
EXPECT_THAT(output, HasSubstr("WARNING: test_warning"));
}

View File

@ -40,6 +40,23 @@ if(CMAKE_Fortran_COMPILER)
add_executable(test_fortran_commands wrap_commands.cpp test_fortran_commands.f90)
target_link_libraries(test_fortran_commands PRIVATE flammps lammps MPI::MPI_Fortran GTest::GTestMain)
add_test(NAME FortranCommands COMMAND test_fortran_commands)
add_executable(test_fortran_get_thermo wrap_get_thermo.cpp test_fortran_get_thermo.f90)
target_link_libraries(test_fortran_get_thermo PRIVATE flammps lammps MPI::MPI_Fortran GTest::GTestMain)
add_test(NAME FortranGetThermo COMMAND test_fortran_get_thermo)
add_executable(test_fortran_box wrap_box.cpp test_fortran_box.f90)
target_link_libraries(test_fortran_box PRIVATE flammps lammps MPI::MPI_Fortran GTest::GTestMain)
add_test(NAME FortranBox COMMAND test_fortran_box)
add_executable(test_fortran_properties wrap_properties.cpp test_fortran_properties.f90 test_fortran_commands.f90)
target_link_libraries(test_fortran_properties PRIVATE flammps lammps MPI::MPI_Fortran GTest::GTestMain)
add_test(NAME FortranProperties COMMAND test_fortran_properties)
add_executable(test_fortran_extract_global wrap_extract_global.cpp test_fortran_extract_global.f90)
target_link_libraries(test_fortran_extract_global PRIVATE flammps lammps MPI::MPI_Fortran GTest::GTestMain)
add_test(NAME FortranExtractGlobal COMMAND test_fortran_extract_global)
else()
message(STATUS "Skipping Tests for the LAMMPS Fortran Module: no Fortran compiler")
endif()

View File

@ -0,0 +1,142 @@
MODULE keepbox
USE liblammps
IMPLICIT NONE
TYPE(LAMMPS) :: lmp
CHARACTER(len=40), DIMENSION(3), PARAMETER :: demo_input = &
[ CHARACTER(len=40) :: &
'region box block 0 $x 0 2 0 2', &
'create_box 1 box', &
'create_atoms 1 single 1.0 1.0 ${zpos}' ]
CHARACTER(len=40), DIMENSION(2), PARAMETER :: cont_input = &
[ CHARACTER(len=40) :: &
'create_atoms 1 single &', &
' 0.2 0.1 0.1' ]
END MODULE keepbox
FUNCTION f_lammps_with_args() BIND(C, name="f_lammps_with_args")
USE ISO_C_BINDING, ONLY: c_ptr
USE liblammps
USE keepbox, ONLY: lmp
IMPLICIT NONE
TYPE(c_ptr) :: f_lammps_with_args
CHARACTER(len=12), DIMENSION(12), PARAMETER :: args = &
[ CHARACTER(len=12) :: 'liblammps', '-log', 'none', &
'-echo','screen','-nocite','-var','zpos','1.5','-var','x','2']
lmp = lammps(args)
f_lammps_with_args = lmp%handle
END FUNCTION f_lammps_with_args
SUBROUTINE f_lammps_close() BIND(C, name="f_lammps_close")
USE ISO_C_BINDING, ONLY: c_null_ptr
USE liblammps
USE keepbox, ONLY: lmp
IMPLICIT NONE
CALL lmp%close()
lmp%handle = c_null_ptr
END SUBROUTINE f_lammps_close
SUBROUTINE f_lammps_box_setup () BIND(C)
USE liblammps
USE keepbox, ONLY : lmp, demo_input
IMPLICIT NONE
CALL lmp%commands_list(demo_input)
END SUBROUTINE f_lammps_box_setup
SUBROUTINE f_lammps_delete_everything() BIND(C)
USE liblammps
USE keepbox, ONLY : lmp
IMPLICIT NONE
CALL lmp%command("delete_atoms group all");
END SUBROUTINE f_lammps_delete_everything
FUNCTION f_lammps_extract_box_xlo () BIND(C)
USE, INTRINSIC :: ISO_C_BINDING, ONLY : c_double
USE liblammps
USE keepbox, ONLY : lmp
IMPLICIT NONE
REAL (c_double) :: f_lammps_extract_box_xlo
REAL (c_double) :: boxdim(3)
CALL lmp%extract_box(boxlo=boxdim)
f_lammps_extract_box_xlo = boxdim(1)
END FUNCTION f_lammps_extract_box_xlo
FUNCTION f_lammps_extract_box_xhi () BIND(C)
USE, INTRINSIC :: ISO_C_BINDING, ONLY : c_double
USE liblammps
USE keepbox, ONLY : lmp
IMPLICIT NONE
REAL (c_double) :: f_lammps_extract_box_xhi
REAL (c_double) :: boxdim(3)
CALL lmp%extract_box(boxhi=boxdim)
f_lammps_extract_box_xhi = boxdim(1)
END FUNCTION f_lammps_extract_box_xhi
FUNCTION f_lammps_extract_box_ylo () BIND(C)
USE, INTRINSIC :: ISO_C_BINDING, ONLY : c_double
USE liblammps
USE keepbox, ONLY : lmp
IMPLICIT NONE
REAL (c_double) :: f_lammps_extract_box_ylo
REAL (c_double) :: boxdim(3)
CALL lmp%extract_box(boxlo=boxdim)
f_lammps_extract_box_ylo = boxdim(2)
END FUNCTION f_lammps_extract_box_ylo
FUNCTION f_lammps_extract_box_yhi () BIND(C)
USE, INTRINSIC :: ISO_C_BINDING, ONLY : c_double
USE liblammps
USE keepbox, ONLY : lmp
IMPLICIT NONE
REAL (c_double) :: f_lammps_extract_box_yhi
REAL (c_double) :: boxdim(3)
CALL lmp%extract_box(boxhi=boxdim)
f_lammps_extract_box_yhi = boxdim(2)
END FUNCTION f_lammps_extract_box_yhi
FUNCTION f_lammps_extract_box_zlo () BIND(C)
USE, INTRINSIC :: ISO_C_BINDING, ONLY : c_double
USE liblammps
USE keepbox, ONLY : lmp
IMPLICIT NONE
REAL (c_double) :: f_lammps_extract_box_zlo
REAL (c_double) :: boxdim(3)
CALL lmp%extract_box(boxlo=boxdim)
f_lammps_extract_box_zlo = boxdim(2)
END FUNCTION f_lammps_extract_box_zlo
FUNCTION f_lammps_extract_box_zhi () BIND(C)
USE, INTRINSIC :: ISO_C_BINDING, ONLY : c_double
USE liblammps
USE keepbox, ONLY : lmp
IMPLICIT NONE
REAL (c_double) :: f_lammps_extract_box_zhi
REAL (c_double) :: boxdim(3)
CALL lmp%extract_box(boxhi=boxdim)
f_lammps_extract_box_zhi = boxdim(2)
END FUNCTION f_lammps_extract_box_zhi
SUBROUTINE f_lammps_reset_box_2x () BIND(C)
USE, INTRINSIC :: ISO_C_BINDING, ONLY : c_double
USE liblammps
USE keepbox, ONLY : lmp
IMPLICIT NONE
REAL (c_double) :: newlo(3), newhi(3), xy, yz, xz
xy = 0.0_c_double
yz = 0.0_c_double
xz = 0.0_c_double
newlo = [-1.0_c_double, -1.0_c_double, -1.0_c_double]
newhi = [3.0_c_double, 3.0_c_double, 3.0_c_double]
CALL lmp%reset_box(newlo, newhi, xy, yz, xz)
END SUBROUTINE f_lammps_reset_box_2x

View File

@ -1,5 +1,6 @@
MODULE keepcmds
USE liblammps
IMPLICIT NONE
TYPE(LAMMPS) :: lmp
CHARACTER(len=40), DIMENSION(3), PARAMETER :: demo_input = &
[ CHARACTER(len=40) :: &

View File

@ -0,0 +1,491 @@
MODULE keepglobal
USE liblammps
TYPE(LAMMPS) :: lmp
CHARACTER(LEN=40), DIMENSION(3), PARAMETER :: demo_input = &
[ CHARACTER(len=40) :: &
'region box block 0 $x 0 3 0 4', &
'create_box 1 box', &
'create_atoms 1 single 1.0 1.0 ${zpos}' ]
CHARACTER(LEN=40), DIMENSION(2), PARAMETER :: cont_input = &
[ CHARACTER(len=40) :: &
'create_atoms 1 single &', &
' 0.2 0.1 0.1' ]
CHARACTER(LEN=40), DIMENSION(3), PARAMETER :: pair_input = &
[ CHARACTER(LEN=40) :: &
'pair_style lj/cut 2.5', &
'pair_coeff 1 1 1.0 1.0', &
'mass 1 1.0' ]
END MODULE keepglobal
FUNCTION f_lammps_with_args() BIND(C, name="f_lammps_with_args")
USE ISO_C_BINDING, ONLY: c_ptr
USE liblammps
USE keepglobal, ONLY: lmp
IMPLICIT NONE
TYPE(c_ptr) :: f_lammps_with_args
CHARACTER(len=12), DIMENSION(12), PARAMETER :: args = &
[ CHARACTER(len=12) :: 'liblammps', '-log', 'none', &
'-echo','screen','-nocite','-var','zpos','1.5','-var','x','2']
lmp = lammps(args)
f_lammps_with_args = lmp%handle
END FUNCTION f_lammps_with_args
SUBROUTINE f_lammps_close() BIND(C, name="f_lammps_close")
USE ISO_C_BINDING, ONLY: c_null_ptr
USE liblammps
USE keepglobal, ONLY: lmp
IMPLICIT NONE
CALL lmp%close()
lmp%handle = c_null_ptr
END SUBROUTINE f_lammps_close
SUBROUTINE f_lammps_setup_extract_global () BIND(C)
USE LIBLAMMPS
USE keepglobal, ONLY : lmp, demo_input, cont_input, pair_input
IMPLICIT NONE
CALL lmp%commands_list(demo_input)
CALL lmp%commands_list(cont_input)
CALL lmp%commands_list(pair_input)
CALL lmp%command('run 0')
END SUBROUTINE f_lammps_setup_extract_global
SUBROUTINE f_lammps_setup_full_extract_global () BIND(C)
USE LIBLAMMPS
USE keepglobal, ONLY : lmp
IMPLICIT NONE
INTERFACE
SUBROUTINE f_lammps_setup_extract_global () BIND(C)
END SUBROUTINE f_lammps_setup_extract_global
END INTERFACE
CALL lmp%command('atom_style full')
CALL f_lammps_setup_extract_global
CALL lmp%command('bond_style zero')
CALL lmp%command('angle_style zero')
CALL lmp%command('dihedral_style zero')
CALL lmp%command('run 0')
END SUBROUTINE f_lammps_setup_full_extract_global
FUNCTION f_lammps_extract_global_units () BIND(C) RESULT(success)
USE, INTRINSIC :: ISO_C_BINDING, ONLY : C_int
USE LIBLAMMPS
USE keepglobal, ONLY : lmp
IMPLICIT NONE
INTEGER (C_int) :: success
CHARACTER (LEN=16) :: units
! passing strings from Fortran to C is icky, so we do the test here and
! report the result instead
units = lmp%extract_global('units')
IF ( TRIM(units) == 'lj' ) THEN
success = 1_C_int
ELSE
success = 0_C_int
END IF
END FUNCTION f_lammps_extract_global_units
FUNCTION f_lammps_extract_global_ntimestep () BIND(C)
USE, INTRINSIC :: ISO_C_BINDING, ONLY : C_int
USE keepglobal, ONLY : lmp
USE LIBLAMMPS
IMPLICIT NONE
INTEGER (C_int), POINTER :: ntimestep
INTEGER (C_int) :: f_lammps_extract_global_ntimestep
ntimestep = lmp%extract_global("ntimestep")
f_lammps_extract_global_ntimestep = ntimestep
END FUNCTION f_lammps_extract_global_ntimestep
FUNCTION f_lammps_extract_global_ntimestep_big () BIND(C)
USE, INTRINSIC :: ISO_C_BINDING, ONLY : C_int64_t
USE keepglobal, ONLY : lmp
USE LIBLAMMPS
IMPLICIT NONE
INTEGER (C_int64_t), POINTER :: ntimestep
INTEGER (C_int64_t) :: f_lammps_extract_global_ntimestep_big
ntimestep = lmp%extract_global("ntimestep")
f_lammps_extract_global_ntimestep_big = ntimestep
END FUNCTION f_lammps_extract_global_ntimestep_big
FUNCTION f_lammps_extract_global_dt () BIND(C)
USE, INTRINSIC :: ISO_C_BINDING, ONLY : C_double
USE keepglobal, ONLY : lmp
USE LIBLAMMPS
IMPLICIT NONE
REAL (C_double), POINTER :: dt
REAL (C_double) :: f_lammps_extract_global_dt
dt = lmp%extract_global("dt")
f_lammps_extract_global_dt = dt
END FUNCTION f_lammps_extract_global_dt
SUBROUTINE f_lammps_extract_global_boxlo (C_boxlo) BIND(C)
USE, INTRINSIC :: ISO_C_BINDING, ONLY : C_double
USE keepglobal, ONLY : lmp
USE LIBLAMMPS
IMPLICIT NONE
REAL (C_double), DIMENSION(3) :: C_boxlo
REAL (C_double), DIMENSION(:), POINTER :: boxlo
boxlo = lmp%extract_global("boxlo")
C_boxlo = boxlo
END SUBROUTINE f_lammps_extract_global_boxlo
SUBROUTINE f_lammps_extract_global_boxhi (C_boxhi) BIND(C)
USE, INTRINSIC :: ISO_C_BINDING, ONLY : C_double
USE keepglobal, ONLY : lmp
USE LIBLAMMPS
IMPLICIT NONE
REAL (C_double), DIMENSION(3) :: C_boxhi
REAL (C_double), DIMENSION(:), POINTER :: boxhi
boxhi = lmp%extract_global("boxhi")
C_boxhi = boxhi
END SUBROUTINE f_lammps_extract_global_boxhi
FUNCTION f_lammps_extract_global_boxxlo () BIND(C) RESULT(C_boxxlo)
USE, INTRINSIC :: ISO_C_BINDING, ONLY : C_double
USE keepglobal, ONLY : lmp
USE LIBLAMMPS
IMPLICIT NONE
REAL (C_double) :: C_boxxlo
REAL (C_double), POINTER :: boxxlo
boxxlo = lmp%extract_global("boxxlo")
C_boxxlo = boxxlo
END FUNCTION f_lammps_extract_global_boxxlo
FUNCTION f_lammps_extract_global_boxxhi () BIND(C) RESULT(C_boxxhi)
USE, INTRINSIC :: ISO_C_BINDING, ONLY : C_double
USE keepglobal, ONLY : lmp
USE LIBLAMMPS
IMPLICIT NONE
REAL (C_double) :: C_boxxhi
REAL (C_double), POINTER :: boxxhi
boxxhi = lmp%extract_global("boxxhi")
C_boxxhi = boxxhi
END FUNCTION f_lammps_extract_global_boxxhi
FUNCTION f_lammps_extract_global_boxylo () BIND(C) RESULT(C_boxylo)
USE, INTRINSIC :: ISO_C_BINDING, ONLY : C_double
USE keepglobal, ONLY : lmp
USE LIBLAMMPS
IMPLICIT NONE
REAL (C_double) :: C_boxylo
REAL (C_double), POINTER :: boxylo
boxylo = lmp%extract_global("boxylo")
C_boxylo = boxylo
END FUNCTION f_lammps_extract_global_boxylo
FUNCTION f_lammps_extract_global_boxyhi () BIND(C) RESULT(C_boxyhi)
USE, INTRINSIC :: ISO_C_BINDING, ONLY : C_double
USE keepglobal, ONLY : lmp
USE LIBLAMMPS
IMPLICIT NONE
REAL (C_double) :: C_boxyhi
REAL (C_double), POINTER :: boxyhi
boxyhi = lmp%extract_global("boxyhi")
C_boxyhi = boxyhi
END FUNCTION f_lammps_extract_global_boxyhi
FUNCTION f_lammps_extract_global_boxzlo () BIND(C) RESULT(C_boxzlo)
USE, INTRINSIC :: ISO_C_BINDING, ONLY : C_double
USE keepglobal, ONLY : lmp
USE LIBLAMMPS
IMPLICIT NONE
REAL (C_double) :: C_boxzlo
REAL (C_double), POINTER :: boxzlo
boxzlo = lmp%extract_global("boxzlo")
C_boxzlo = boxzlo
END FUNCTION f_lammps_extract_global_boxzlo
FUNCTION f_lammps_extract_global_boxzhi () BIND(C) RESULT(C_boxzhi)
USE, INTRINSIC :: ISO_C_BINDING, ONLY : C_double
USE keepglobal, ONLY : lmp
USE LIBLAMMPS
IMPLICIT NONE
REAL (C_double) :: C_boxzhi
REAL (C_double), POINTER :: boxzhi
boxzhi = lmp%extract_global("boxzhi")
C_boxzhi = boxzhi
END FUNCTION f_lammps_extract_global_boxzhi
SUBROUTINE f_lammps_extract_global_periodicity (C_periodicity) BIND(C)
USE, INTRINSIC :: ISO_C_BINDING, ONLY : C_int
USE keepglobal, ONLY : lmp
USE LIBLAMMPS
IMPLICIT NONE
INTEGER (C_int), DIMENSION(3) :: C_periodicity
INTEGER (C_int), DIMENSION(:), POINTER :: periodicity
periodicity = lmp%extract_global("periodicity")
C_periodicity = periodicity
END SUBROUTINE f_lammps_extract_global_periodicity
FUNCTION f_lammps_extract_global_triclinic () BIND(C)
USE, INTRINSIC :: ISO_C_BINDING, ONLY : C_int
USE keepglobal, ONLY : lmp
USE LIBLAMMPS
IMPLICIT NONE
INTEGER (C_int), POINTER :: triclinic
INTEGER (C_int) :: f_lammps_extract_global_triclinic
triclinic = lmp%extract_global("triclinic")
f_lammps_extract_global_triclinic = triclinic
END FUNCTION f_lammps_extract_global_triclinic
FUNCTION f_lammps_extract_global_xy () BIND(C) RESULT(C_xy)
USE, INTRINSIC :: ISO_C_BINDING, ONLY : C_double
USE keepglobal, ONLY : lmp
USE LIBLAMMPS
IMPLICIT NONE
REAL (C_double) :: C_xy
REAL (C_double), POINTER :: xy
xy = lmp%extract_global("xy")
C_xy = xy
END FUNCTION f_lammps_extract_global_xy
FUNCTION f_lammps_extract_global_xz () BIND(C) RESULT(C_xz)
USE, INTRINSIC :: ISO_C_BINDING, ONLY : C_double
USE keepglobal, ONLY : lmp
USE LIBLAMMPS
IMPLICIT NONE
REAL (C_double) :: C_xz
REAL (C_double), POINTER :: xz
xz = lmp%extract_global("xz")
C_xz = xz
END FUNCTION f_lammps_extract_global_xz
FUNCTION f_lammps_extract_global_yz () BIND(C) RESULT(C_yz)
USE, INTRINSIC :: ISO_C_BINDING, ONLY : C_double
USE keepglobal, ONLY : lmp
USE LIBLAMMPS
IMPLICIT NONE
REAL (C_double) :: C_yz
REAL (C_double), POINTER :: yz
yz = lmp%extract_global("yz")
C_yz = yz
END FUNCTION f_lammps_extract_global_yz
FUNCTION f_lammps_extract_global_natoms () BIND(C)
USE, INTRINSIC :: ISO_C_BINDING, ONLY : C_int
USE keepglobal, ONLY : lmp
USE LIBLAMMPS
IMPLICIT NONE
INTEGER (C_int), POINTER :: natoms
INTEGER (C_int) :: f_lammps_extract_global_natoms
natoms = lmp%extract_global("natoms")
f_lammps_extract_global_natoms = natoms
END FUNCTION f_lammps_extract_global_natoms
FUNCTION f_lammps_extract_global_natoms_big () BIND(C)
USE, INTRINSIC :: ISO_C_BINDING, ONLY : C_int64_t
USE keepglobal, ONLY : lmp
USE LIBLAMMPS
IMPLICIT NONE
INTEGER (C_int64_t), POINTER :: natoms
INTEGER (C_int64_t) :: f_lammps_extract_global_natoms_big
natoms = lmp%extract_global("natoms")
f_lammps_extract_global_natoms_big = natoms
END FUNCTION f_lammps_extract_global_natoms_big
FUNCTION f_lammps_extract_global_nbonds () BIND(C)
USE, INTRINSIC :: ISO_C_BINDING, ONLY : C_int
USE keepglobal, ONLY : lmp
USE LIBLAMMPS
IMPLICIT NONE
INTEGER (C_int), POINTER :: nbonds
INTEGER (C_int) :: f_lammps_extract_global_nbonds
nbonds = lmp%extract_global("nbonds")
f_lammps_extract_global_nbonds = nbonds
END FUNCTION f_lammps_extract_global_nbonds
FUNCTION f_lammps_extract_global_nbonds_big () BIND(C)
USE, INTRINSIC :: ISO_C_BINDING, ONLY : C_int64_t
USE keepglobal, ONLY : lmp
USE LIBLAMMPS
IMPLICIT NONE
INTEGER (C_int64_t), POINTER :: nbonds
INTEGER (C_int64_t) :: f_lammps_extract_global_nbonds_big
nbonds = lmp%extract_global("nbonds")
f_lammps_extract_global_nbonds_big = nbonds
END FUNCTION f_lammps_extract_global_nbonds_big
FUNCTION f_lammps_extract_global_nangles () BIND(C)
USE, INTRINSIC :: ISO_C_BINDING, ONLY : C_int
USE keepglobal, ONLY : lmp
USE LIBLAMMPS
IMPLICIT NONE
INTEGER (C_int), POINTER :: nangles
INTEGER (C_int) :: f_lammps_extract_global_nangles
nangles = lmp%extract_global("nangles")
f_lammps_extract_global_nangles = nangles
END FUNCTION f_lammps_extract_global_nangles
FUNCTION f_lammps_extract_global_nangles_big () BIND(C)
USE, INTRINSIC :: ISO_C_BINDING, ONLY : C_int64_t
USE keepglobal, ONLY : lmp
USE LIBLAMMPS
IMPLICIT NONE
INTEGER (C_int64_t), POINTER :: nangles
INTEGER (C_int64_t) :: f_lammps_extract_global_nangles_big
nangles = lmp%extract_global("nangles")
f_lammps_extract_global_nangles_big = nangles
END FUNCTION f_lammps_extract_global_nangles_big
FUNCTION f_lammps_extract_global_ndihedrals () BIND(C)
USE, INTRINSIC :: ISO_C_BINDING, ONLY : C_int
USE keepglobal, ONLY : lmp
USE LIBLAMMPS
IMPLICIT NONE
INTEGER (C_int), POINTER :: ndihedrals
INTEGER (C_int) :: f_lammps_extract_global_ndihedrals
ndihedrals = lmp%extract_global("ndihedrals")
f_lammps_extract_global_ndihedrals = ndihedrals
END FUNCTION f_lammps_extract_global_ndihedrals
FUNCTION f_lammps_extract_global_ndihedrals_big () BIND(C)
USE, INTRINSIC :: ISO_C_BINDING, ONLY : C_int64_t
USE keepglobal, ONLY : lmp
USE LIBLAMMPS
IMPLICIT NONE
INTEGER (C_int64_t), POINTER :: ndihedrals
INTEGER (C_int64_t) :: f_lammps_extract_global_ndihedrals_big
ndihedrals = lmp%extract_global("ndihedrals")
f_lammps_extract_global_ndihedrals_big = ndihedrals
END FUNCTION f_lammps_extract_global_ndihedrals_big
FUNCTION f_lammps_extract_global_nimpropers () BIND(C)
USE, INTRINSIC :: ISO_C_BINDING, ONLY : C_int
USE keepglobal, ONLY : lmp
USE LIBLAMMPS
IMPLICIT NONE
INTEGER (C_int), POINTER :: nimpropers
INTEGER (C_int) :: f_lammps_extract_global_nimpropers
nimpropers = lmp%extract_global("nimpropers")
f_lammps_extract_global_nimpropers = nimpropers
END FUNCTION f_lammps_extract_global_nimpropers
FUNCTION f_lammps_extract_global_nimpropers_big () BIND(C)
USE, INTRINSIC :: ISO_C_BINDING, ONLY : C_int64_t
USE keepglobal, ONLY : lmp
USE LIBLAMMPS
IMPLICIT NONE
INTEGER (C_int64_t), POINTER :: nimpropers
INTEGER (C_int64_t) :: f_lammps_extract_global_nimpropers_big
nimpropers = lmp%extract_global("nimpropers")
f_lammps_extract_global_nimpropers_big = nimpropers
END FUNCTION f_lammps_extract_global_nimpropers_big
FUNCTION f_lammps_extract_global_ntypes () BIND(C)
USE, INTRINSIC :: ISO_C_BINDING, ONLY : C_int
USE keepglobal, ONLY : lmp
USE LIBLAMMPS
IMPLICIT NONE
INTEGER (C_int), POINTER :: ntypes
INTEGER (C_int) :: f_lammps_extract_global_ntypes
ntypes = lmp%extract_global("ntypes")
f_lammps_extract_global_ntypes = ntypes
END FUNCTION f_lammps_extract_global_ntypes
FUNCTION f_lammps_extract_global_nlocal () BIND(C)
USE, INTRINSIC :: ISO_C_BINDING, ONLY : C_int
USE keepglobal, ONLY : lmp
USE LIBLAMMPS
IMPLICIT NONE
INTEGER (C_int), POINTER :: nlocal
INTEGER (C_int) :: f_lammps_extract_global_nlocal
nlocal = lmp%extract_global("nlocal")
f_lammps_extract_global_nlocal = nlocal
END FUNCTION f_lammps_extract_global_nlocal
FUNCTION f_lammps_extract_global_nghost () BIND(C)
USE, INTRINSIC :: ISO_C_BINDING, ONLY : C_int
USE keepglobal, ONLY : lmp
USE LIBLAMMPS
IMPLICIT NONE
INTEGER (C_int), POINTER :: nghost
INTEGER (C_int) :: f_lammps_extract_global_nghost
nghost = lmp%extract_global("nghost")
f_lammps_extract_global_nghost = nghost
END FUNCTION f_lammps_extract_global_nghost
FUNCTION f_lammps_extract_global_nmax () BIND(C)
USE, INTRINSIC :: ISO_C_BINDING, ONLY : C_int
USE keepglobal, ONLY : lmp
USE LIBLAMMPS
IMPLICIT NONE
INTEGER (C_int), POINTER :: nmax
INTEGER (C_int) :: f_lammps_extract_global_nmax
nmax = lmp%extract_global("nmax")
f_lammps_extract_global_nmax = nmax
END FUNCTION f_lammps_extract_global_nmax
FUNCTION f_lammps_extract_global_boltz () BIND(C) RESULT(C_k_B)
USE, INTRINSIC :: ISO_C_BINDING, ONLY : C_double
USE keepglobal, ONLY : lmp
USE LIBLAMMPS
IMPLICIT NONE
REAL (C_double) :: C_k_B
REAL (C_double), POINTER :: k_B
k_B = lmp%extract_global("boltz")
C_k_B = k_B
END FUNCTION f_lammps_extract_global_boltz
FUNCTION f_lammps_extract_global_hplanck () BIND(C) RESULT(C_h)
USE, INTRINSIC :: ISO_C_BINDING, ONLY : C_double
USE keepglobal, ONLY : lmp
USE LIBLAMMPS
IMPLICIT NONE
REAL (C_double) :: C_h
REAL (C_double), POINTER :: h
h = lmp%extract_global("boltz")
C_h = h
END FUNCTION f_lammps_extract_global_hplanck
FUNCTION f_lammps_extract_global_angstrom () BIND(C) RESULT(Angstrom)
USE, INTRINSIC :: ISO_C_BINDING, ONLY : C_double
USE keepglobal, ONLY : lmp
USE LIBLAMMPS
IMPLICIT NONE
REAL (C_double) :: Angstrom
REAL (C_double), POINTER :: A
A = lmp%extract_global("angstrom")
Angstrom = A
END FUNCTION f_lammps_extract_global_angstrom
FUNCTION f_lammps_extract_global_femtosecond () BIND(C) RESULT(fs)
USE, INTRINSIC :: ISO_C_BINDING, ONLY : C_double
USE keepglobal, ONLY : lmp
USE LIBLAMMPS
IMPLICIT NONE
REAL (C_double) :: fs
REAL (C_double), POINTER :: femtosecond
femtosecond = lmp%extract_global("femtosecond")
fs = femtosecond
END FUNCTION f_lammps_extract_global_femtosecond

View File

@ -0,0 +1,174 @@
MODULE keepthermo
USE liblammps
IMPLICIT NONE
TYPE(LAMMPS) :: lmp
CHARACTER(LEN=40), DIMENSION(3), PARAMETER :: demo_input = &
[ CHARACTER(len=40) :: &
'region box block 0 $x 0 3 0 4', &
'create_box 1 box', &
'create_atoms 1 single 1.0 1.0 ${zpos}' ]
CHARACTER(LEN=40), DIMENSION(2), PARAMETER :: cont_input = &
[ CHARACTER(len=40) :: &
'create_atoms 1 single &', &
' 0.2 0.1 0.1' ]
CHARACTER(LEN=40), DIMENSION(3), PARAMETER :: pair_input = &
[ CHARACTER(LEN=40) :: &
'pair_style lj/cut 2.5', &
'pair_coeff 1 1 1.0 1.0', &
'mass 1 1.0' ]
END MODULE keepthermo
FUNCTION f_lammps_with_args() BIND(C)
USE ISO_C_BINDING, ONLY: c_ptr
USE liblammps
USE keepthermo, ONLY: lmp
IMPLICIT NONE
TYPE(c_ptr) :: f_lammps_with_args
CHARACTER(len=12), DIMENSION(12), PARAMETER :: args = &
[ CHARACTER(len=12) :: 'liblammps', '-log', 'none', &
'-echo','screen','-nocite','-var','zpos','1.5','-var','x','2']
lmp = lammps(args)
f_lammps_with_args = lmp%handle
END FUNCTION f_lammps_with_args
SUBROUTINE f_lammps_close() BIND(C)
USE ISO_C_BINDING, ONLY: c_null_ptr
USE liblammps
USE keepthermo, ONLY: lmp
IMPLICIT NONE
CALL lmp%close()
lmp%handle = c_null_ptr
END SUBROUTINE f_lammps_close
SUBROUTINE f_lammps_get_thermo_setup () BIND(C)
USE liblammps
USE keepthermo, ONLY : lmp, demo_input, cont_input, pair_input
IMPLICIT NONE
CALL lmp%commands_list(demo_input)
CALL lmp%commands_list(cont_input)
CALL lmp%commands_list(pair_input)
END SUBROUTINE f_lammps_get_thermo_setup
FUNCTION f_lammps_get_thermo_natoms () BIND(C)
USE, INTRINSIC :: ISO_C_BINDING, ONLY: c_double
USE liblammps
USE keepthermo, ONLY : lmp
IMPLICIT NONE
REAL (c_double) :: f_lammps_get_thermo_natoms
f_lammps_get_thermo_natoms = lmp%get_thermo('atoms')
END FUNCTION f_lammps_get_thermo_natoms
FUNCTION f_lammps_get_thermo_dt () BIND (C)
USE, INTRINSIC :: ISO_C_BINDING, ONLY: c_double
USE liblammps
USE keepthermo, ONLY : lmp
IMPLICIT NONE
REAL (c_double) :: f_lammps_get_thermo_dt
f_lammps_get_thermo_dt = lmp%get_thermo('dt')
END FUNCTION f_lammps_get_thermo_dt
FUNCTION f_lammps_get_thermo_vol () BIND (C)
USE, INTRINSIC :: ISO_C_BINDING, ONLY: c_double
USE liblammps
USE keepthermo, ONLY : lmp
IMPLICIT NONE
REAL (c_double) :: f_lammps_get_thermo_vol
f_lammps_get_thermo_vol = lmp%get_thermo('vol')
END FUNCTION f_lammps_get_thermo_vol
FUNCTION f_lammps_get_thermo_lx () BIND (C)
USE, INTRINSIC :: ISO_C_BINDING, ONLY: c_double
USE liblammps
USE keepthermo, ONLY : lmp
IMPLICIT NONE
REAL (c_double) :: f_lammps_get_thermo_lx
f_lammps_get_thermo_lx = lmp%get_thermo('lx')
END FUNCTION f_lammps_get_thermo_lx
FUNCTION f_lammps_get_thermo_ly () BIND (C)
USE, INTRINSIC :: ISO_C_BINDING, ONLY: c_double
USE liblammps
USE keepthermo, ONLY : lmp
IMPLICIT NONE
REAL (c_double) :: f_lammps_get_thermo_ly
f_lammps_get_thermo_ly = lmp%get_thermo('ly')
END FUNCTION f_lammps_get_thermo_ly
FUNCTION f_lammps_get_thermo_lz () BIND (C)
USE, INTRINSIC :: ISO_C_BINDING, ONLY: c_double
USE liblammps
USE keepthermo, ONLY : lmp
IMPLICIT NONE
REAL (c_double) :: f_lammps_get_thermo_lz
f_lammps_get_thermo_lz = lmp%get_thermo('lz')
END FUNCTION f_lammps_get_thermo_lz
FUNCTION f_lammps_get_thermo_xlo () BIND (C)
USE, INTRINSIC :: ISO_C_BINDING, ONLY: c_double
USE liblammps
USE keepthermo, ONLY : lmp
IMPLICIT NONE
REAL (c_double) :: f_lammps_get_thermo_xlo
f_lammps_get_thermo_xlo = lmp%get_thermo('xlo')
END FUNCTION f_lammps_get_thermo_xlo
FUNCTION f_lammps_get_thermo_xhi () BIND (C)
USE, INTRINSIC :: ISO_C_BINDING, ONLY: c_double
USE liblammps
USE keepthermo, ONLY : lmp
IMPLICIT NONE
REAL (c_double) :: f_lammps_get_thermo_xhi
f_lammps_get_thermo_xhi = lmp%get_thermo('xhi')
END FUNCTION f_lammps_get_thermo_xhi
FUNCTION f_lammps_get_thermo_ylo () BIND (C)
USE, INTRINSIC :: ISO_C_BINDING, ONLY: c_double
USE liblammps
USE keepthermo, ONLY : lmp
IMPLICIT NONE
REAL (c_double) :: f_lammps_get_thermo_ylo
f_lammps_get_thermo_ylo = lmp%get_thermo('ylo')
END FUNCTION f_lammps_get_thermo_ylo
FUNCTION f_lammps_get_thermo_yhi () BIND (C)
USE, INTRINSIC :: ISO_C_BINDING, ONLY: c_double
USE liblammps
USE keepthermo, ONLY : lmp
IMPLICIT NONE
REAL (c_double) :: f_lammps_get_thermo_yhi
f_lammps_get_thermo_yhi = lmp%get_thermo('yhi')
END FUNCTION f_lammps_get_thermo_yhi
FUNCTION f_lammps_get_thermo_zlo () BIND (C)
USE, INTRINSIC :: ISO_C_BINDING, ONLY: c_double
USE liblammps
USE keepthermo, ONLY : lmp
IMPLICIT NONE
REAL (c_double) :: f_lammps_get_thermo_zlo
f_lammps_get_thermo_zlo = lmp%get_thermo('zlo')
END FUNCTION f_lammps_get_thermo_zlo
FUNCTION f_lammps_get_thermo_zhi () BIND (C)
USE, INTRINSIC :: ISO_C_BINDING, ONLY: c_double
USE liblammps
USE keepthermo, ONLY : lmp
IMPLICIT NONE
REAL (c_double) :: f_lammps_get_thermo_zhi
f_lammps_get_thermo_zhi = lmp%get_thermo('zhi')
END FUNCTION f_lammps_get_thermo_zhi

View File

@ -0,0 +1,52 @@
FUNCTION f_lammps_version () BIND(C)
USE, INTRINSIC :: ISO_C_BINDING, ONLY : C_int
USE liblammps
USE keepcmds, ONLY : lmp
IMPLICIT NONE
INTEGER (C_int) :: f_lammps_version
f_lammps_version = lmp%version()
END FUNCTION f_lammps_version
SUBROUTINE f_lammps_memory_usage (meminfo) BIND(C)
USE, INTRINSIC :: ISO_C_BINDING, ONLY : C_double
USE liblammps
USE keepcmds, ONLY : lmp
IMPLICIT NONE
REAL (C_double), DIMENSION(3), INTENT(OUT) :: meminfo
CALL lmp%memory_usage(meminfo)
END SUBROUTINE f_lammps_memory_usage
FUNCTION f_lammps_get_mpi_comm () BIND(C)
USE, INTRINSIC :: ISO_C_BINDING, ONLY : C_int
USE liblammps
USE keepcmds, ONLY : lmp
IMPLICIT NONE
INTEGER (C_int) :: f_lammps_get_mpi_comm
f_lammps_get_mpi_comm = lmp%get_mpi_comm()
END FUNCTION f_lammps_get_mpi_comm
FUNCTION f_lammps_extract_setting (Cstr) BIND(C)
USE, INTRINSIC :: ISO_C_BINDING, ONLY : C_int, C_char
USE keepcmds, ONLY : lmp
USE LIBLAMMPS
IMPLICIT NONE
INTEGER (C_int) :: f_lammps_extract_setting
CHARACTER (KIND=C_char, LEN=1), DIMENSION(*), INTENT(IN) :: Cstr
INTEGER :: strlen, i
CHARACTER (LEN=:), ALLOCATABLE :: Fstr
i = 1
DO WHILE (Cstr(i) /= ACHAR(0))
i = i + 1
END DO
strlen = i
allocate ( CHARACTER(LEN=strlen) :: Fstr)
FORALL (i=1:strlen)
Fstr(i:i) = Cstr(i)
END FORALL
f_lammps_extract_setting = lmp%extract_setting(Fstr)
deallocate (Fstr)
END FUNCTION f_lammps_extract_setting

View File

@ -0,0 +1,64 @@
// unit tests for extracting box dimensions fom a LAMMPS instance through the Fortran wrapper
#include "lammps.h"
#include <mpi.h>
#include <string>
#include "gtest/gtest.h"
// prototypes for fortran reverse wrapper functions
extern "C" {
void *f_lammps_with_args();
void f_lammps_close();
void f_lammps_box_setup();
double f_lammps_extract_box_xlo();
double f_lammps_extract_box_xhi();
double f_lammps_extract_box_ylo();
double f_lammps_extract_box_yhi();
double f_lammps_extract_box_zlo();
double f_lammps_extract_box_zhi();
void f_lammps_delete_everything();
void f_lammps_reset_box_2x();
}
class LAMMPS_commands : public ::testing::Test {
protected:
LAMMPS_NS::LAMMPS *lmp;
LAMMPS_commands() = default;
~LAMMPS_commands() override = default;
void SetUp() override
{
::testing::internal::CaptureStdout();
lmp = (LAMMPS_NS::LAMMPS *)f_lammps_with_args();
std::string output = ::testing::internal::GetCapturedStdout();
EXPECT_STREQ(output.substr(0, 8).c_str(), "LAMMPS (");
}
void TearDown() override
{
::testing::internal::CaptureStdout();
f_lammps_close();
std::string output = ::testing::internal::GetCapturedStdout();
EXPECT_STREQ(output.substr(0, 16).c_str(), "Total wall time:");
lmp = nullptr;
}
};
TEST_F(LAMMPS_commands, get_thermo)
{
f_lammps_box_setup();
EXPECT_DOUBLE_EQ(f_lammps_extract_box_xlo(), 0.0);
EXPECT_DOUBLE_EQ(f_lammps_extract_box_xhi(), 2.0);
EXPECT_DOUBLE_EQ(f_lammps_extract_box_ylo(), 0.0);
EXPECT_DOUBLE_EQ(f_lammps_extract_box_yhi(), 2.0);
EXPECT_DOUBLE_EQ(f_lammps_extract_box_zlo(), 0.0);
EXPECT_DOUBLE_EQ(f_lammps_extract_box_zhi(), 2.0);
f_lammps_delete_everything();
f_lammps_reset_box_2x();
EXPECT_DOUBLE_EQ(f_lammps_extract_box_xlo(),-1.0);
EXPECT_DOUBLE_EQ(f_lammps_extract_box_xhi(), 3.0);
EXPECT_DOUBLE_EQ(f_lammps_extract_box_ylo(),-1.0);
EXPECT_DOUBLE_EQ(f_lammps_extract_box_yhi(), 3.0);
EXPECT_DOUBLE_EQ(f_lammps_extract_box_zlo(),-1.0);
EXPECT_DOUBLE_EQ(f_lammps_extract_box_zhi(), 3.0);
};

View File

@ -0,0 +1,177 @@
// unit tests for extracting global data from a LAMMPS instance through the
// Fortran wrapper
#include "lammps.h"
#include "library.h"
#include <mpi.h>
#include <string>
#include <cstdlib>
#include <cstdint>
#include "gtest/gtest.h"
// prototypes for Fortran reverse wrapper functions
extern "C" {
void *f_lammps_with_args();
void f_lammps_close();
void f_lammps_setup_extract_global();
void f_lammps_setup_full_extract_global();
int f_lammps_extract_global_units();
int f_lammps_extract_global_ntimestep();
int64_t f_lammps_extract_global_ntimestep_big();
double f_lammps_extract_global_dt();
void f_lammps_extract_global_boxlo(double[3]);
void f_lammps_extract_global_boxhi(double[3]);
double f_lammps_extract_global_boxxlo();
double f_lammps_extract_global_boxylo();
double f_lammps_extract_global_boxzlo();
double f_lammps_extract_global_boxxhi();
double f_lammps_extract_global_boxyhi();
double f_lammps_extract_global_boxzhi();
void f_lammps_extract_global_periodicity(int[3]);
int f_lammps_extract_global_triclinic();
double f_lammps_extract_global_xy();
double f_lammps_extract_global_yz();
double f_lammps_extract_global_xz();
int f_lammps_extract_global_natoms();
int64_t f_lammps_extract_global_natoms_big();
int f_lammps_extract_global_nbonds();
int64_t f_lammps_extract_global_nbonds_big();
int f_lammps_extract_global_nangles();
int64_t f_lammps_extract_global_nangles_big();
int f_lammps_extract_global_ndihedrals();
int64_t f_lammps_extract_global_ndihedrals_big();
int f_lammps_extract_global_nimpropers();
int64_t f_lammps_extract_global_nimpropers_big();
int f_lammps_extract_global_ntypes();
int f_lammps_extract_global_nlocal();
int f_lammps_extract_global_nghost();
int f_lammps_extract_global_nmax();
double f_lammps_extract_global_boltz();
double f_lammps_extract_global_hplanck();
double f_lammps_extract_global_angstrom();
double f_lammps_extract_global_femtosecond();
}
class LAMMPS_extract_global : public ::testing::Test {
protected:
LAMMPS_NS::LAMMPS *lmp;
LAMMPS_extract_global() = default;
~LAMMPS_extract_global() override = default;
void SetUp() override
{
::testing::internal::CaptureStdout();
lmp = (LAMMPS_NS::LAMMPS *)f_lammps_with_args();
std::string output = ::testing::internal::GetCapturedStdout();
EXPECT_STREQ(output.substr(0, 8).c_str(), "LAMMPS (");
}
void TearDown() override
{
::testing::internal::CaptureStdout();
f_lammps_close();
std::string output = ::testing::internal::GetCapturedStdout();
EXPECT_STREQ(output.substr(0, 16).c_str(), "Total wall time:");
lmp = nullptr;
}
};
TEST_F(LAMMPS_extract_global, units)
{
f_lammps_setup_extract_global();
EXPECT_EQ(f_lammps_extract_global_units(), 1);
};
TEST_F(LAMMPS_extract_global, ntimestep)
{
f_lammps_setup_extract_global();
#ifdef LAMMPS_SMALLSMALL
EXPECT_EQ(f_lammps_extract_global_ntimestep(), 0);
#else
EXPECT_EQ(f_lammps_extract_global_ntimestep_big(), 0l);
#endif
};
TEST_F(LAMMPS_extract_global, dt)
{
f_lammps_setup_extract_global();
EXPECT_DOUBLE_EQ(f_lammps_extract_global_dt(), 0.005);
};
TEST_F(LAMMPS_extract_global, boxprops)
{
f_lammps_setup_extract_global();
double boxlo[3], boxhi[3];
f_lammps_extract_global_boxlo(boxlo);
EXPECT_DOUBLE_EQ(boxlo[0], 0.0);
EXPECT_DOUBLE_EQ(boxlo[1], 0.0);
EXPECT_DOUBLE_EQ(boxlo[2], 0.0);
f_lammps_extract_global_boxhi(boxhi);
EXPECT_DOUBLE_EQ(boxhi[0], 2.0);
EXPECT_DOUBLE_EQ(boxhi[1], 3.0);
EXPECT_DOUBLE_EQ(boxhi[2], 4.0);
EXPECT_DOUBLE_EQ(f_lammps_extract_global_boxxlo(), 0.0);
EXPECT_DOUBLE_EQ(f_lammps_extract_global_boxxhi(), 2.0);
EXPECT_DOUBLE_EQ(f_lammps_extract_global_boxylo(), 0.0);
EXPECT_DOUBLE_EQ(f_lammps_extract_global_boxyhi(), 3.0);
EXPECT_DOUBLE_EQ(f_lammps_extract_global_boxzlo(), 0.0);
EXPECT_DOUBLE_EQ(f_lammps_extract_global_boxzhi(), 4.0);
int periodicity[3];
f_lammps_extract_global_periodicity(periodicity);
EXPECT_EQ(periodicity[0], 1);
EXPECT_EQ(periodicity[1], 1);
EXPECT_EQ(periodicity[2], 1);
EXPECT_EQ(f_lammps_extract_global_triclinic(), 0);
EXPECT_DOUBLE_EQ(f_lammps_extract_global_xy(), 0.0);
EXPECT_DOUBLE_EQ(f_lammps_extract_global_yz(), 0.0);
EXPECT_DOUBLE_EQ(f_lammps_extract_global_xz(), 0.0);
};
TEST_F(LAMMPS_extract_global, atomprops)
{
f_lammps_setup_extract_global();
#ifdef LAMMPS_SMALLSMALL
EXPECT_EQ(f_lammps_extract_global_natoms(), 2);
EXPECT_EQ(f_lammps_extract_global_nbonds(), 0);
EXPECT_EQ(f_lammps_extract_global_nangles(), 0);
EXPECT_EQ(f_lammps_extract_global_ndihedrals(), 0);
#else
EXPECT_EQ(f_lammps_extract_global_natoms_big(), 2l);
EXPECT_EQ(f_lammps_extract_global_nbonds_big(), 0l);
EXPECT_EQ(f_lammps_extract_global_nangles_big(), 0l);
EXPECT_EQ(f_lammps_extract_global_ndihedrals_big(), 0l);
#endif
EXPECT_EQ(f_lammps_extract_global_ntypes(), 1);
EXPECT_EQ(f_lammps_extract_global_nlocal(), 2);
EXPECT_EQ(f_lammps_extract_global_nghost(), 41);
EXPECT_EQ(f_lammps_extract_global_nmax(), 16384);
EXPECT_DOUBLE_EQ(f_lammps_extract_global_boltz(), 1.0);
EXPECT_DOUBLE_EQ(f_lammps_extract_global_hplanck(), 1.0);
EXPECT_DOUBLE_EQ(f_lammps_extract_global_angstrom(), 1.0);
EXPECT_DOUBLE_EQ(f_lammps_extract_global_femtosecond(), 1.0);
};
TEST_F(LAMMPS_extract_global, fullprops)
{
if (! lammps_has_style(lmp, "atom", "full")) GTEST_SKIP();
// This is not currently the world's most convincing test....
f_lammps_setup_full_extract_global();
#ifdef LAMMPS_SMALLSMALL
EXPECT_EQ(f_lammps_extract_global_natoms(), 2);
EXPECT_EQ(f_lammps_extract_global_nbonds(), 0);
EXPECT_EQ(f_lammps_extract_global_nangles(), 0);
EXPECT_EQ(f_lammps_extract_global_ndihedrals(), 0);
#else
EXPECT_EQ(f_lammps_extract_global_natoms_big(), 2l);
EXPECT_EQ(f_lammps_extract_global_nbonds_big(), 0l);
EXPECT_EQ(f_lammps_extract_global_nangles_big(), 0l);
EXPECT_EQ(f_lammps_extract_global_ndihedrals_big(), 0l);
#endif
}

View File

@ -0,0 +1,67 @@
// unit tests for getting thermodynamic output from a LAMMPS instance through the Fortran wrapper
#include "lammps.h"
#include <mpi.h>
#include <string>
#include "gtest/gtest.h"
// prototypes for fortran reverse wrapper functions
extern "C" {
void *f_lammps_with_args();
void f_lammps_close();
void f_lammps_get_thermo_setup();
double f_lammps_get_thermo_natoms();
double f_lammps_get_thermo_dt();
double f_lammps_get_thermo_vol();
double f_lammps_get_thermo_lx();
double f_lammps_get_thermo_ly();
double f_lammps_get_thermo_lz();
double f_lammps_get_thermo_xlo();
double f_lammps_get_thermo_xhi();
double f_lammps_get_thermo_ylo();
double f_lammps_get_thermo_yhi();
double f_lammps_get_thermo_zlo();
double f_lammps_get_thermo_zhi();
}
class LAMMPS_thermo : public ::testing::Test {
protected:
LAMMPS_NS::LAMMPS *lmp;
LAMMPS_thermo() = default;
~LAMMPS_thermo() override = default;
void SetUp() override
{
::testing::internal::CaptureStdout();
lmp = (LAMMPS_NS::LAMMPS *)f_lammps_with_args();
std::string output = ::testing::internal::GetCapturedStdout();
EXPECT_STREQ(output.substr(0, 8).c_str(), "LAMMPS (");
}
void TearDown() override
{
::testing::internal::CaptureStdout();
f_lammps_close();
std::string output = ::testing::internal::GetCapturedStdout();
EXPECT_STREQ(output.substr(0, 16).c_str(), "Total wall time:");
lmp = nullptr;
}
};
TEST_F(LAMMPS_thermo, get_thermo)
{
EXPECT_DOUBLE_EQ(f_lammps_get_thermo_natoms(), 0.0);
f_lammps_get_thermo_setup();
EXPECT_DOUBLE_EQ(f_lammps_get_thermo_natoms(), 2.0);
EXPECT_DOUBLE_EQ(f_lammps_get_thermo_dt(), 0.005);
EXPECT_DOUBLE_EQ(f_lammps_get_thermo_vol(), 24.0);
EXPECT_DOUBLE_EQ(f_lammps_get_thermo_lx(), 2.0);
EXPECT_DOUBLE_EQ(f_lammps_get_thermo_ly(), 3.0);
EXPECT_DOUBLE_EQ(f_lammps_get_thermo_lz(), 4.0);
EXPECT_DOUBLE_EQ(f_lammps_get_thermo_xlo(), 0.0);
EXPECT_DOUBLE_EQ(f_lammps_get_thermo_xhi(), 2.0);
EXPECT_DOUBLE_EQ(f_lammps_get_thermo_ylo(), 0.0);
EXPECT_DOUBLE_EQ(f_lammps_get_thermo_yhi(), 3.0);
EXPECT_DOUBLE_EQ(f_lammps_get_thermo_zlo(), 0.0);
EXPECT_DOUBLE_EQ(f_lammps_get_thermo_zhi(), 4.0);
};

View File

@ -0,0 +1,109 @@
// unit tests for getting LAMMPS properties through the Fortran wrapper
#include "lammps.h"
//#include <cstdio> // for stdin, stdout
#include "library.h"
#include <mpi.h>
#include <string>
#include "gtest/gtest.h"
// prototypes for fortran reverse wrapper functions
extern "C" {
void *f_lammps_with_args();
void f_lammps_close();
int f_lammps_version();
void f_lammps_memory_usage(double*);
int f_lammps_get_mpi_comm();
int f_lammps_extract_setting(const char*);
}
class LAMMPS_properties : public ::testing::Test {
protected:
LAMMPS_NS::LAMMPS *lmp;
LAMMPS_properties() = default;
~LAMMPS_properties() override = default;
void SetUp() override
{
::testing::internal::CaptureStdout();
lmp = (LAMMPS_NS::LAMMPS *)f_lammps_with_args();
std::string output = ::testing::internal::GetCapturedStdout();
EXPECT_STREQ(output.substr(0, 8).c_str(), "LAMMPS (");
}
void TearDown() override
{
::testing::internal::CaptureStdout();
f_lammps_close();
std::string output = ::testing::internal::GetCapturedStdout();
EXPECT_STREQ(output.substr(0, 16).c_str(), "Total wall time:");
lmp = nullptr;
}
};
TEST_F(LAMMPS_properties, version)
{
EXPECT_LT(20200917, f_lammps_version());
};
TEST_F(LAMMPS_properties, memory_usage)
{
// copied from c-library, with a two-character modification
double meminfo[3];
f_lammps_memory_usage(meminfo);
EXPECT_GT(meminfo[0], 0.0);
#if defined(__linux__) || defined(_WIN32)
EXPECT_GE(meminfo[1], 0.0);
#endif
#if (defined(__linux__) || defined(__APPLE__) || defined(_WIN32)) && !defined(__INTEL_LLVM_COMPILER)
EXPECT_GT(meminfo[2], 0.0);
#endif
};
TEST_F(LAMMPS_properties, get_mpi_comm)
{
int f_comm = f_lammps_get_mpi_comm();
if ( lammps_config_has_mpi_support() )
EXPECT_GE(f_comm, 0);
else
EXPECT_EQ(f_comm, -1);
};
TEST_F(LAMMPS_properties, extract_setting)
{
#if defined(LAMMPS_SMALLSMALL)
EXPECT_EQ(f_lammps_extract_setting("bigint"), 4);
#else
EXPECT_EQ(f_lammps_extract_setting("bigint"), 8);
#endif
#if defined(LAMMPS_BIGBIG)
EXPECT_EQ(f_lammps_extract_setting("tagint"), 8);
EXPECT_EQ(f_lammps_extract_setting("imageint"), 8);
#else
EXPECT_EQ(f_lammps_extract_setting("tagint"), 4);
EXPECT_EQ(f_lammps_extract_setting("imageint"), 4);
#endif
EXPECT_EQ(f_lammps_extract_setting("box_exist"), 0);
EXPECT_EQ(f_lammps_extract_setting("dimension"), 3);
EXPECT_EQ(f_lammps_extract_setting("world_size"), 1);
EXPECT_EQ(f_lammps_extract_setting("world_rank"), 0);
EXPECT_EQ(f_lammps_extract_setting("universe_size"), 1);
EXPECT_EQ(f_lammps_extract_setting("universe_rank"), 0);
EXPECT_GT(f_lammps_extract_setting("nthreads"), 0);
EXPECT_EQ(f_lammps_extract_setting("newton_pair"), 1);
EXPECT_EQ(f_lammps_extract_setting("newton_bond"), 1);
EXPECT_EQ(f_lammps_extract_setting("ntypes"), 0);
EXPECT_EQ(f_lammps_extract_setting("nbondtypes"), 0);
EXPECT_EQ(f_lammps_extract_setting("nangletypes"), 0);
EXPECT_EQ(f_lammps_extract_setting("ndihedraltypes"), 0);
EXPECT_EQ(f_lammps_extract_setting("nimpropertypes"), 0);
EXPECT_EQ(f_lammps_extract_setting("molecule_flag"), 0);
EXPECT_EQ(f_lammps_extract_setting("q_flag"), 0);
EXPECT_EQ(f_lammps_extract_setting("mu_flag"), 0);
EXPECT_EQ(f_lammps_extract_setting("rmass_flag"), 0);
EXPECT_EQ(f_lammps_extract_setting("UNKNOWN"), -1);
};

View File

@ -45,11 +45,21 @@ class PythonOpen(unittest.TestCase):
def testWithArgs(self):
"""Create LAMMPS instance with a few arguments"""
lmp=lammps(name=self.machine,
cmdargs=['-nocite','-sf','opt','-log','none'])
lmp=lammps(name=self.machine,cmdargs=['-nocite','-sf','opt','-log','none'])
self.assertIsNot(lmp.lmp,None)
self.assertEqual(lmp.opened,1)
def testError(self):
"""Print warning message through LAMMPS Error class"""
lmp=lammps(name=self.machine,cmdargs=['-nocite','-log','none','-screen','tmp.error.output'])
lmp.error(0,'test_warning')
lmp.close()
with open('tmp.error.output','r') as f:
output = f.read()
self.assertTrue('LAMMPS' in output)
self.assertTrue('Total wall time' in output)
self.assertTrue('WARNING: test_warning' in output)
def testContextManager(self):
"""Automatically clean up LAMMPS instance"""
with lammps(name=self.machine) as lmp: