QM/MM in AMBER with QUICK¶
This tutorial describes how to run minimization, equilibration, and production with AMBER files generated by CHARMM-GUI, including QM/MM simulations with QUICK and semiempirical methods.
Assumed file names:
step3_input.parm7step3_input.rst7step4.0_minimization.mdinstep4.1_equilibration.mdinstep5_production.mdin
If your files use different names, substitute them in the commands below.
1. Minimization¶
Run minimization with sander on CPU. If dihe.restraint exists, update the restraint force placeholder first:
grep -q "FC" dihe.restraint && sed -e "s/FC/1.0/g" dihe.restraint > step4.0_minimization.rest
Run minimization:
sander -O -i step4.0_minimization.mdin -p step3_input.parm7 -c step3_input.rst7 -o step4.0_minimization.mdout -r step4.0_minimization.rst7 -inf step4.0_minimization.mdinfo -ref step3_input.rst7
For GPU execution, use pmemd.cuda with the same arguments when the calculation type supports it:
pmemd.cuda -O ...
2. Equilibration¶
If dihe.restraint exists:
sed -e "s/FC/1.0/g" dihe.restraint > step4.1_equilibration.rest
Run equilibration:
sander -O -i step4.1_equilibration.mdin -p step3_input.parm7 -c step4.0_minimization.rst7 -o step4.1_equilibration.mdout -r step4.1_equilibration.rst7 -inf step4.1_equilibration.mdinfo -ref step3_input.rst7 -x step4.1_equilibration.nc
GPU form:
pmemd.cuda -O ...
3. Production¶
sander -O -i step5_production.mdin -p step3_input.parm7 -c step4.1_equilibration.rst7 -o step5.mdout -r step5.rst7 -inf step5.mdinfo -x step5.nc
For MPI-based execution:
mpirun -np 2 sander.MPI -O -i step5_production.mdin -p step3_input.parm7 -c step4.1_equilibration.rst7 -o step5.mdout -r step5.rst7 -inf step5.mdinfo -x step5.nc
Semiempirical QM/MM with AM1 is not accelerated through pmemd.cuda. To run QM/MM where the quantum region is evaluated on GPU, use QUICK through AmberTools.
4. QM/MM Dynamics with QUICK¶
SANDER can use different QUICK installations for QM/MM:
- serial
- MPI parallel
- CUDA accelerated
- HIP accelerated
- CUDA + MPI
- HIP + MPI
QUICK can be used through two main interfaces:
- FBI, the file-based interface
- API, the in-memory application programming interface
5. File-Based Interface¶
With the file-based interface, sander can call QUICK executables such as:
quickquick.MPIquick.cudaquick.hipquick.cuda.MPIquick.hip.MPI
Before running QUICK simulations, load the AMBER environment:
source $AMBERHOME/amber.sh
or, for C shell:
source $AMBERHOME/amber.csh
FBI Example with Mechanical Embedding¶
The example below places the first two residues in the QM region and runs B3LYP/def2-SVP with quick.cuda.MPI on two GPUs:
&cntrl
...
ifqnt = 1,
/
&qmmm
qmmask = ':1-2',
qm_theory = 'extern',
qmmm_int = 5,
/
&quick
method = 'B3LYP',
basis = 'def2-svp',
executable = 'quick.cuda.MPI',
do_parallel = 'mpirun -np 2',
/
Main flags:
ifqnt = 1: enables QM/MMqmmask: selects atoms in the QM regionqm_theory = 'extern': uses an external program through FBIqmmm_int = 5: mechanical embeddingexecutable: selects the QUICK executabledo_parallel: command prefix for MPI QUICK executables
In many FBI workflows, use serial sander rather than sander.MPI, because system calls inside MPI programs can be limited. This means the MM region may run on one CPU core even when the QM calculation uses multiple GPUs.
6. QUICK API¶
The API communicates directly in memory and is usually much faster than FBI.
Example for electrostatic embedding:
&cntrl
...
ifqnt = 1,
/
&qmmm
qmmask = ':1-2',
qm_theory = 'quick',
qmmm_int = 1,
qm_ewald = 0,
/
&quick
method = 'B3LYP',
basis = 'def2-svp',
/
Important points:
qm_theory = 'quick'activates the QUICK API.qmmm_int = 1uses electrostatic embedding.- The same input can be used with
sander,sander.MPI,sander.quick.cuda, orsander.quick.cuda.MPI. - QUICK output is written to
quick.outunless changed.
7. &quick Namelist Summary¶
| Variable | Type | Interface | Description |
|---|---|---|---|
method |
String | API/FBI | Method: HF, B3LYP, wB97X-D, PBE, etc.; default is BLYP. |
basis |
String | API/FBI | Basis set: 6-31G*, def2-SVP, cc-pVDZ, etc.; default is 6-31G. |
executable |
String | FBI only | QUICK executable, such as quick.cuda.MPI or quick.hip. |
do_parallel |
String | FBI only | Prefix such as mpirun -np 4 or srun --gpus=4. |
scf_cyc |
Integer | API/FBI | Maximum SCF cycles; default is 200. |
reuse_dmx |
Integer | API only | Reuse previous density matrix; 1 is default and accelerates MD. |
denserms |
Float | API only | Density-matrix convergence criterion. |
intcutoff |
Float | API only | Integral cutoff. |
xccutoff |
Float | API only | Exchange-correlation pruning threshold. |
basiscutoff |
Float | API only | Cutoff for insignificant basis functions. |
gradcutoff |
Float | API only | Gradient convergence criterion. |
export |
String | API only | Export orbitals, for example molden. |
keywords |
String | API only | Full QUICK keyword line, for example B3LYP BASIS=cc-pVDZ CHARGE=0 MULT=1 GRADIENT EXTCHARGES. |
outfprefix |
String | API only | Prefix for QUICK output; default creates quick.out. |
debug |
Integer | API/FBI | Debug level. |
use_template |
Integer | FBI only | Use a QUICK template file. |
Practical rule:
- For maximum speed and electrostatic embedding, use the API with
qm_theory='quick'andsander.quick.cudaorsander.quick.cuda.MPI. - Use FBI only when a specific QUICK option is not exposed through the API.
8. FBI vs API¶
| Feature | FBI, qm_theory='extern' |
API, qm_theory='quick' |
|---|---|---|
| Communication | Through files | Directly in memory |
| Speed in MD | Usually much slower | Fastest option |
| MM part | Usually serial | Can use MPI/OpenMP depending on executable |
| Multi-GPU QM | Supported with quick.cuda.MPI |
Supported with sander.quick.cuda.MPI |
| SANDER executable | Usually serial sander |
sander.quick.cuda or sander.quick.cuda.MPI |
| Electrostatic embedding | Supported | Supported and recommended |
| Mechanical embedding | Supported | Supported |
| QUICK output | Many separate files | Usually one quick.out |
| Typical use | Rare compatibility cases | Default choice for performance |
9. Example QUICK Commands¶
Single GPU:
sander.quick.cuda -O -i md.in -o md.out -p topo.prmtop -c coord.rst
Multi-GPU with parallel MM:
mpirun -np 8 sander.quick.cuda.MPI -O -i md.in -o md.out -p topo.prmtop -c coord.rst
Example .mdin fragment:
&qmmm
qm_theory = 'quick',
qmmask = ':LIG | :120,130,145',
/
&quick
method = 'PM6',
basis = '6-31G*',
/
10. Study-Specific QUICK Production Flags¶
Example production input with explicit iqmatoms:
&qmmm
iqmatoms=593, 594, 595, 596, 597, 598, 3722, 3723, 3724, 3725, 3726, 3727, 3728, 3729, 3730, 3731, 45573, 45574, 45575, 45624, 45625, 45626, 56283, 56284, 56285, 58281, 58282, 58283, 58680, 58681, 58682, 58608, 58609, 58610, 58863, 58864, 58865, 9066, 9067, 9068, 9069, 9070, 9071, 9072, 9073, 9074, 9075, 9076, 9077, 9078, 9079, 9080, 9081, 9082, 9083, 9084, 9085, 9086, 9087, 9088,
qmcharge=-1,
qm_theory='PM3',
qmcut=12.0,
qmshake=0,
adjust_q=1
/
&quick
method = 'B3LYP',
basis = 'def2-svp',
/
The production simulation was run with:
mpirun -np 2 sander.quick.cuda.MPI -O -i step5_production.mdin -p step3_input.parm7 -c step4.1_equilibration.rst7 -o step5.mdout -r step5.rst7 -inf step5.mdinfo -x step5.nc
In this case, -np was limited to 2 because using more CPU ranks caused immediate GPU memory overflow on two RTX 4090 GPUs.
11. Odd Electron Count Error¶
If MPI_ABORT occurs and quick.out contains:
QMMM: System specified with odd number of electrons (107)
QMMM: but odd spin (1). You most likely have the charge of
QMMM: QM region (qmcharge) set incorrectly.
The selected QM region has an odd number of electrons. Review qmcharge and spin/multiplicity settings so they are chemically consistent with the selected QM region.
Example input after adding explicit charge and spin settings:
&qmmm
iqmatoms=3729, 45573, 45574, 45575, 3728, 3730, 3731, 598, 596, 597, 45624, 45625, 45626, 56283, 56284, 56285, 58281, 58282, 58283, 58590, 58591, 58592, 9067, 9068, 9066, 9089, 9106, 9109, 9110, 9107, 9108,
qmcharge=-1,
spin=1,
qm_theory='quick',
qmcut=12.0,
qmshake=0,
adjust_q=1
/
&quick
method = 'B3LYP',
basis = 'def2-svp',
/
12. Semiempirical AM1 Fallback¶
In the reference workflow, the B3LYP/def2-SVP QUICK run was estimated at about 6,123.8 hours. Because of this cost, the QM/MM MD was run with the semiempirical method qm_theory='AM1'.
Production flags:
&qmmm
iqmatoms=3729, 45573, 45574, 45575, 3728, 3730, 3731, 598, 596, 597, 45624, 45625, 45626, 56283, 56284, 56285, 58281, 58282, 58283, 58590, 58591, 58592, 9067, 9068, 9066, 9089, 9106, 9109, 9110, 9107, 9108,
qmcharge=-1,
spin=1,
qm_theory='AM1',
qmcut=12.0,
qmshake=1,
adjust_q=1,
qm_ewald=1, qm_pme=1,
/
Run on CPU with 28 cores:
mpirun -np 28 sander.MPI -O -i step5_production.mdin -p step3_input.parm7 -c step4.1_equilibration.rst7 -o step5.mdout -r step5.rst7 -inf step5.mdinfo -x step5.nc
13. Error: QM Region + Cutoff Larger than Box¶
During QM/MM with AMBER, the following error can appear:
****************************************************
ERROR: QM region + cutoff larger than box dimension:
QM-MM Cutoff = 35.0000
Coord Lower Upper Size Radius of largest sphere inside unit cell
X -40.743 39.788 80.531 46.761
Y -40.855 52.676 93.531 46.761
Z -42.214 43.047 85.261 46.761
****************************************************
SANDER BOMB in subroutine QM_CHECK_PERIODIC<qm_mm.f>
QM region + cutoff larger than box
cannot continue, need larger box.
AMBER checks whether the QM region fits inside the simulation box using:
- radius of the QM region
- QM/MM cutoff,
qmcut - smallest box dimension
The required condition is:
QM_radius + qmcut < half_box_dimension
where:
half_box_dimension = smallest_box_dimension / 2
Example:
qmcut = 35 angstromQM_radius = 8.147 angstrom- smallest box dimension =
80.531 angstrom
Then:
QM_radius + qmcut = 43.147 angstrom
half_box_dimension = 80.531 / 2 = 40.265 angstrom
Since 43.147 > 40.265, the QM region plus cutoff does not fit in the box.
Reducing qmcut to 30 gives:
QM_radius + qmcut = 38.147 angstrom
half_box_dimension = 40.265 angstrom
Now 38.147 < 40.265, so the simulation can proceed.
14. Check the QM Radius Automatically¶
Save the following script as calc_qm_radius.py:
import sys
import math
fn = sys.argv[1]
qmcut = float(sys.argv[2])
min_box_dimension = float(sys.argv[3])
iqm_list = [
3729, 45573, 45574, 45575, 3728, 3730, 3731, 598, 596, 597,
45624, 45625, 45626, 56283, 56284, 56285, 58281, 58282, 58283,
58590, 58591, 58592, 9067, 9068, 9066, 9089, 9106, 9109,
9110, 9107, 9108,
]
atoms = []
with open(fn) as f:
for line in f:
if line.startswith("ATOM") or line.startswith("HETATM"):
serial = int(line[6:11].strip())
x = float(line[30:38].strip())
y = float(line[38:46].strip())
z = float(line[46:54].strip())
resseq = line[22:26].strip()
atoms.append((serial, int(resseq) if resseq.isdigit() else None, x, y, z))
coords = [(x, y, z) for (serial, resseq, x, y, z) in atoms if serial in iqm_list]
if not coords:
coords = [(x, y, z) for (serial, resseq, x, y, z) in atoms if resseq in iqm_list]
if not coords:
print("No IQM atom found. Check whether iqm_list contains atom serials or residue IDs.")
print("Total atoms in PDB:", len(atoms))
sys.exit(1)
cx = sum(x for x, y, z in coords) / len(coords)
cy = sum(y for x, y, z in coords) / len(coords)
cz = sum(z for x, y, z in coords) / len(coords)
dists = [
math.sqrt((x - cx) ** 2 + (y - cy) ** 2 + (z - cz) ** 2)
for x, y, z in coords
]
qm_radius = max(dists)
required_half_box = qm_radius + qmcut
required_box_size = 2 * required_half_box
half_box_dimension = min_box_dimension / 2
print("QM atom count:", len(coords))
print("QM centroid: {:.3f} {:.3f} {:.3f}".format(cx, cy, cz))
print("QM radius: {:.3f} angstrom".format(qm_radius))
print("Required half box: {:.3f} angstrom".format(required_half_box))
print("Required box size: {:.3f} angstrom".format(required_box_size))
if required_half_box > half_box_dimension:
print(
"WARNING: QM region + qmcut ({:.2f} angstrom) > half box ({:.2f} angstrom)".format(
required_half_box, half_box_dimension
)
)
print("Solution: increase the box size or reduce qmcut.")
else:
print(
"OK: QM region + qmcut = {:.2f} angstrom fits in a box of {:.2f} angstrom".format(
required_half_box, min_box_dimension
)
)
Run:
python calc_qm_radius.py step3_input.pdb 35 80.531
python calc_qm_radius.py step3_input.pdb 30 80.531
Use the output to choose a qmcut that fits inside the simulation box.