Question about NB-LIB API in GROMACS 2026.1 – mismatch with manual examples

GROMACS version: 2026.1
GROMACS modification: No
I am currently trying to install the NB-LIB (Non-Bonded LIBrary) and use its API to develop custom simulation code. Specifically, I want to implement simulations with the AMBER force field using the GPU-accelerated version of GROMACS.

Following the installation instructions on website ( Installation guide - GROMACS 2026.1 documentation ), I successfully built GROMACS 2026.1 with NB-LIB enabled. However, when I try to follow the example code in the NB-LIB guide ( Guide to Writing MD Programs - GROMACS 2026.1 documentation ), I encounter issues: some header files (*.h) appear to have been modified or restructured, causing mismatches between the sample code and the actual headers in the 2026.1 installation. As a result, the examples do not compile or work as shown.

I am just wondering:
Which GROMACS version’s NB-LIB API most closely matches the current online manual examples?
Or, alternatively, where can I find an updated version of the guide/manual that aligns with the latest code in 2026.1 (or the most recent release)?

Thanks very much for any help.

It looks like this documentation was written for a very first version, in 2020, and never updated. So maybe there is not even a release where the code matches the documentation.

My guess would be that you need to change to gmxcalculatorcpu.h and kerneloptions.h for the includes. I don’t know how up to / out of date the rest of the example documentation is. The doxygen should be up to date though. It would be great if you could provide a list of what we need to update here.

I assume you need more than just simulations with the AMBER force field, as GROMACS already does this. Implementing the AMBER force field through the nblib interface is a lot of work.

I installed GROMACS 2026.1 and enabled nblib during the build. To test whether the nblib library works correctly, I wrote a simple test program based on the official documentation. However, I encountered a compilation error related to a missing internal GROMACS header.

Here is my test code (simplified for demonstration):

#include <nblib/box.h>
#include <nblib/gmxcalculatorcpu.h>
#include <nblib/integrator.h>
#include <nblib/molecules.h>
#include <nblib/nbkerneloptions.h>
#include <nblib/particletype.h>
#include <nblib/simulationstate.h>
#include <nblib/topology.h>

using namespace nblib;

int main() {
// Example ParticleType definition (simplified)
struct WaterO {
ParticleName name = “Ow”;
Mass mass = 15.999;
C6 c6 = 0.0026173456;
C12 c12 = 2.634129e-06;
};

ParticleType Ow(“Ow”, 15.999); // corrected for clarity

ParticleTypeInteractions interactions(CombinationRule::Geometric);
interactions.add(“Ow”, 0.0026173456, 2.634129e-06);

Molecule water(“Water”);
water.addParticle(“O”, Ow);

// … (rest of topology and simulation setup)

NBKernelOptions options;
options.useGpu = true;

// … (coordinates, forces, SimulationState, ForceCalculator, etc.)

return 0;

}

When I try to compile it (using g++ with proper include and library paths), I get the following error:

/include/nblib/gmxcalculatorcpu.h:54:10: fatal error: gromacs/utility/vectypes.h: No such file or directory
54 | #include “gromacs/utility/vectypes.h”
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
compilation terminated.

It seems that the header gmxcalculatorcpu.h (part of nblib) is trying to include an internal GROMACS header that is not found in the installation. This looks like a dependency or installation path issue.

Any help or example would be greatly appreciated.

Thank you very much for your support!

Is the solution to that that you need to enable GMX_INSTALL_LEGACY_API?

Thank you very much. This problem has been solved after enabling the option GMX_INSTALL_LEGACY_API. However, I have encountered another issue: when I try to directly use the function GmxNBForceCalculatorCpu to calculate energy, I get the following error:

cpp

#include <cstdio>
#include "nblib/box.h"
#include "nblib/integrator.h"
#include "nblib/molecules.h"
#include "nblib/particletype.h"
#include "nblib/simulationstate.h"
#include "nblib/topology.h"
#include "nblib/gmxcalculatorcpu.h"
#include "nblib/kerneloptions.h"
#include "nblib/interactions.h"

using namespace nblib;
using namespace std;

struct OWaterAtom
{
    ParticleName         name{"Ow"};
    Mass                 mass{15.999_real};
    C6                   c6{0.0026173456_real};
    C12                  c12{2.634129e-06_real};
};

struct HwAtom
{
    ParticleName         name{"Hw"};
    Mass                 mass{1.00784_real};
    C6                   c6{0.0_real};
    C12                  c12{0.0_real};
};

struct CMethAtom
{
    ParticleName         name{"Cm"};
    Mass                 mass{12.0107_real};
    C6                   c6{0.01317904_real};
    C12                  c12{34.363044e-06_real};
};

