openforcefield / openff-toolkit

The Open Forcefield Toolkit provides implementations of the SMIRNOFF format, parameterization engine, and other tools. Documentation available at http://open-forcefield-toolkit.readthedocs.io
http://openforcefield.org
MIT License
301 stars 88 forks source link

Allow global toolkit conformer generation for assign_partial_charges #1863

Open lilyminium opened 2 months ago

lilyminium commented 2 months ago

Is your feature request related to a problem? Please describe.

When assigning partial charges with OpenEye, conformers are generated via the toolkit API using OpenEye:

https://github.com/openforcefield/openff-toolkit/blob/f79f48bef13a997619c4391ca6c800806238237a/openff/toolkit/utils/openeye_wrapper.py#L2456-L2461

@ntBre and I have seen that there are some molecules that OpenEye can't handle that RDKit is perfectly happy to generate. Specifically we ran into this with [SX3+1] atoms, e.g.:

from openff.toolkit import Molecule, ForceField

mol = Molecule.from_smiles("C[S+](C)C")
mol.assign_partial_charges("am1bccelf10")

yields this warning:

Warning: OEMMFFParams::PrepMol() : unable to type atom 1 S on residue UNL-1
Warning: : Force field setup failed due to missing parameters
Warning: OEMMFFParams::PrepMol() : unable to type atom 1 S on residue UNL-1
Warning: : Force field setup failed due to missing parameters

and error:

ValueError: No registered toolkits can provide the capability "assign_partial_charges" for args "()" and kwargs "{'molecule': Molecule with name '' and SMILES '[H]C([H])([H])[S+](C([H])([H])[H])C([H])([H])[H]', 'partial_charge_method': 'am1bccelf10', 'use_conformers': None, 'strict_n_conformers': False, 'normalize_partial_charges': True, '_cls': <class 'openff.toolkit.topology.molecule.Molecule'>}"
Available toolkits are: [ToolkitWrapper around OpenEye Toolkit version 2022.1.1, ToolkitWrapper around The RDKit version 2024.03.1, ToolkitWrapper around Built-in Toolkit version None]
 ToolkitWrapper around OpenEye Toolkit version 2022.1.1 <class 'openff.toolkit.utils.exceptions.ConformerGenerationError'> : OpenEye Omega conformer generation failed

Describe the solution you'd like

One pathway to bypass this is to generate conformers with RDKit and pass them to OpenEye for charge assignment.

from openff.toolkit import Molecule, ForceField

mol = Molecule.from_smiles("C[S+](C)C")
mol.generate_conformers(n_conformers=10)
mol.assign_partial_charges("am1bccelf10", use_conformers=mol.conformers)

RDKit delivers a UFFTYPER warning but succeeds, and partial charges are assigned by OpenEye with no further complaints.

[14:21:45] UFFTYPER: Unrecognized charge state for atom: 1

Would it be possible to rearrange https://github.com/openforcefield/openff-toolkit/blob/f79f48bef13a997619c4391ca6c800806238237a/openff/toolkit/utils/openeye_wrapper.py#L2456-L2461 such that it uses the global toolkit registry, to allow conformer generation to fall back to RDKit? e.g.

mol_copy.generate_conformers(
    n_conformers=charge_method["rec_confs"],
    rms_cutoff=0.25 * unit.angstrom,
    make_carboxylic_acids_cis=True,
)

Describe alternatives you've considered

This is potentially a bad idea, if the conformers generated by RDKit aren't suitable for charge assignment.

Additional context