update fortran2 module

This commit is contained in:
Axel Kohlmeyer
2020-10-01 23:20:52 -04:00
parent 51d55aa036
commit 2c7a686220
3 changed files with 2026 additions and 1207 deletions

File diff suppressed because it is too large Load Diff

View File

@ -1,265 +1,265 @@
LAMMPS.F90 defines a Fortran 2003 module, LAMMPS, which wraps all functions in LAMMPS.F90 defines a Fortran 2003 module, LAMMPS, which wraps all functions in
src/library.h so they can be used directly from Fortran-encoded programs. src/library.h so they can be used directly from Fortran-encoded programs.
All functions in src/library.h that use and/or return C-style pointers have All functions in src/library.h that use and/or return C-style pointers have
Fortran wrapper functions that use Fortran-style arrays, pointers, and Fortran wrapper functions that use Fortran-style arrays, pointers, and
strings; all C-style memory management is handled internally with no user strings; all C-style memory management is handled internally with no user
intervention. See --USE-- for notes on how this interface differs from the intervention. See --USE-- for notes on how this interface differs from the
C interface (and the Python interface). C interface (and the Python interface).
This interface was created by Karl Hammond who you can contact with This interface was created by Karl Hammond who you can contact with
questions: questions:
Karl D. Hammond Karl D. Hammond
University of Tennessee, Knoxville University of Tennessee, Knoxville
karlh at ugcs.caltech.edu karlh at ugcs.caltech.edu
karlh at utk.edu karlh at utk.edu
------------------------------------- -------------------------------------
--COMPILATION-- --COMPILATION--
First, be advised that mixed-language programming is not trivial. It requires First, be advised that mixed-language programming is not trivial. It requires
you to link in the required libraries of all languages you use (in this case, you to link in the required libraries of all languages you use (in this case,
those for Fortran, C, and C++), as well as any other libraries required. those for Fortran, C, and C++), as well as any other libraries required.
You are also advised to read the --USE-- section below before trying to You are also advised to read the --USE-- section below before trying to
compile. compile.
The following steps will work to compile this module (replace ${LAMMPS_SRC} The following steps will work to compile this module (replace ${LAMMPS_SRC}
with the path to your LAMMPS source directory). with the path to your LAMMPS source directory).
Steps 3-5 are accomplished, possibly after some modifications to Steps 3-5 are accomplished, possibly after some modifications to
the makefile, by make using the attached makefile. Said makefile also builds the makefile, by make using the attached makefile. Said makefile also builds
the dynamically-linkable library (liblammps_fortran.so). the dynamically-linkable library (liblammps_fortran.so).
** STATIC LIBRARY INSTRUCTIONS ** ** STATIC LIBRARY INSTRUCTIONS **
(1) Compile LAMMPS as a static library. (1) Compile LAMMPS as a static library.
Call the resulting file ${LAMMPS_LIB}, which will have an actual name Call the resulting file ${LAMMPS_LIB}, which will have an actual name
like liblmp_openmpi.a. If compiling using the MPI stubs in like liblmp_openmpi.a. If compiling using the MPI stubs in
${LAMMPS_SRC}/STUBS, you will need to know where libmpi_stubs.a ${LAMMPS_SRC}/STUBS, you will need to know where libmpi_stubs.a
is as well (I'll call it ${MPI_STUBS} hereafter) is as well (I'll call it ${MPI_STUBS} hereafter)
(2) Copy said library to your Fortran program's source directory or replace (2) Copy said library to your Fortran program's source directory or replace
${LAMMPS_LIB} with its full path in the instructions below. ${LAMMPS_LIB} with its full path in the instructions below.
(3) Compile (but don't link!) LAMMPS.F90. Example: (3) Compile (but don't link!) LAMMPS.F90. Example:
mpif90 -c LAMMPS.f90 mpif90 -c LAMMPS.f90
OR OR
gfortran -c LAMMPS.F90 gfortran -c LAMMPS.F90
NOTE: you may get a warning such as, NOTE: you may get a warning such as,
subroutine lammps_open_wrapper (argc, argv, communicator, ptr) & subroutine lammps_open_wrapper (argc, argv, communicator, ptr) &
Variable 'communicator' at (1) is a parameter to the BIND(C) Variable 'communicator' at (1) is a parameter to the BIND(C)
procedure 'lammps_open_wrapper' but may not be C interoperable procedure 'lammps_open_wrapper' but may not be C interoperable
This is normal (see --IMPLEMENTATION NOTES--). This is normal (see --IMPLEMENTATION NOTES--).
(4) Compile (but don't link) LAMMPS-wrapper.cpp. You will need its header (4) Compile (but don't link) LAMMPS-wrapper.cpp. You will need its header
file as well. You will have to provide the locations of LAMMPS's file as well. You will have to provide the locations of LAMMPS's
header files. For example, header files. For example,
mpicxx -c -I${LAMMPS_SRC} LAMMPS-wrapper.cpp mpicxx -c -I${LAMMPS_SRC} LAMMPS-wrapper.cpp
OR OR
g++ -c -I${LAMMPS_SRC} -I${LAMMPS_SRC}/STUBS LAMMPS-wrapper.cpp g++ -c -I${LAMMPS_SRC} -I${LAMMPS_SRC}/STUBS LAMMPS-wrapper.cpp
OR OR
icpc -c -I${LAMMPS_SRC} -I${LAMMPS_SRC}/STUBS LAMMPS-wrapper.cpp icpc -c -I${LAMMPS_SRC} -I${LAMMPS_SRC}/STUBS LAMMPS-wrapper.cpp
(5) OPTIONAL: Make a library from the object files so you can carry around (5) OPTIONAL: Make a library from the object files so you can carry around
two files instead of three. Example: two files instead of three. Example:
ar rs liblammps_fortran.a LAMMPS.o LAMMPS-wrapper.o ar rs liblammps_fortran.a LAMMPS.o LAMMPS-wrapper.o
This will create the file liblammps_fortran.a that you can use in place This will create the file liblammps_fortran.a that you can use in place
of "LAMMPS.o LAMMPS-wrapper.o" later. Note that you will still of "LAMMPS.o LAMMPS-wrapper.o" later. Note that you will still
need to have the .mod file from part (3). need to have the .mod file from part (3).
It is also possible to add LAMMPS.o and LAMMPS-wrapper.o into the It is also possible to add LAMMPS.o and LAMMPS-wrapper.o into the
LAMMPS library (e.g., liblmp_openmpi.a) instead of creating a separate LAMMPS library (e.g., liblmp_openmpi.a) instead of creating a separate
library, like so: library, like so:
ar rs ${LAMMPS_LIB} LAMMPS.o LAMMPS-wrapper.o ar rs ${LAMMPS_LIB} LAMMPS.o LAMMPS-wrapper.o
In this case, you can now use the Fortran wrapper functions as if they In this case, you can now use the Fortran wrapper functions as if they
were part of the usual LAMMPS library interface (if you have the module were part of the usual LAMMPS library interface (if you have the module
file visible to the compiler, that is). file visible to the compiler, that is).
(6) Compile (but don't link) your Fortran program. Example: (6) Compile (but don't link) your Fortran program. Example:
mpif90 -c myfreeformatfile.f90 mpif90 -c myfreeformatfile.f90
mpif90 -c myfixedformatfile.f mpif90 -c myfixedformatfile.f
OR OR
gfortran -c myfreeformatfile.f90 gfortran -c myfreeformatfile.f90
gfortran -c myfixedformatfile.f gfortran -c myfixedformatfile.f
The object files generated by these steps are collectively referred to The object files generated by these steps are collectively referred to
as ${my_object_files} in the next step(s). as ${my_object_files} in the next step(s).
IMPORTANT: If the Fortran module from part (3) is not in the current IMPORTANT: If the Fortran module from part (3) is not in the current
directory or in one searched by the compiler for module files, you will directory or in one searched by the compiler for module files, you will
need to include that location via the -I flag to the compiler, like so: need to include that location via the -I flag to the compiler, like so:
mpif90 -I${LAMMPS_SRC}/examples/COUPLE/fortran2 -c myfreeformatfile.f90 mpif90 -I${LAMMPS_SRC}/examples/COUPLE/fortran2 -c myfreeformatfile.f90
(7) Link everything together, including any libraries needed by LAMMPS (such (7) Link everything together, including any libraries needed by LAMMPS (such
as the C++ standard library, the C math library, the JPEG library, fftw, as the C++ standard library, the C math library, the JPEG library, fftw,
etc.) For example, etc.) For example,
mpif90 LAMMPS.o LAMMPS-wrapper.o ${my_object_files} \ mpif90 LAMMPS.o LAMMPS-wrapper.o ${my_object_files} \
${LAMMPS_LIB} -lmpi_cxx -lstdc++ -lm ${LAMMPS_LIB} -lmpi_cxx -lstdc++ -lm
OR OR
gfortran LAMMPS.o LAMMPS-wrapper.o ${my_object_files} \ gfortran LAMMPS.o LAMMPS-wrapper.o ${my_object_files} \
${LAMMPS_LIB} ${MPI_STUBS} -lstdc++ -lm ${LAMMPS_LIB} ${MPI_STUBS} -lstdc++ -lm
OR OR
ifort LAMMPS.o LAMMPS-wrapper.o ${my_object_files} \ ifort LAMMPS.o LAMMPS-wrapper.o ${my_object_files} \
${LAMMPS_LIB} ${MPI_STUBS} -cxxlib -lm ${LAMMPS_LIB} ${MPI_STUBS} -cxxlib -lm
Any other required libraries (e.g. -ljpeg, -lfftw) should be added to Any other required libraries (e.g. -ljpeg, -lfftw) should be added to
the end of this line. the end of this line.
You should now have a working executable. You should now have a working executable.
** DYNAMIC LIBRARY INSTRUCTIONS ** ** DYNAMIC LIBRARY INSTRUCTIONS **
(1) Compile LAMMPS as a dynamic library (1) Compile LAMMPS as a dynamic library
(make makeshlib && make -f Makefile.shlib [targetname]). (make makeshlib && make -f Makefile.shlib [targetname]).
(2) Compile, but don't link, LAMMPS.F90 using the -fPIC flag, such as (2) Compile, but don't link, LAMMPS.F90 using the -fPIC flag, such as
mpif90 -fPIC -c LAMMPS.f90 mpif90 -fPIC -c LAMMPS.f90
(3) Compile, but don't link, LAMMPS-wrapper.cpp in the same manner, e.g. (3) Compile, but don't link, LAMMPS-wrapper.cpp in the same manner, e.g.
mpicxx -fPIC -c LAMMPS-wrapper.cpp mpicxx -fPIC -c LAMMPS-wrapper.cpp
(4) Make the dynamic library, like so: (4) Make the dynamic library, like so:
mpif90 -fPIC -shared -o liblammps_fortran.so LAMMPS.o LAMMPS-wrapper.o mpif90 -fPIC -shared -o liblammps_fortran.so LAMMPS.o LAMMPS-wrapper.o
(5) Compile your program, such as, (5) Compile your program, such as,
mpif90 -I${LAMMPS_SRC}/examples/COUPLE/fortran2 -c myfreeformatfile.f90 mpif90 -I${LAMMPS_SRC}/examples/COUPLE/fortran2 -c myfreeformatfile.f90
where ${LAMMPS_SRC}/examples/COUPLE/fortran2 contains the .mod file from where ${LAMMPS_SRC}/examples/COUPLE/fortran2 contains the .mod file from
step (3) step (3)
(6) Link everything together, such as (6) Link everything together, such as
mpif90 ${my_object_files} -L${LAMMPS_SRC} \ mpif90 ${my_object_files} -L${LAMMPS_SRC} \
-L${LAMMPS_SRC}/examples/COUPLE/fortran2 -llammps_fortran \ -L${LAMMPS_SRC}/examples/COUPLE/fortran2 -llammps_fortran \
-llammps_openmpi -lmpi_cxx -lstdc++ -lm -llammps_openmpi -lmpi_cxx -lstdc++ -lm
If you wish to avoid the -L flags, add the directories containing your If you wish to avoid the -L flags, add the directories containing your
shared libraries to the LIBRARY_PATH environment variable. At run time, you shared libraries to the LIBRARY_PATH environment variable. At run time, you
will have to add these directories to LD_LIBRARY_PATH as well; otherwise, will have to add these directories to LD_LIBRARY_PATH as well; otherwise,
your executable will not find the libraries it needs. your executable will not find the libraries it needs.
------------------------------------- -------------------------------------
--USAGE-- --USAGE--
To use this API, your program unit (PROGRAM/SUBROUTINE/FUNCTION/MODULE/etc.) To use this API, your program unit (PROGRAM/SUBROUTINE/FUNCTION/MODULE/etc.)
should look something like this: should look something like this:
program call_lammps program call_lammps
use LAMMPS use LAMMPS
! Other modules, etc. ! Other modules, etc.
implicit none implicit none
type (lammps_instance) :: lmp ! This is a pointer to your LAMMPS instance type (lammps_instance) :: lmp ! This is a pointer to your LAMMPS instance
real (C_double) :: fix real (C_double) :: fix
real (C_double), dimension(:), pointer :: fix2 real (C_double), dimension(:), pointer :: fix2
! Rest of declarations ! Rest of declarations
call lammps_open_no_mpi ('lmp -in /dev/null -screen out.lammps',lmp) call lammps_open_no_mpi ('lmp -in /dev/null -screen out.lammps',lmp)
! Set up rest of program here ! Set up rest of program here
call lammps_file (lmp, 'in.example') call lammps_file (lmp, 'in.example')
call lammps_extract_fix (fix, lmp, '2', 0, 1, 1, 1) call lammps_extract_fix (fix, lmp, '2', 0, 1, 1, 1)
call lammps_extract_fix (fix2, lmp, '4', 0, 2, 1, 1) call lammps_extract_fix (fix2, lmp, '4', 0, 2, 1, 1)
call lammps_close (lmp) call lammps_close (lmp)
end program call_lammps end program call_lammps
Important notes: Important notes:
* Though I dislike the use of pointers, they are necessary when communicating * Though I dislike the use of pointers, they are necessary when communicating
with C and C++, which do not support Fortran's ALLOCATABLE attribute. with C and C++, which do not support Fortran's ALLOCATABLE attribute.
* There is no need to deallocate C-allocated memory; this is done for you in * There is no need to deallocate C-allocated memory; this is done for you in
the cases when it is done (which are all cases when pointers are not the cases when it is done (which are all cases when pointers are not
accepted, such as global fix data) accepted, such as global fix data)
* All arguments which are char* variables in library.cpp are character (len=*) * All arguments which are char* variables in library.cpp are character (len=*)
variables here. For example, variables here. For example,
call lammps_command (lmp, 'units metal') call lammps_command (lmp, 'units metal')
will work as expected. will work as expected.
* The public functions (the only ones you can use) have interfaces as * The public functions (the only ones you can use) have interfaces as
described in the comments at the top of LAMMPS.F90. They are not always described in the comments at the top of LAMMPS.F90. They are not always
the same as those in library.h, since C strings are replaced by Fortran the same as those in library.h, since C strings are replaced by Fortran
strings and the like. strings and the like.
* The module attempts to check whether you have done something stupid (such * The module attempts to check whether you have done something stupid (such
as assign a 2D array to a scalar), but it's not perfect. For example, the as assign a 2D array to a scalar), but it's not perfect. For example, the
command command
call lammps_extract_global (nlocal, ptr, 'nlocal') call lammps_extract_global (nlocal, ptr, 'nlocal')
will give nlocal correctly if nlocal is a pointer to type INTEGER, but it will give nlocal correctly if nlocal is a pointer to type INTEGER, but it
will give the wrong answer if nlocal is a pointer to type REAL. This is a will give the wrong answer if nlocal is a pointer to type REAL. This is a
feature of the (void*) type cast in library.cpp. There is no way I can feature of the (void*) type cast in library.cpp. There is no way I can
check this for you! It WILL catch you if you pass it an allocatable or check this for you! It WILL catch you if you pass it an allocatable or
fixed-size array when it expects a pointer. fixed-size array when it expects a pointer.
* Arrays constructed from temporary data from LAMMPS are ALLOCATABLE, and * Arrays constructed from temporary data from LAMMPS are ALLOCATABLE, and
represent COPIES of data, not the originals. Functions like represent COPIES of data, not the originals. Functions like
lammps_extract_atom, which return actual LAMMPS data, are pointers. lammps_extract_atom, which return actual LAMMPS data, are pointers.
* IMPORTANT: Due to the differences between C and Fortran arrays (C uses * IMPORTANT: Due to the differences between C and Fortran arrays (C uses
row-major vectors, Fortran uses column-major vectors), all arrays returned row-major vectors, Fortran uses column-major vectors), all arrays returned
from LAMMPS have their indices swapped. from LAMMPS have their indices swapped.
* An example of a complete program, simple.f90, is included with this * An example of a complete program, simple.f90, is included with this
package. package.
------------------------------------- -------------------------------------
--TROUBLESHOOTING-- --TROUBLESHOOTING--
Compile-time errors (when compiling LAMMPS.F90, that is) probably indicate Compile-time errors (when compiling LAMMPS.F90, that is) probably indicate
that your compiler is not new enough to support Fortran 2003 features. For that your compiler is not new enough to support Fortran 2003 features. For
example, GCC 4.1.2 will not compile this module, but GCC 4.4.0 will. example, GCC 4.1.2 will not compile this module, but GCC 4.4.0 will.
If your compiler balks at 'use, intrinsic :: ISO_C_binding,' try removing the If your compiler balks at 'use, intrinsic :: ISO_C_binding,' try removing the
intrinsic part so it looks like an ordinary module. However, it is likely intrinsic part so it looks like an ordinary module. However, it is likely
that such a compiler will also have problems with everything else in the that such a compiler will also have problems with everything else in the
file as well. file as well.
If you get a segfault as soon as the lammps_open call is made, check that you If you get a segfault as soon as the lammps_open call is made, check that you
compiled your program AND LAMMPS-wrapper.cpp using the same MPI headers. Using compiled your program AND LAMMPS-wrapper.cpp using the same MPI headers. Using
the stubs for one and the actual MPI library for the other will cause Bad the stubs for one and the actual MPI library for the other will cause Bad
Things to happen. Things to happen.
If you find run-time errors, please pass them along via the LAMMPS Users If you find run-time errors, please pass them along via the LAMMPS Users
mailing list (please CC me as well; address above). Please provide a minimal mailing list (please CC me as well; address above). Please provide a minimal
working example along with the names and versions of the compilers you are working example along with the names and versions of the compilers you are
using. Please make sure the error is repeatable and is in MY code, not yours using. Please make sure the error is repeatable and is in MY code, not yours
(generating a minimal working example will usually ensure this anyway). (generating a minimal working example will usually ensure this anyway).
------------------------------------- -------------------------------------
--IMPLEMENTATION NOTES-- --IMPLEMENTATION NOTES--
The Fortran procedures have the same names as the C procedures, and The Fortran procedures have the same names as the C procedures, and
their purpose is the same, but they may take different arguments. Here are their purpose is the same, but they may take different arguments. Here are
some of the important differences: some of the important differences:
* lammps_open and lammps_open_no_mpi take a string instead of argc and * lammps_open and lammps_open_no_mpi take a string instead of argc and
argv. This is necessary because C and C++ have a very different way argv. This is necessary because C and C++ have a very different way
of treating strings than Fortran. If you want the command line to be of treating strings than Fortran. If you want the command line to be
passed to lammps_open (as it often would be from C/C++), use the passed to lammps_open (as it often would be from C/C++), use the
GET_COMMAND intrinsic to obtain it. GET_COMMAND intrinsic to obtain it.
* All C++ functions that accept char* pointers now accept Fortran-style * All C++ functions that accept char* pointers now accept Fortran-style
strings within this interface instead. strings within this interface instead.
* All of the lammps_extract_[something] functions, which return void* * All of the lammps_extract_[something] functions, which return void*
C-style pointers, have been replaced by generic subroutines that return C-style pointers, have been replaced by generic subroutines that return
Fortran variables (which may be arrays). The first argument houses the Fortran variables (which may be arrays). The first argument houses the
variable/pointer to be returned (pretend it's on the left-hand side); all variable/pointer to be returned (pretend it's on the left-hand side); all
other arguments are identical except as stipulated above. other arguments are identical except as stipulated above.
Note that it is not possible to declare generic functions that are selected Note that it is not possible to declare generic functions that are selected
based solely on the type/kind/rank (TKR) signature of the return value, based solely on the type/kind/rank (TKR) signature of the return value,
only based on the TKR of the arguments. only based on the TKR of the arguments.
* The SHAPE of the first argument to lammps_extract_[something] is checked * The SHAPE of the first argument to lammps_extract_[something] is checked
against the "shape" of the C array (e.g., double vs. double* vs. double**). against the "shape" of the C array (e.g., double vs. double* vs. double**).
Calling a subroutine with arguments of inappropriate rank will result in an Calling a subroutine with arguments of inappropriate rank will result in an
error at run time. error at run time.
* The indices i and j in lammps_extract_fix are used the same way they * The indices i and j in lammps_extract_fix are used the same way they
are in f_ID[i][j] references in LAMMPS (i.e., starting from 1). This is are in f_ID[i][j] references in LAMMPS (i.e., starting from 1). This is
different than the way library.cpp uses these numbers, but is more different than the way library.cpp uses these numbers, but is more
consistent with the way arrays are accessed in LAMMPS and in Fortran. consistent with the way arrays are accessed in LAMMPS and in Fortran.
* The char* pointer normally returned by lammps_command is thrown away * The char* pointer normally returned by lammps_command is thrown away
in this version; note also that lammps_command is now a subroutine in this version; note also that lammps_command is now a subroutine
instead of a function. instead of a function.
* The pointer to LAMMPS itself is of type(lammps_instance), which is itself * The pointer to LAMMPS itself is of type(lammps_instance), which is itself
a synonym for type(C_ptr), part of ISO_C_BINDING. Type (C_ptr) is a synonym for type(C_ptr), part of ISO_C_BINDING. Type (C_ptr) is
C's void* data type. C's void* data type.
* This module will almost certainly generate a compile-time warning, * This module will almost certainly generate a compile-time warning,
such as, such as,
subroutine lammps_open_wrapper (argc, argv, communicator, ptr) & subroutine lammps_open_wrapper (argc, argv, communicator, ptr) &
Variable 'communicator' at (1) is a parameter to the BIND(C) Variable 'communicator' at (1) is a parameter to the BIND(C)
procedure 'lammps_open_wrapper' but may not be C interoperable procedure 'lammps_open_wrapper' but may not be C interoperable
This happens because lammps_open_wrapper actually takes a Fortran This happens because lammps_open_wrapper actually takes a Fortran
INTEGER argument, whose type is defined by the MPI library itself. The INTEGER argument, whose type is defined by the MPI library itself. The
Fortran integer is converted to a C integer by the MPI library (if such Fortran integer is converted to a C integer by the MPI library (if such
conversion is actually necessary). conversion is actually necessary).
* lammps_extract_global returns COPIES of the (scalar) data, as does the * lammps_extract_global returns COPIES of the (scalar) data, as does the
C version. C version.
* lammps_extract_atom, lammps_extract_compute, and lammps_extract_fix * lammps_extract_atom, lammps_extract_compute, and lammps_extract_fix
have a first argument that will be associated with ACTUAL LAMMPS DATA. have a first argument that will be associated with ACTUAL LAMMPS DATA.
This means the first argument must be: This means the first argument must be:
* The right rank (via the DIMENSION modifier) * The right rank (via the DIMENSION modifier)
* A C-interoperable POINTER type (i.e., INTEGER (C_int) or * A C-interoperable POINTER type (i.e., INTEGER (C_int) or
REAL (C_double)). REAL (C_double)).
* lammps_extract_variable returns COPIES of the data, as the C library * lammps_extract_variable returns COPIES of the data, as the C library
interface does. There is no need to deallocate using lammps_free. interface does. There is no need to deallocate using lammps_free.
* The 'data' argument to lammps_gather_atoms and lammps_scatter atoms must * The 'data' argument to lammps_gather_atoms and lammps_scatter atoms must
be ALLOCATABLE. It should be of type INTEGER or DOUBLE PRECISION. It be ALLOCATABLE. It should be of type INTEGER or DOUBLE PRECISION. It
does NOT need to be C inter-operable (and indeed should not be). does NOT need to be C inter-operable (and indeed should not be).
* The 'count' argument of lammps_scatter_atoms is unnecessary; the shape of * The 'count' argument of lammps_scatter_atoms is unnecessary; the shape of
the array determines the number of elements LAMMPS will read. the array determines the number of elements LAMMPS will read.