struct HcAtom
{
    ParticleName         name{"Hc"};
    Mass                 mass{1.00784_real};
    C6                   c6{8.464e-05_real};
    C12                  c12{15.129e-09_real};
};

std::vector<gmx::RVec> coordinates = {
    { 0.794, 1.439, 0.610 }, { 1.397, 0.673, 1.916 }, { 0.659, 1.080, 0.573 },
    { 1.105, 0.090, 3.431 }, { 1.741, 1.291, 3.432 }, { 1.936, 1.441, 5.873 },
    { 0.960, 2.246, 1.659 }, { 0.382, 3.023, 2.793 }, { 0.053, 4.857, 4.242 },
    { 2.655, 5.057, 2.211 }, { 4.114, 0.737, 0.614 }, { 5.977, 5.104, 5.217 },
};

std::vector<gmx::RVec> velocities = {
    { 0.0055, -0.1400, 0.2127 }, { 0.0930, -0.0160, -0.0086 }, { 0.1678, 0.2476, -0.0660 },
    { 0.1591, -0.0934, -0.0835 }, { -0.0317, 0.0573, 0.1453 }, { 0.0597, 0.0013, -0.0462 },
    { 0.0484, -0.0357, 0.0168 }, { 0.0530, 0.0295, -0.2694 }, { -0.0550, -0.0896, 0.0494 },
    { -0.0799, -0.2534, -0.0079 }, { 0.0436, -0.1557, 0.1849 }, { -0.0214, 0.0446, 0.0758},
};

std::vector<gmx::RVec> forces = {
    { 0.0000, 0.0000, 0.0000 }, { 0.0000, 0.0000, 0.0000 }, { 0.0000, 0.0000, 0.0000 },
    { 0.0000, 0.0000, 0.0000 }, { 0.0000, 0.0000, 0.0000 }, { 0.0000, 0.0000, 0.0000 },
    { 0.0000, 0.0000, 0.0000 }, { 0.0000, 0.0000, 0.0000 }, { 0.0000, 0.0000, 0.0000 },
    { 0.0000, 0.0000, 0.0000 }, { 0.0000, 0.0000, 0.0000 }, { 0.0000, 0.0000, 0.0000 },
};

int main()
{
    OWaterAtom  owAtom;
    HwAtom      hwAtom;
    CMethAtom   cmethAtom;
    HcAtom      hcAtom;

    ParticleType Ow(ParticleTypeName(owAtom.name), owAtom.mass);
    ParticleType Hw(ParticleTypeName(hwAtom.name), hwAtom.mass);
    ParticleType Cm(ParticleTypeName(cmethAtom.name), cmethAtom.mass);
    ParticleType Hc(ParticleTypeName(hcAtom.name), hcAtom.mass);

    ParticleTypesInteractions interactions(CombinationRule::Geometric);

    interactions.add(ParticleTypeName(owAtom.name), owAtom.c6, owAtom.c12);
    interactions.add(ParticleTypeName(hwAtom.name), hwAtom.c6, hwAtom.c12);
    interactions.add(ParticleTypeName(cmethAtom.name), cmethAtom.c6, cmethAtom.c12);
    interactions.add(ParticleTypeName(hcAtom.name), hcAtom.c6, hcAtom.c12);

    interactions.add(ParticleTypeName("Ow"), ParticleTypeName("Cm"), C6{0.42_real}, C12{42e-6_real});

    Molecule water(MoleculeName("Water"));
    Molecule methane(MoleculeName("Methane"));

    water.addParticle(ParticleName("O"), Ow);
    water.addParticle(ParticleName("H1"), Hw);
    water.addParticle(ParticleName("H2"), Hw);

    water.addExclusion(ParticleIdentifier(ParticleName("H1")), ParticleIdentifier(ParticleName("O")));
    water.addExclusion(ParticleIdentifier(ParticleName("H2")), ParticleIdentifier(ParticleName("O")));

    methane.addParticle(ParticleName("C"), Cm);
    methane.addParticle(ParticleName("H1"), Hc);
    methane.addParticle(ParticleName("H2"), Hc);
    methane.addParticle(ParticleName("H3"), Hc);
    methane.addParticle(ParticleName("H4"), Hc);

    methane.addExclusion(ParticleIdentifier(ParticleName("H1")), ParticleIdentifier(ParticleName("C")));
    methane.addExclusion(ParticleIdentifier(ParticleName("H2")), ParticleIdentifier(ParticleName("C")));
    methane.addExclusion(ParticleIdentifier(ParticleName("H3")), ParticleIdentifier(ParticleName("C")));
    methane.addExclusion(ParticleIdentifier(ParticleName("H4")), ParticleIdentifier(ParticleName("C")));

    HarmonicBondType ohHarmonicBond(1.0_real, 1.0_real);   
    HarmonicBondType hcHarmonicBond(2.0_real, 1.0_real);

    HarmonicAngle hohAngle(1.0_real, Degrees(120.0));   
    HarmonicAngle hchAngle(1.0_real, Degrees(109.5)); 

    water.addInteraction(ParticleName("O"), ParticleName("H1"), ohHarmonicBond);
    water.addInteraction(ParticleName("O"), ParticleName("H2"), ohHarmonicBond);

    water.addInteraction(ParticleName("H1"), ParticleName("O"), ParticleName("H2"), hohAngle);

    methane.addInteraction(ParticleName("H1"), ParticleName("C"), hcHarmonicBond);
    methane.addInteraction(ParticleName("H2"), ParticleName("C"), hcHarmonicBond);
    methane.addInteraction(ParticleName("H3"), ParticleName("C"), hcHarmonicBond);
    methane.addInteraction(ParticleName("H4"), ParticleName("C"), hcHarmonicBond);

    methane.addInteraction(ParticleName("H1"), ParticleName("C"), ParticleName("H2"), hchAngle);
    methane.addInteraction(ParticleName("H1"), ParticleName("C"), ParticleName("H3"), hchAngle);
    methane.addInteraction(ParticleName("H1"), ParticleName("C"), ParticleName("H4"), hchAngle);
    methane.addInteraction(ParticleName("H2"), ParticleName("C"), ParticleName("H3"), hchAngle);
    methane.addInteraction(ParticleName("H2"), ParticleName("C"), ParticleName("H4"), hchAngle);
    methane.addInteraction(ParticleName("H3"), ParticleName("C"), ParticleName("H4"), hchAngle);

    // Define a box for the simulation
    Box box(6.05449);

    // Define options for the non-bonded kernels
    NBKernelOptions options;

    TopologyBuilder topologyBuilder;

    // add molecules
    topologyBuilder.addMolecule(water, 10);
    topologyBuilder.addMolecule(methane, 10);

    // add non-bonded interaction map
    topologyBuilder.addParticleTypesInteractions(interactions);

    Topology topology = topologyBuilder.buildTopology();

    SimulationState simulationState(coordinates, velocities, forces, box, topology);

    // The force calculator contains all the data needed to compute forces
    auto forceCalculator = setupGmxForceCalculatorCpu(simulationState.topology(), options);

    forceCalculator->updatePairlist(simulationState.coordinates(), simulationState.box());

    forceCalculator->compute(simulationState.coordinates(), simulationState.box(), simulationState.forces());

    return 0;
}

