def convert_parm_to_xml(path: pathlib.Path) -> str:
"""Convert an Amber parameter file to OpenMM XML format.
Notes:
* This function requires that ParmEd is installed.
* Doing any kind of interconversion of force fields is inherently dangerous.
This should only be used as a last resort when you have no other option.
Args:
path: The path to the Amber parameter file (.parm7, .prmtop, .parm).
Returns:
The OpenMM XML representation of the Amber parameter file.
"""
import parmed
if path.suffix.lower() not in {".prmtop", ".parm7", ".parm"}:
raise ValueError(f"Unsupported Amber file format: {path}")
warnings.warn(
f"Converting {path.name} from {path.suffix} to OpenMM FFXML. It is assumed "
f"that the parameter was generated by an Amber based FF, e.g. GAFF, and treats "
f"any improper torsions as such. Such conversion is inherently dangerous, and "
f"support to do so will be removed in the future.",
DeprecationWarning,
stacklevel=2,
)
structure = parmed.amber.AmberParm(str(path))
mock_atoms = [
_MockAtom(
index=atom.idx,
name=atom.name,
symbol=openmm.app.Element.getByAtomicNumber(atom.element).symbol,
typename=atom.type,
mass=atom.mass,
neighbours=[neigh.idx for neigh in atom.bond_partners],
)
for atom in structure.atoms
]
mock_bonds = [
_MockBond(
atom1=mock_atoms[bond.atom1.idx],
atom2=mock_atoms[bond.atom2.idx],
)
for bond in structure.bonds
]
mock_mol = _MockMolecule(atoms=mock_atoms, bonds=mock_bonds)
system = structure.createSystem(removeCMMotion=False)
_reorder_torsions(system, mock_mol)
mixin = openmmforcefields.generators.template_generators.OpenMMSystemMixin()
ffxml = mixin.convert_system_to_ffxml(mock_mol, system, "amber")
ffxml = ffxml.replace('ordering="smirnoff"', 'ordering="amber"')
return ffxml