4.10. Notes for updating code written for older LAMMPS versions

This section documents how C++ source files that are available outside of the LAMMPS source distribution (e.g. in external USER packages or as source files provided as a supplement to a publication) that are written for an older version of LAMMPS and thus need to be updated to be compatible with the current version of LAMMPS. Due to the active development of LAMMPS it is likely to always be incomplete. Please contact developers@lammps.org in case you run across an issue that is not (yet) listed here. Please also review the latest information about the LAMMPS programming style conventions, especially if you are considering to submit the updated version for inclusion into the LAMMPS distribution.

Available topics in mostly chronological order:


4.10.1. Setting flags in the constructor

As LAMMPS gains additional functionality, new flags may need to be set in the constructor or a class to signal compatibility with such features. Most of the time the defaults are chosen conservatively, but sometimes the conservative choice is the uncommon choice, and then those settings need to be made when updating code.

Pair styles:

  • manybody_flag: set to 1 if your pair style is not pair-wise additive

  • restartinfo: set to 0 if your pair style does not store data in restart files

4.10.2. Rename of pack/unpack_comm() to pack/unpack_forward_comm()

Changed in version 8Aug2014.

In this change set, the functions to pack/unpack data into communication buffers for forward communications were renamed from pack_comm() and unpack_comm() to pack_forward_comm() and unpack_forward_comm(), respectively. Also the meaning of the return value of these functions was changed: rather than returning the number of items per atom stored in the buffer, now the total number of items added (or unpacked) needs to be returned. Here is an example from the PairEAM class. Of course the member function declaration in corresponding header file needs to be updated accordingly.

Old:

int PairEAM::pack_comm(int n, int *list, double *buf, int pbc_flag, int *pbc)
{
  int m = 0;
  for (int i = 0; i < n; i++) {
    int j = list[i];
    buf[m++] = fp[j];
  }
  return 1;
}

New:

int PairEAM::pack_forward_comm(int n, int *list, double *buf, int pbc_flag, int *pbc)
{
  int m = 0;
  for (int i = 0; i < n; i++) {
    int j = list[i];
    buf[m++] = fp[j];
  }
  return m;
}

Note

Because the various “pack” and “unpack” functions are defined in the respective base classes as dummy functions doing nothing, and because of the the name mismatch the custom versions in the derived class will no longer be called, there will be no compilation error when this change is not applied. Only calculations will suddenly produce incorrect results because the required forward communication calls will cease to function correctly.

4.10.3. Use ev_init() to initialize variables derived from eflag and vflag

Changed in version 29Mar2019.

There are several variables that need to be initialized based on the values of the “eflag” and “vflag” variables and since sometimes there are new bits added and new variables need to be set to 1 or 0. To make this consistent across all styles, there is now an inline function ev_init(eflag, vflag) that makes those settings consistently and calls either ev_setup() or ev_unset(). Example from a pair style:

Old:

if (eflag || vflag) ev_setup(eflag, vflag);
else evflag = vflag_fdotr = eflag_global = eflag_atom = 0;

New:

ev_init(eflag, vflag);

Not applying this change will not cause a compilation error, but can lead to inconsistent behavior and incorrect tallying of energy or virial.

4.10.4. Use utils::count_words() functions instead of atom->count_words()

Changed in version 2Jun2020.

The “count_words()” functions for parsing text have been moved from the Atom class to the utils namespace. The “count_words()” function in “utils” uses the Tokenizer class internally to split a line into words and count them, thus it will not modify the argument string as the function in the Atoms class did and thus had a variant using a copy buffer. Unlike the old version, the new version does not remove comments. For that you can use the utils::trim_comment() function as shown in the example below.

Old:

nwords = atom->count_words(line);
int nwords = atom->count_words(buf);

New:

nwords = utils::count_words(line);
int nwords = utils::count_words(utils::trim_comment(buf));

4.10.5. Use utils::numeric() functions instead of force->numeric()

Changed in version 18Sep2020.

