Dashboard Core — QM/MM¶
Moved to dense_evolution.qmmm — this page documents the
backward-compatible re-export only; dashboard_core.qmmm still works
unchanged, but the real implementation and any new QM/MM work (region
partitioning, embedding) now live in the library itself, alongside real
Hellmann-Feynman nuclear forces and a real Velocity-Verlet MD step for
this project's molecule catalog — no fabricated geometry, no placeholder
forces. Backs Composer's QM/MM force and MD-trajectory panels.
from dashboard_core.qmmm import compute_hellmann_feynman_forces, run_md_trajectory
from dashboard_core.hamiltonians import MOLECULE_CATALOG
# MOLECULE_CATALOG keys are descriptive strings, not bare element symbols:
h2 = [k for k in MOLECULE_CATALOG if k.startswith("H2 ")][0]
forces = compute_hellmann_feynman_forces(h2)
print(forces["energy_hartree"]) # -1.1373 (Hartree-Fock ground state)
print(forces["force_norm"]) # ~0.0154 Hartree/Angstrom -- small residual at equilibrium
trajectory = run_md_trajectory(h2, n_steps=3, dt_fs=0.5)
print(trajectory["force_norm"]) # decreasing as the bond relaxes toward equilibrium
qmmm ¶
Backward-compatibility re-export. The real implementation moved to
dense_evolution.qmmm.forces (Dense-Evolution issue #283 -- qmmm now lives
in the library, alongside real QM/MM region partitioning/embedding,
instead of being buried inside the dashboard tool). Nothing in dashboard
code needed to change: from dashboard_core.qmmm import ... still works.
compute_hellmann_feynman_forces ¶
compute_hellmann_feynman_forces(
name: str,
statevector=None,
mapping: str = "jordan_wigner",
geometry=None,
fd_step_angstrom: float = 0.001,
)
Real Hellmann-Feynman forces (Hartree/Angstrom) on every nucleus of
MOLECULE_CATALOG[name]: F = -d
Cost (prog.txt, dashboard_core audit point 4a): the central-difference derivative evaluates energy_at 6n_atoms+1 times (H2's 2 atoms -> 13 Hamiltonian builds per call, each at a genuinely different geometry). This looks like it should be cacheable -- build_molecular_hamiltonian already caches by exact geometry -- but it isn't in practice: every one of the 13 geometries differs by fd_step_angstrom, so every call is a cache miss. Measured directly on H2 (dhf/PennyLane path) before deciding not to add a "cache the Pauli-term basis" layer here: HF + fermion-to-qubit mapping took 0.130s, Pauli-term extraction 0.0005s, dense matrix assembly 0.0031s -- the Hartree-Fock solve itself is 96%+ of the cost, not the bookkeeping after it, so caching the Pauli-term structure would save a few percent at best, not the 6n_atoms multiplier prog.txt's framing suggests. A real geometry change requires a real HF re-solve regardless of how its output gets packaged afterward -- see the module docstring's own account of why analytic differentiation (which WOULD avoid re-solving HF this many times) was tried and dropped for a real cross-platform PennyLane/ autograd bug, not reattempted here.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
A key from |
required |
statevector
|
see description above.
|
|
None
|
mapping
|
see description above.
|
|
None
|
geometry
|
see description above.
|
|
None
|
fd_step_angstrom
|
see description above.
|
|
None
|
Returns:
| Type | Description |
|---|---|
dict
|
|
Examples:
>>> from dense_evolution.qmmm import compute_hellmann_feynman_forces
>>> from dashboard_core.hamiltonians import MOLECULE_CATALOG
>>> h2 = [k for k in MOLECULE_CATALOG if k.startswith("H2 ")][0]
>>> result = compute_hellmann_feynman_forces(h2)
>>> round(result['energy_hartree'], 4)
-1.1373
>>> 0.01 < result['force_norm'] < 0.02 # small residual at equilibrium, not exactly zero
True
Source code in dense_evolution/qmmm/forces.py
172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 | |
md_step ¶
md_step(
positions_angstrom,
velocities_angstrom_per_fs,
forces_hartree_per_angstrom,
symbols,
dt_fs: float = 0.5,
)
One real Velocity-Verlet half-step (v(t+dt/2) = v(t) + a(t)dt/2, r(t+dt) = r(t) + v(t+dt/2)dt) using the real Hellmann-Feynman forces above and each atom's real atomic mass -- ordinary classical Newtonian mechanics (F=ma), nothing invented. Positions in Angstrom, velocities in Angstrom/fs, forces in Hartree/Angstrom, dt in femtoseconds.
Examples:
>>> import numpy as np
>>> from dense_evolution.qmmm import md_step
>>> positions = np.array([[0, 0, 0.0], [0, 0, 0.7414]]) # H2 at equilibrium
>>> velocities = np.zeros_like(positions)
>>> forces = np.array([[0, 0, 0.0109], [0, 0, -0.0109]]) # restoring force, pulling atoms together
>>> new_pos, new_vel, accel = md_step(positions, velocities, forces, ['H', 'H'], dt_fs=0.5)
>>> bool(new_pos[1, 2] < 0.7414) # the second atom moved toward the first
True
Source code in dense_evolution/qmmm/forces.py
run_md_trajectory ¶
run_md_trajectory(
name: str,
n_steps: int,
dt_fs: float = 0.5,
mapping: str = "jordan_wigner",
recompute_electronic_state: bool = False,
fd_step_angstrom: float = 0.001,
)
Real, minimal ab-initio-forces MD trajectory: at each step, real Hellmann-Feynman forces (compute_hellmann_feynman_forces) move the real nuclear positions/velocities via real Velocity-Verlet (md_step). Starts from rest (zero initial velocities) at the catalog's real equilibrium geometry.
fd_step_angstrom: forwarded to compute_hellmann_feynman_forces at every step -- previously not exposed here at all, silently using that function's own default (0.001 A) with no way for a caller to ask for a different finite-difference step (e.g. a molecule with an unusually steep energy landscape, where the default step size isn't the one already verified converged for H2).
recompute_electronic_state=False (default) holds the electronic state fixed at the initial Hartree-Fock reference through the whole trajectory -- forces stay exact only close to the starting geometry (a real, explicitly-stated approximation, not a fabricated one). True ab-initio MD (re-solving Hartree-Fock at every step's new geometry) is available by setting this True, at real, substantial extra cost per step.
Examples:
>>> from dense_evolution.qmmm import run_md_trajectory
>>> from dashboard_core.hamiltonians import MOLECULE_CATALOG
>>> h2 = [k for k in MOLECULE_CATALOG if k.startswith("H2 ")][0]
>>> traj = run_md_trajectory(h2, n_steps=3, dt_fs=0.5)
>>> traj['step']
[0, 1, 2]
>>> len(traj['force_norm'])
3
Source code in dense_evolution/qmmm/forces.py
See also: dashboard_core.hamiltonians
for MOLECULE_CATALOG and build_molecular_hamiltonian, which this
module's forces are derived from.