User Guide#
seamm_mdi provides one public class, MDIEngine, a
driver that launches an MDI engine and drives it for repeated energy/force
evaluations. This guide covers the launch contract, the driving API, units, and
the client/server model.
Launching an engine#
MDIEngine(build_argv, elements, *, name="SEAMM",
hostname="localhost", timeout=60.0)
build_argv is a callable build_argv(hostname, port) -> list[str] that
returns the command line to start the engine, pointed at the driver’s
hostname and port. The engine must be launched with
-role ENGINE so that it connects to the driver (see The client/server
model below). In a SEAMM step this callable is usually built from the model
chemistry’s get_mdi_engine_command so the engine, method, charge, and
multiplicity all come from the user’s Model Chemistry choice.
elements is the list of atomic numbers, in coordinate order, and is fixed
for the life of the engine.
The engine is started with start(), or by entering
the object as a context manager, which is the recommended form:
with MDIEngine(build_argv, elements=[8, 1, 1]) as engine:
... # drive the engine here
start picks a free port, begins listening, launches the engine, accepts its
connection, and sends the fixed topology (number of atoms and elements).
close() (called automatically on exit) tells the
engine to shut down and reaps the process.
Note
MDI keeps global state, so use one active engine per process.
Driving the engine#
engine.set_coordinates(xyz, units="Å") # (n, 3) or flat (3n,)
e = engine.energy(units="kcal/mol") # a float
f = engine.forces(units="kcal/mol/Å") # an (n, 3) array
You can call these repeatedly for different geometries — that is the whole
point, since the engine is launched only once. The number of evaluations is
tracked in engine.n_energy_calls and engine.n_force_calls (handy for
reporting how many times the external code ran).
Periodic systems and optional capabilities#
For a periodic system send the cell before the coordinates; the engine then treats the system as fully periodic and can return the stress tensor:
if engine.supports(">CELL"):
engine.set_cell(cell_vectors, units="Å") # (3, 3), vectors as rows
engine.set_coordinates(xyz, units="Å")
sigma = engine.stress(units="GPa") # (3, 3), pressure sign convention
Not every engine understands >CELL (MOPAC’s does not; xnn’s and tblite’s
do), so check with engine.supports(command) first. The same check gates the
optional analytic Hessian: engine.supports("<HESSIAN") is truthful, and
engine.hessian() returns the (3n, 3n) matrix when it is offered.
Units#
All unit conversion is done inside MDIEngine (via seamm_util.Q_),
so callers never sprinkle conversions through their own code. Each method takes
an optional units= string; the defaults are MDI-native:
Method |
Default units |
Example override |
|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Any unit string pint understands is accepted.
The client/server model#
MDI decides which side is the network server from -role: the driver
listens on its port and the engine connects to it (that is why the engine
gets the -hostname). MDIEngine is the driver, so it listens; engines
dial in. This is the only direction that works when one driver serves several
engines, and — importantly — it is the direction that will work for remote
execution, where the driver runs on the SEAMM JobServer and the engine, launched
on a compute node, dials back to it.
The present release launches the engine as a local subprocess (localhost).
Launching the engine remotely through the SEAMM executor (queue submission, with
the engine dialing back to the JobServer) is planned; the driving API above will
be unchanged.