The “numeric()” conversion functions (including “inumeric()”, “bnumeric()”, and “tnumeric()”) have been moved from the Force class to the utils namespace. Also they take an additional argument that selects whether the Error::all() or Error::one() function should be called in case of an error. The former should be used when all MPI processes call the conversion function and the latter must be used when they are called from only one or a subset of the MPI processes.

Old:

val = force->numeric(FLERR, arg[1]);
num = force->inumeric(FLERR, arg[2]);

New:

val = utils::numeric(FLERR, true, arg[1], lmp);
num = utils::inumeric(FLERR, false, arg[2], lmp);

4.10.6. Use utils::open_potential() function to open potential files

Changed in version 18Sep2020.

The utils::open_potential() function must be used to replace calls to force->open_potential() and should be used to replace fopen() for opening potential files for reading. The custom function does three additional steps compared to fopen(): 1) it will try to parse the UNITS: and DATE: metadata and will stop with an error on a units mismatch and will print the date info, if present, in the log file; 2) for pair styles that support it, it will set up possible automatic unit conversions based on the embedded unit information and LAMMPS’ current units setting; 3) it will not only try to open a potential file at the given path, but will also search in the folders listed in the LAMMPS_POTENTIALS environment variable. This allows potential files to reside in a common location instead of having to copy them around for simulations.

Old:

fp = force->open_potential(filename);
fp = fopen(filename, "r");

New:

fp = utils::open_potential(filename, lmp);

4.10.7. Use symbolic Atom and AtomVec constants instead of numerical values

Changed in version 18Sep2020.

Properties in LAMMPS that were represented by integer values (0, 1, 2, 3) to indicate settings in the Atom and AtomVec classes (or classes derived from it) (and its derived classes) have been converted to use scoped enumerators instead.

Symbolic Constant

Value

Symbolic Constant

Value

Symbolic Constant

Value

Atom::GROW

0

Atom::ATOMIC

0

Atom::MAP_NONE

0

Atom::RESTART

1

Atom::MOLECULAR

1

Atom::MAP_ARRAY

1

Atom::BORDER

2

Atom::TEMPLATE

2

Atom::MAP_HASH

2

AtomVec::PER_ATOM

0

AtomVec::PER_TYPE

1

Atom::MAP_YES

3

Old:

molecular = 0;
mass_type = 1;
if (atom->molecular == 2)
if (atom->map_style == 2)
atom->add_callback(0);
atom->delete_callback(id,1);

New:

molecular = Atom::ATOMIC;
mass_type = AtomVec::PER_TYPE;
if (atom->molecular == Atom::TEMPLATE)
if (atom->map_style == Atom::MAP_HASH)
atom->add_callback(Atom::GROW);
atom->delete_callback(id,Atom::RESTART);

4.10.8. Simplify customized error messages

Changed in version 14May2021.

Aided by features of the bundled {fmt} library, error messages now can have a variable number of arguments and the string will be interpreted as a {fmt} style format string so that error messages can be easily customized without having to use temporary buffers and sprintf(). Example:

Old:

if (fptr == NULL) {
  char str[128];
  sprintf(str,"Cannot open AEAM potential file %s",filename);
  error->one(FLERR,str);
}

New:

if (fptr == nullptr)
  error->one(FLERR, "Cannot open AEAM potential file {}: {}", filename, utils::getsyserror());

4.10.9. Use of “override” instead of “virtual”

Changed in version 17Feb2022.

Since LAMMPS requires C++17, we switched to use the “override” keyword instead of “virtual” to indicate polymorphism in derived classes. This allows the C++ compiler to better detect inconsistencies when an override is intended or not. Please note that “override” has to be added to all polymorph functions in derived classes and “virtual” only to the function in the base class (or the destructor). Here is an example from the FixWallReflect class:

Old:

FixWallReflect(class LAMMPS *, int, char **);
virtual ~FixWallReflect();
int setmask();
void init();
void post_integrate();

New:

FixWallReflect(class LAMMPS *, int, char **);
~FixWallReflect() override;
int setmask() override;
void init() override;
void post_integrate() override;

