Skip to content

Cenverting from RDKit molcule to OpenMM leads to incompatibility #2068

@MiloszGrabski

Description

@MiloszGrabski

Describe the bug
When adding a molecule converted from RDKit using OpenFF Toolkit to an OpenMM Modeller, the following error is raised:

AttributeError: 'numpy.ndarray' object has no attribute 'x'

This occurs due to a mismatch in coordinate format returned by t.get_positions()—a NumPy array— instead Vec3

Minimal example

This helper function causes the issue:

def add_molecule_to_modeller(modeller: Modeller, molecule: rdkit.Chem.Mol, resname: str = "FRA") -> None:
    resid = modeller.topology.getNumResidues() + 1
    mol = Molecule.from_rdkit(molecule)
    t = mol.to_topology()
    for atom in t.atoms:
        atom.metadata["residue_name"] = resname
        atom.metadata["residue_number"] = str(resid)
    modeller.add(t.to_openmm(), t.get_positions().to_openmm())  # <-- Causes error

Downstream, this triggers an exception when trying to compute bounding box coordinates after using modeller.addSolvent()

    for pos in water_positions:
        min_coords = Vec3(min(min_coords.x, pos.x), min(min_coords.y, pos.y), min(min_coords.z, pos.z))
        max_coords = Vec3(max(max_coords.x, pos.x), max(max_coords.y, pos.y), max(max_coords.z, pos.z))

Expected behavior
The to_openmm() call should produce a list of Vec3 positions compatible with Modeller.addSolvent().

Actual behavior
The t.get_positions().to_openmm() call returns a NumPy array, not a list of Vec3, leading to the AttributeError.

Workaround
Manually convert coordinates to Vec3:

from openmm.unit import nanometer, Vec3

def add_molecule_to_modeller(modeller: Modeller, molecule: rdkit.Chem.Mol, resname: str = "FRA") -> None:
    """Converts RDKit molecule to topology and adds it to the modeller."""
    resid = modeller.topology.getNumResidues() + 1
    mol = Molecule.from_rdkit(molecule)
    t = mol.to_topology()
    for atom in t.atoms:
        atom.metadata["residue_name"] = resname
        atom.metadata["residue_number"] = str(resid)
    positions = []
    for x, y, z in t.get_positions():
        x = x.to('nanometer').magnitude
        y = y.to('nanometer').magnitude
        z = z.to('nanometer').magnitude
        positions.append(Vec3(x, y, z) * nanometer)
    modeller.add(t.to_openmm(), positions)

Computing environment:

openff-toolkit 0.16.9 pyhd8ed1ab_0 conda-forge
openmm 8.2.0 py312haeaa2e4_2 conda-forge

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions