Writing new pair (and other) styles for LAMMPS

Dear current, past, and future LAMMPS developers,

I just completed a pull request with a detailed description of the contents of a (simple) new pair style to be added to LAMMPS and some additional related discussions: Add detailed developer information about adding pair styles and use new born/gauss style as example by akohlmey · Pull Request #3667 · lammps/lammps · GitHub

If any of you have written new or modified pair (or other) styles for LAMMPS (regardless of whether those were contributed to LAMMPS or not), I would very much appreciate some feedback from you. In particular, I am interested in the following:

  • Do you find any mistakes or oversights? Since this is going to be particularly important to people with limited experience in LAMMPS or programming, it is crucial that the explanations are complete and correct. However, as a person with lots of experience in both, it is very difficult for me to put myself into the position of such a person.
  • Do you see any questions that you came across that are unanswered? Are the provided explanations lucid and accessible? Is there anything that you wondered about that is not mentioned.
  • Do you have suggestions for future documents of a similar kind? Which styles or features in LAMMPS should be discussed next.

You can either check out or download the branch from GitHub directly and translate it by typing “make html” or “make pdf” in the doc folder, or you can download pre-translated files from our continuous integration test server at (the link to the latest change will of course change when new updates are made to that pull request, but this should be quite close to a final version): dev » pull_requests » build_docs #7431 [Jenkins]

I am particularly interested in feedback to the files, Developer_write.rst, and Developer_write_pair.rst (or the corresponding .html files in the translated html version).

Feedback can be added to this discussion topic or - where applicable - as comments on the pull request or feature request issue on GitHub.

Thanks in advance,


Hi Axel, I thought the guides were quite clear and would have been very helpful back when I was learning LAMMPS. Few comments:

  1. Should the pages on modifying/extending pair/fix styles in Section 14 link to these new pages? Or are the new pages supposed to replace the old pages? The distinction between Secs. 14 and 15 isn’t clear to me.
  2. Regarding the stored atom positions in the fix example, a discussion of when/how one might alternatively initialize a fix store/atom or property/atom to store data might help. Maybe a link to section 15.8.3? Similarly, a link to 15.8.2 might be helpful for the discussion of neighbor lists for the many body potential.
  3. I think there are now 3 bits reserved in the neighbor list, two for special bonds and one for history (which arguably is unnecessary)
  4. With the description of ev_tally, would it be appropriate to add a brief note about ev_tally_xyz?

I also spotted some minor typos.

I see two differences:
First, most of section 14 used to be all there was in the old days. People were expected to be experienced programmers able to learn what they need from reading the source code (this was a significant motivation for trying to keep the source code - at least the parts in the src/ folder, i.e. not in packages, readable and well commented. Section 15 is a “gift of the pandemic”. Without the extra time at hand, it would have happened. After adding more and more content for developers, we restructured the manual altogether and eliminated a lot of redundancies and inconsistencies. For example, there used to be three places with documentation about the library interface and the python module, but neither was complete, correct, or in sync with the code. We have consolidated those.

Second, I see a significant difference in the “perspective”. Section 14 is “top down”. If you want to add code to LAMMPS, it will tell you what you have to do without going into details too much.
Section 15 is “bottom up” in comparison, i.e. it starts with looking at individual functions and explains what they do and then how they fit into the bigger context.

Making links is definitely a good idea. In the past, my approach has always been to try and add content first and wherever it feels natural to be added and complete it and then review it and see if a different location would be better or if it can be shortened or something else needs to be shortened. At the moment we are still in a phase where there is plenty of room to add stuff in many places. Making it more compact and to the point and eliminating undesired redundancies is the step after that.

Please note, that the fix example is an old document that was written by Kyrill Lykov, IIRC, a long time ago. I am not certain when it was revised the last time and checked for accuracy.
The next step I am planning to do in this regard would be a bit about writing per-chunk computes since I just refactored them in Refactor per-chunk computes to use ComputeChunk class with shared functionality by akohlmey · Pull Request #3691 · lammps/lammps · GitHub

I need to check, but I have not looked at this in a long time. Most of what I wrote was from memory and rather quickly.

Absolutely, there are a more tally functions (including some v_tally variants).
… and there are also some unusual uses. I have once written a version of pair style lj/cut that uses a full neighbor list (for multi-threading with many threads). There I am using

        if (evflag) ev_tally(i, i, nlocal, 0, 0.5*evdwl, 0.0, 0.5*fpair, delx, dely, delz);

While the (regular) half neighbor list version uses:

        if (evflag) ev_tally(i, j, nlocal, newton_pair, evdwl, 0.0, fpair, delx, dely, delz);

Please point them out, either as comments on the pull request, or as pull request to the pull request or attach or email me a patch. Also any other proposed changes.

In general, I can only encourage people to write down such kind of “develper tutorial” documents. I found it to be a very good learning experience to improve my level of understand on some details that I didn’t think much about in the past.

This is true, but what I wrote is (technically speaking) also true: the upper two bits are used for encoding the special status. The sbmask() macro still does a bitshift by 30 bits, so the history bit is ignored here. Only NEIGHMASK is different from what it used to be, since it now has to also mask out the history bit, but it does mask out the special bits like the text claims.