LAMMPS / Fortran coupling

I was corresponding earlier in the week with someone regarding coupling LAMMPS with Fortran-based software, and it alerted me to a few things in need of maintenance in examples/COUPLE/fortran2 (such as the fact that all the e-mail addresses given in both the README and the source code that are supposed to point to me no longer get e-mail to me).

However, before I spend time doing that, I thought I’d ask: (1) should I keep maintaining that interface, as it appears that the goal is to maintain the one in “fortran” instead of “examples/COUPLE/fortran2,” and (2) would you mind if I updated “fortran/lammps.f90” to include, more or less, the functions in library.h/library.cpp?

If yes to (2), I will try to follow the coding conventions that are present there (e.g., capitalizations, interface), and there may be some snags with some of the ones that don’t have implementations in examples/COUPLE/fortran2 yet, but I can give it a whack if you’d like. If there are any constraints I should observe and/or preferred methods of sending in changes (e.g., via git, by e-mail), let me know that as well. If I should keep my hands off, that’s fine too!

@karlh I didn’t see that you have posted here also before I finished my reply to your post to the mailing list. I am just adding a link to here. Re: [lammps-users] LAMMPS / Fortran coupling | LAMMPS

We can - of course - continue the discussion here or offline.

Yes, my first post got sent to moderation because the e-mail that I registered to use with the mailing list is down, and I see the mailing list is going away soon as well, so I made this post.

There isn’t much that I see in the old version that needs immediate attention; the only one I saw that hasn’t been fixed already was line 1295, where “lammps_gather_atoms” should be “lammps_scatter_atoms” inside the error message string. A similar typo has already been fixed on line 1314. The other fixes would be the e-mail address on line 15 of LAMMPS.F90, LAMMPS-wrapper.cpp, LAMMPS-wrapper.h, and README (line 16 of the README should be removed). There is also going to be an issue with lammps_open due to the changes to library.cpp, which could be solved by adding -DLAMMPS_LIB_MPI to CXX_FLAGS in the makefile.

The main thing for future development is missing interfaces to the new functions in library.cpp. If you were planning to rewrite it anyway, though, then I should work on that instead of the old one.

The functions I wrote assume the MPI module (Fortran 90/95/2003 bindings) is being used, though I think the interface is largely the same as with “include ‘mpif.h’” (Fortran 77 bindings). I have not looked much at the MPI_F08 module, though I can certainly look into that before doing anything further.

The part about not having an auxiliary library is hard unless you’re willing to add some “helper” functions to library.cpp. For example, the “lammps_error_all” in LAMMPS-wrapper.cpp could easily be added to library.cpp; “lammps_get_ntypes” could also be in library.cpp, as lammps_get_natoms is already. The tricky part would be dealing with extract_fix, extract_compute, etc. (and I see some of the new commands deal with neighbor lists, which could be interesting), as those return actual C++ data that Fortran must know the size and shape of at the time they are bound. The Python interface may have some clues here, so I might look through that if/when the time comes.

I will wait for the next ‘stable’ version and base any revisions off of that.

Please check out this commit: More fixes and small changes for the stable release by akohlmey · Pull Request #3309 · lammps/lammps · GitHub

This is already set, but just in CPPFLAGS. I just checked. Compiling the wrapper and building the “simple” example works and the input runs in serial and parallel.

We have already done so. For example, there is a lammps_open_fortran().

When I look through the list of functions, then lammps_error_all() seems to be the only one for which no equivalent exists.

The situation is that I currently don’t know how much time I can spend on this and when. One additional thing - but of lower importance - is that along with the fortran module, there are also unit tests that check the correctness and functionality of the implementation (so that any breakage gets to our attention quicker). lammps/unittest/fortran at develop · lammps/lammps · GitHub
This adds the additional challenge to do a “reverse wrapper” in addition so the googletest library can be used.

Please don’t spend too much time on this. It is just something that is on my mind. There will be somebody asking for it, but things in the Fortran world are moving slow, so I don’t know when this will become a serious problem with multiple people requesting it. So far, backward compatibility has been good enough. But I am concerned that some future fortran compiler may drop support for some currently expected features.

I think you got the pull request I put out—let me know if there is anything else I need to do. This is the first time I have used github to make a change to LAMMPS, so I’m not 100% certain I did it correctly.

It was perfect.

I messed around with the MPI_F08 module a bit yesterday, and I figured out how to make the Fortran interface largely agnostic to whether the user invokes the MPI_F08 vs. MPI modules (I haven’t tested it with mpif.h, but its use is not recommended anyway). However, I thought I should run it by you first, as it might slightly complicate the process.

Basically, the only way that I’ve been able to track down for sending communicators from Fortran to C is using MPI_Comm_f2c from C, which is in use as part of lammps_open_fortran. The MPI_F08 module uses TYPE (MPI_comm) for its communicators, but the type is just used for the strict type-checking required by the standard and there is always a comm%MPI_VAL element that is the “old style” INTEGER communicator ID that the MPI module would use.

The solution is to import only MPI_Comm from MPI_F08, then write two overloaded constructors. The first would be the one that’s already there, which is used if “use MPI” was invoked in the calling routine. The second would use “TYPE(MPI_Comm)” in place of “INTEGER” on the appropriate line, then grab comm%MPI_VAL from it and call the original. It is my impression that the MPI standard requires the integer-style communicators in code that loads MPI to work alongside derived-type-style communicators in code that loads MPI_F08, but I haven’t actually read the standard.

The other idea I had on this was to provide another overloaded constructor that takes the whole command line rather than breaking it into an array first. The difference from the user’s perspective (assuming they’re trying to grab the actual command line the way C and C++ do) would be something like

! Current constructor
CHARACTER (LEN=128), allocatable :: command_args(:)
  CALL GET_COMMAND_ARGUMENT(i,command_args(i))
lmp = LAMMPS(command_args, MPI_COMM_WORLD)

for the way it’s written now, or something like

! Alternative constructor
CHARACTER (LEN=1024) :: command_line
CALL GET_COMMAND(command_line)
lmp = LAMMPS(command_line, MPI_COMM_WORLD)

If they pass a string. The constructor is overloaded, so they would have either option.

The user could, of course, provide arbitrary strings/arrays of strings to these constructors, as in the example.

If it’s easier to see encoded in full, I could make these changes to a branch and do a pull request (now that I know how to do that) and let you look at it that way. I haven’t looked at any of the other functions yet; the constructor seemed like the most important part, and it’s also the most likely part to depend in any particular way on which MPI module is being used.

I submitted a pull request a few minutes ago. Feel free to reject or edit as desired.

Thanks. I will look at it later. Right now I have a bunch of other items to deal with and won’t have the time to look at this with the necessary attention to detail. It will likely take a month or more.