This change set will neither cause a compilation failure, nor will it change functionality, but if you plan to submit the updated code for inclusion into the LAMMPS distribution, it will be requested for achieve a consistent programming style.

4.10.10. Simplified function names for forward and reverse communication

Changed in version 24Mar2022.

Rather than using the function name to distinguish between the different forward and reverse communication functions for styles, LAMMPS now uses the type of the “this” pointer argument.

Old:

comm->forward_comm_pair(this);
comm->forward_comm_fix(this);
comm->forward_comm_compute(this);
comm->forward_comm_dump(this);
comm->reverse_comm_pair(this);
comm->reverse_comm_fix(this);
comm->reverse_comm_compute(this);
comm->reverse_comm_dump(this);

New:

comm->forward_comm(this);
comm->reverse_comm(this);

This change is required or else the code will not compile.

4.10.11. Simplified and more compact neighbor list requests

Changed in version 24Mar2022.

This change set reduces the amount of code required to request a neighbor list. It enforces consistency and no longer requires to change internal data of the request. More information on neighbor list requests can be found here. Example from the ComputeRDF class:

Old:

int irequest = neighbor->request(this,instance_me);
neighbor->requests[irequest]->pair = 0;
neighbor->requests[irequest]->compute = 1;
neighbor->requests[irequest]->occasional = 1;
if (cutflag) {
  neighbor->requests[irequest]->cut = 1;
  neighbor->requests[irequest]->cutoff = mycutneigh;
}

New:

auto req = neighbor->add_request(this, NeighConst::REQ_OCCASIONAL);
if (cutflag) req->set_cutoff(mycutneigh);

Public access to the NeighRequest class data members has been removed so this update is required to avoid compilation failure.

4.10.12. Split of fix STORE into fix STORE/GLOBAL and fix STORE/PERATOM

Changed in version 15Sep2022.

This change splits the GLOBAL and PERATOM modes of fix STORE into two separate fixes STORE/GLOBAL and STORE/PERATOM. There was very little shared code between the two fix STORE modes and the two different code paths had to be prefixed with if statements. Furthermore, some flags were used differently in the two modes leading to confusion. Splitting the code into two fix styles, makes it more easily maintainable. Since these are internal fixes, there is no user visible change.

Old:

#include "fix_store.h"