The compilation errors are as follows:

text

example-test.cpp: In function ‘int main()’:
example-test.cpp:163:64: error: cannot convert ‘std::vector<gmx::BasicVector<float> >’ to ‘gmx::ArrayRef<gmx::BasicVector<float> >’
  163 |     forceCalculator->updatePairlist(simulationState.coordinates(), simulationState.box());
      |                                                                |
      |                                                                std::vector<gmx::BasicVector<float> >

In file included from example-test.cpp:8:
gromacs_gpu/include/nblib/gmxcalculatorcpu.h:86:50: note:   initializing argument 1 of ‘void nblib::GmxNBForceCalculatorCpu::updatePairlist(gmx::ArrayRef<gmx::BasicVector<float> >, const nblib::Box&)’
   86 |     void updatePairlist(gmx::ArrayRef<gmx::RVec> coordinates, const Box& box);
      |                         ~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~

example-test.cpp:165:29: error: no matching function for call to ‘nblib::GmxNBForceCalculatorCpu::compute(std::vector<gmx::BasicVector<float> >&, nblib::Box, std::vector<gmx::BasicVector<float> >&)’
  165 |     forceCalculator->compute(simulationState.coordinates(), simulationState.box(), simulationState.forces());
      |     ~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

In file included from example-test.cpp:8:
gromacs_gpu/include/nblib/gmxcalculatorcpu.h:89:10: note: candidate: ‘void nblib::GmxNBForceCalculatorCpu::compute(gmx::ArrayRef<const gmx::BasicVector<float> >, const nblib::Box&, gmx::ArrayRef<gmx::BasicVector<float> >)’
   89 |     void compute(gmx::ArrayRef<const gmx::RVec> coordinateInput,
      |          ^~~~~~~

gromacs_gpu/include/nblib/gmxcalculatorcpu.h:89:49: note:   no known conversion for argument 1 from ‘std::vector<gmx::BasicVector<float> >’ to ‘gmx::ArrayRef<const gmx::BasicVector<float> >’
   89 |     void compute(gmx::ArrayRef<const gmx::RVec> coordinateInput,
      |                  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~

It appears that my method of calling the GmxNBForceCalculatorCpu class is incorrect.

Could you please show me the correct way to call these functions? Thank you!

This should be solved by including gromacs/utility/arrayref.h