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¶
ForceInputcarries the geometry for one evaluation: positions, atomic
numbers, the cell, and the unit strings the caller wants back.
PotentialResultcarries the energy and the flat force array for that
evaluation.
PotentialConfigcarries 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: