The RPC Model

A client needs an energy and forces for one geometry, from one backend. The backends do not share a configuration language. Lennard-Jones takes a few scalars, CPMD takes a deck, and a metatomic model takes a file path. The wire therefore splits the conversation into three carriers, all defined in one Cap’n Proto schema (Potentials.capnp).

Three carriers

  • ForceInput carries the geometry for one evaluation: positions, atomic

numbers, the cell, and the unit strings the caller wants back.

  • PotentialResult carries the energy and the flat force array for that

evaluation.

  • PotentialConfig carries backend setup, and only setup.

A client sends it once through configure, then sends a new ForceInput for every geometry.

Geometry stays off the configuration message. A change of method does not reshape the coordinates, and a change of coordinates does not repeat the method. The same split is what cpmdc uses for CPMDParams and ForceInput, and what eOn’s RgpotPot uses when it calls the NWChem and CPMD frontends.

One schema, many languages

The schema is the contract. The C++ server, the Python tests, and the Rust core all read it. The Rust crate vendors a copy so a crates.io build still has the schema. The monorepo copy under CppCore/rgpot/rpc/ is the fallback the build script checks. The Cap’n Proto wire format does not depend on the language, so a Rust client can call a C++ server, and the reverse.

Units

Inside the library the units are fixed: energy in eV, length in Angstrom, force in eV/Angstrom. A caller that works in Hartree or Bohr names those units on ForceInput. The server converts the inbound geometry before the potential runs, and converts the energy and forces on the way out. The potential implementations themselves stay in the native units.

Engines stay outside the server

NWChemPot and CPMDPot are frontends. They always build. At run time they dlopen libnwchemc and libcpmdc from the split projects. rgpot does not embed those engines. A test build can point the same frontends at the in-tree fake engines. Method options travel in the matching PotentialConfig arm (nwchem or cpmd). The geometry still arrives on ForceInput.

Where the layers sit

The schema is what a client sees. Under it, a Rust core owns the public types and the C ABI, and hand-written C++ wrappers give RAII handles over that ABI. The C++ potentials stay in CppCore and register back into the core through a callback. The layer-by-layer layout, the status codes, and the capability fields are reference material:

Architecture Overview