Components are usually by default loaded into OpenFE without pre-existing partial charges. This is particularly true when loading from SDF and PDB files.

In those cases, partial charges will be assigned within the selected Protocol. As of writing, for SmallMoleculeComponents this is done using antechamber’s am1bcc charge assignment, using the input conformer as the pre-optimized input for sqm’s AM1 calculation. For ProteinComponents and SolventComponents this is done by assigning charges from the chosen protein and solvent force fields.

Unfortunately charge assignment can be both, a) time consuming for large molecules, and b) non-deterministic, especially when the molecule occupies a conformation far from a local minima in the AM1 energetic landscape. The latter can be particularly problematic as this can lead to significant differences in assigned partial charges between Protocol simulation repeats.

To avoid these issues, we recommend applying user charges to SmallMoleculeComponents. In its simplest form, this is done by converting the SmallMoleculeComponent to an OpenFF Molecule calling the OpenFF Molecule’s ``assign_partial_charges method` <https://docs.openforcefield.org/projects/toolkit/en/latest/api/generated/openff.toolkit.topology.Molecule.html#openff.toolkit.topology.Molecule.assign_partial_charges>`__ and then re-loading it back into a SmallMoleculeComponent before further manipulation.

Here we demonstrate how to first load a set of small molecules from an SDF and converting them to OpenFF Molecules

[1]:
from rdkit import Chem
from openff.toolkit import Molecule

off_molecules = [
    Molecule.from_rdkit(mol)
    for mol in Chem.SDMolSupplier(
        "assets/somebenzenes.sdf",
        removeHs=False,
    )
]

Remember to include the removeHs=False keyword argument so that RDKit does not strip your hydrogens!

Assigning partial charges to an OpenFF Molecule#

Next we assign partial charges to the OpenFF Molecule using the am1bcc method and the conformation taken from the input SDF file.

[2]:
# Loop through each Molecule and call `assign_partial_charges`

for offmol in off_molecules:
    offmol.assign_partial_charges('am1bcc', use_conformers=offmol.conformers)

By default this will default to using the OEChem TK if available, otherwise AmberTools’ antechamber will be used.

Alternative partial charge methods can be used. For example one could ask for am1-mulliken charges. Please see the OpenFF documentation for more information.

[3]:
# Instead assign am1-mulliken charges

for offmol in off_molecules:
    offmol.assign_partial_charges('am1-mulliken', use_conformers=offmol.conformers)

Any kind of charge assignment will be usable by OpenFE, except if all the partial charges are set to zero!

Once we have the desired partial charges for our small molecules, we can then convert them to SmallMoleculeComponents for further use within the OpenFE toolkit.

[4]:
import openfe

small_molecule_components = [
    openfe.SmallMoleculeComponent.from_openff(mol)
    for mol in off_molecules
]
/home/bioc1523/software/mambaforge/install/envs/openfe/lib/python3.11/site-packages/gufe/components/explicitmoleculecomponent.py:79: UserWarning: Partial charges have been provided, these will preferentially be used instead of generating new partial charges
  warnings.warn(wmsg)

A warning is expected on SmallMoleculeComponent creation. This is to tell you that input partial charges have been provided. Where appropriate these will be preferrentially used within OpenFE, avoiding any subsequent charge assignment steps.