FixStore *fix = dynamic_cast<FixStore *>(
   modify->add_fix(fmt::format("{} {} STORE peratom 1 13",id_pole,group->names[0]));

FixStore *fix = dynamic_cast<FixStore *>(modify->get_fix_by_id(id_pole));

New:

#include "fix_store_peratom.h"

FixStorePeratom *fix = dynamic_cast<FixStorePeratom *>(
   modify->add_fix(fmt::format("{} {} STORE/PERATOM 1 13",id_pole,group->names[0]));

FixStorePeratom *fix = dynamic_cast<FixStorePeratom *>(modify->get_fix_by_id(id_pole));

Old:

#include "fix_store.h"

FixStore *fix = dynamic_cast<FixStore *>(
   modify->add_fix(fmt::format("{} {} STORE global 1 1",id_fix,group->names[igroup]));

FixStore *fix = dynamic_cast<FixStore *>(modify->get_fix_by_id(id_fix));

New:

#include "fix_store_global.h"

FixStoreGlobal *fix = dynamic_cast<FixStoreGlobal *>(
   modify->add_fix(fmt::format("{} {} STORE/GLOBAL 1 1",id_fix,group->names[igroup]));

FixStoreGlobal *fix = dynamic_cast<FixStoreGlobal *>(modify->get_fix_by_id(id_fix));

This change is required or else the code will not compile.

4.10.13. Rename of fix STORE/PERATOM to fix STORE/ATOM and change of arguments

Changed in version 28Mar2023.

The available functionality of the internal fix to store per-atom properties was expanded to enable storing data with ghost atoms and to support binary restart files. With those changes, the fix was renamed to fix STORE/ATOM and the number and order of (required) arguments has changed.

Old syntax: ID group-ID STORE/PERATOM rflag n1 n2 [n3]

  • rflag = 0/1, no/yes store per-atom values in restart file

  • \(n1 = 1, n2 = 1, \mathrm{no}\;n3 \to\) per-atom vector, single value per atom

  • \(n1 = 1, n2 > 1, \mathrm{no}\;n3 \to\) per-atom array, n2 values per atom

  • \(n1 = 1, n2 > 0, n3 > 0 \to\) per-atom tensor, n2 x n3 values per atom

New syntax: ID group-ID STORE/ATOM n1 n2 gflag rflag

  • \(n1 = 1, n2 = 0 \to\) per-atom vector, single value per atom

  • \(n1 > 1, n2 = 0 \to\) per-atom array, n1 values per atom

  • \(n1 > 0, n2 > 0 \to\) per-atom tensor, n1 x n2 values per atom

  • gflag = 0/1, no/yes communicate per-atom values with ghost atoms

  • rflag = 0/1, no/yes store per-atom values in restart file

Since this is an internal fix, there is no user visible change.

4.10.14. Use Output::get_dump_by_id() instead of Output::find_dump()

Changed in version 15Sep2022.

The accessor function to individual dump style instances has been changed from Output::find_dump() returning the index of the dump instance in the list of dumps to Output::get_dump_by_id() returning a pointer to the dump directly. Example:

Old:

int idump = output->find_dump(arg[iarg+1]);
if (idump < 0)
  error->all(FLERR,"Dump ID in hyper command does not exist");
memory->grow(dumplist,ndump+1,"hyper:dumplist");
dumplist[ndump++] = idump;

[...]

if (dumpflag)
  for (int idump = 0; idump < ndump; idump++)
    output->dump[dumplist[idump]]->write();

New:

auto idump = output->get_dump_by_id(arg[iarg+1]);
if (!idump) error->all(FLERR,"Dump ID {} in hyper command does not exist", arg[iarg+1]);
dumplist.emplace_back(idump);

[...]

if (dumpflag) for (auto idump : dumplist) idump->write();

This change is required or else the code will not compile.

4.10.15. Refactored grid communication using Grid3d/Grid2d classes instead of GridComm

Changed in version 22Dec2022.

The GridComm class was for creating and communicating distributed grids was replaced by the Grid3d class with added functionality. A Grid2d class was also added for additional flexibility.

The new functionality and commands using the two grid classes are discussed on the following documentation pages:

If you have custom LAMMPS code, which uses the GridComm class, here are some notes on how to adapt it for using the Grid3d class.

  1. The constructor has changed to allow the Grid3d / Grid2d classes to partition the global grid across processors, both for owned and ghost grid cells. Previously any class which called GridComm performed the partitioning itself and that information was passed in the GridComm::GridComm() constructor. There are several “set” functions which can be called to alter how Grid3d / Grid2d perform the partitioning. They should be sufficient for most use cases of the grid classes.

  2. The partitioning is triggered by the setup_grid() method.

  3. The setup() method of the GridComm class has been replaced by the setup_comm() method in the new grid classes. The syntax for the forward_comm() and reverse_comm() methods is slightly altered as is the syntax of the associated pack/unpack callback methods. But the functionality of these operations is the same as before.

  4. The new Grid3d / Grid2d classes have additional functionality for dynamic load-balancing of grids and their associated data across processors. This did not exist in the GridComm class.

This and more is explained in detail on the Use of distributed grids within style classes page. The following LAMMPS source files can be used as illustrative examples for how the new grid classes are used by computes, fixes, and various KSpace solvers which use distributed FFT grids:

  • src/fix_ave_grid.cpp

  • src/compute_property_grid.cpp

  • src/EXTRA-FIX/fix_ttm_grid.cpp

  • src/KSPACE/pppm.cpp

This change is required or else the code will not compile.

4.10.16. FLERR as first argument to minimum image functions in Domain class

Changed in version 12Jun2025.

The Domain::minimum_image() and Domain::minimum_image_big() functions were changed to take the FLERR macros as first argument. This way the error message indicates where the function was called instead of pointing to the implementation of the function. Example:

Old:

double delx1 = x[i1][0] - x[i2][0];
double dely1 = x[i1][1] - x[i2][1];
double delz1 = x[i1][2] - x[i2][2];
domain->minimum_image(delx1, dely1, delz1);
double r1 = sqrt(delx1 * delx1 + dely1 * dely1 + delz1 * delz1);

double delx2 = x[i3][0] - x[i2][0];
double dely2 = x[i3][1] - x[i2][1];
double delz2 = x[i3][2] - x[i2][2];
domain->minimum_image_big(delx2, dely2, delz2);
double r2 = sqrt(delx2 * delx2 + dely2 * dely2 + delz2 * delz2);

New:

double delx1 = x[i1][0] - x[i2][0];
double dely1 = x[i1][1] - x[i2][1];
double delz1 = x[i1][2] - x[i2][2];
domain->minimum_image(FLERR, delx1, dely1, delz1);
double r1 = sqrt(delx1 * delx1 + dely1 * dely1 + delz1 * delz1);

double delx2 = x[i3][0] - x[i2][0];
double dely2 = x[i3][1] - x[i2][1];
double delz2 = x[i3][2] - x[i2][2];
domain->minimum_image_big(FLERR, delx2, dely2, delz2);
double r2 = sqrt(delx2 * delx2 + dely2 * dely2 + delz2 * delz2);

This change is required or else the code will not compile.

4.10.17. Use utils::logmesg() instead of error->warning()

Changed in version 22Jul2025.

The Error::message() method has been removed since its functionality has been superseded by the utils::logmesg() function.

Old:

 if (comm->me == 0) {
   error->message(FLERR, "INFO: About to read data file: {}", filename);
}

New:

if (comm->me == 0) utils::logmesg(lmp, "INFO: About to read data file: {}\n", filename);

This change is required or else the code will not compile.

4.10.18. Explicit interpretation for custom neighbor list cutoffs

Changed in version 30Sep2026.

The default neighbor list is built with a cutoff per pair of atom types, so a request for a custom cutoff is ambiguous on its own: the same number can mean “the largest cutoff used by any type pair” or “this cutoff for every type pair”. Assuming the former where the latter was meant silently truncates the list for the type pairs that use a shorter pair style cutoff.

NeighRequest::set_cutoff() has therefore been replaced by two functions that each state the intended interpretation, and must be called instead:

  • set_cutoff_max(cutoff) – the maximum across atom types, individual type pairs may use a shorter cutoff. This is the typical case for pair styles.

  • set_cutoff_fixed(cutoff) – applies uniformly to every pair of atom types. This is the typical case for a fix or compute analyzing a fixed range, e.g. an RDF.

Old:

auto req = neighbor->add_request(this, NeighConst::REQ_OCCASIONAL);
if (cutflag) req->set_cutoff(mycutneigh);

New:

auto req = neighbor->add_request(this, NeighConst::REQ_OCCASIONAL);
if (cutflag) req->set_cutoff_fixed(mycutneigh);

This change is required or else the code will not compile.

4.10.19. Use Modify::has_fixes() instead of the Modify::n_* counters

Changed in version 13Nov2026.

The Modify class used to have a public integer counter for every stage of a timestep or minimization (n_pre_force, n_post_force_any, n_end_of_step, n_min_post_force, and so on) with the number of fixes that are invoked at that stage. Integrators and some commands and fixes test these counters to skip the call into the Modify class when no fix needs it. The counters have been replaced by the function Modify::has_fixes(). It takes a combination of the stage constants from FixConst (the same constants that a fix returns from its setmask() method) and returns whether any fix is invoked at any of these stages. The combined stages that had their own counters are available as FixConst::POST_FORCE_ANY and FixConst::POST_FORCE_RESPA_ANY (which include the internal fixes maintaining dynamic groups), and the contributions to the global and per-atom energy as FixConst::ENERGY_GLOBAL and FixConst::ENERGY_ATOM. As with the counters, the result is only valid after the fixes have been initialized for a run or minimization.

Old:

int n_pre_force = modify->n_pre_force;
int n_post_force_any = modify->n_post_force_any;

[...]

if (n_pre_force) modify->pre_force(vflag);
if (n_post_force_any) modify->post_force(vflag);

New:

if (modify->has_fixes(FixConst::PRE_FORCE)) modify->pre_force(vflag);
if (modify->has_fixes(FixConst::POST_FORCE_ANY)) modify->post_force(vflag);

This change is required or else the code will not compile.

4.10.20. Access fixes and computes through the Modify accessor functions

Changed in version 13Nov2026.

The lists of fixes and computes in the Modify class are now stored in std::vector containers and fixes are invoked by testing their mask rather than through lists of indices. The public members fix, nfix, fmask, compute, and ncompute that gave direct access to the lists have been removed, as have the functions Modify::find_fix() and Modify::find_compute() that returned an index into them and the overloads Modify::delete_fix(int) and Modify::delete_compute(int) that took such an index. Use Modify::get_fix_list() and Modify::get_compute_list() to loop over all fixes or computes (they now return a reference to the list instead of a copy, so no fix or compute may be added or deleted while looping over it), Modify::get_fix_by_id() and Modify::get_compute_by_id() to look up an instance by its ID, Modify::get_fix_mask(), Modify::set_fix_mask(), and Modify::clear_fix_mask() to query or change the stages at which a fix is invoked, and delete fixes and computes by ID or by pointer. Code that needs a position in the list, e.g. to check the order of fixes, can loop over the list with an index, but must not store that index, since it changes when fixes are deleted. The remaining public data members of the Modify class are now protected, too: use Modify::has_restart_pbc() instead of restart_pbc_any and Modify::get_nfix_restart_peratom() instead of nfix_restart_peratom.

Old:

for (int i = 0; i < modify->nfix; i++)
  if (modify->fix[i]->box_change) box_change = 1;

int ifix = modify->find_fix(id_fix);
if (ifix < 0) error->all(FLERR, "Fix ID {} does not exist", id_fix);
Fix *myfix = modify->fix[ifix];

[...]

modify->delete_fix(ifix);

New:

for (const auto &fix : modify->get_fix_list())
  if (fix->box_change) box_change = 1;

Fix *myfix = modify->get_fix_by_id(id_fix);
if (!myfix) error->all(FLERR, "Fix ID {} does not exist", id_fix);

[...]

modify->delete_fix(myfix);

This change is required or else the code will not compile.

4.10.21. Register callbacks for per-atom arrays with a pointer to the fix

Changed in version 13Nov2026.

A fix that manages per-atom arrays registers callbacks with the Atom class, so that its arrays are grown, copied, communicated, and stored in restart files together with the arrays of the atom style. The Atom class used to record the position of the fix in the list of fixes, which it had to guess when the fix constructor registered the callback and to update whenever a fix was deleted. The callback lists are now lists of pointers to the fixes. Thus Atom::add_callback() and Atom::delete_callback() take a pointer to the fix as their first argument (this when called from the constructor and destructor of the fix) instead of no argument or the fix ID, respectively. The counters nextra_grow, nextra_restart, and nextra_border and their _max variants have been removed, and the lists extra_grow, extra_restart, and extra_border are now std::vector containers with the fixes in the order of the list of fixes of the Modify class. A fix whose callbacks are still registered when it is deleted (e.g. because its constructor failed) is removed from the lists by the destructor of the Fix base class.

Old:

atom->add_callback(Atom::GROW);
atom->delete_callback(id, Atom::GROW);

for (int iextra = 0; iextra < atom->nextra_grow; iextra++)
  modify->fix[atom->extra_grow[iextra]]->grow_arrays(nmax);

New:

atom->add_callback(this, Atom::GROW);
atom->delete_callback(this, Atom::GROW);

for (auto *ifix : atom->extra_grow) ifix->grow_arrays(nmax);

This change is required or else the code will not compile.