Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 13 additions & 9 deletions gufe/components/explicitmoleculecomponent.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import json
import logging
import warnings
from typing import Optional

Expand Down Expand Up @@ -34,7 +35,7 @@ def _ensure_ofe_name(mol: RDKitMol, name: str) -> str:
return name


def _check_partial_charges(mol: RDKitMol) -> None:
def _check_partial_charges(mol: RDKitMol, logger=None) -> None:
"""
Checks for the presence of partial charges.

Expand Down Expand Up @@ -82,15 +83,18 @@ def _check_partial_charges(mol: RDKitMol) -> None:
raise ValueError(errmsg)

if np.all(np.isclose(p_chgs, 0.0)):
wmsg = f"Partial charges provided all equal to " "zero. These may be ignored by some Protocols."
wmsg = "Partial charges provided all equal to zero. These may be ignored by some Protocols."
warnings.warn(wmsg)
else:
wmsg = (
"Partial charges have been provided, these will "
"preferentially be used instead of generating new "
"partial charges"
)
warnings.warn(wmsg)
msg = "Partial charges have been provided"
if name := mol.GetProp("ofe-name"):
msg += f" for {name}"
msg += ", these will preferentially be used instead of generating new partial charges."

if logger is None:
logger = logging.getLogger(__name__)

logger.info(msg)


class ExplicitMoleculeComponent(Component):
Expand All @@ -106,7 +110,7 @@ class ExplicitMoleculeComponent(Component):

def __init__(self, rdkit: RDKitMol, name: str = ""):
name = _ensure_ofe_name(rdkit, name)
_check_partial_charges(rdkit)
_check_partial_charges(rdkit, logger=self.logger)
conformers = list(rdkit.GetConformers())
if not conformers:
raise ValueError("Molecule was provided with no conformers.")
Expand Down
32 changes: 21 additions & 11 deletions gufe/tests/test_smallmoleculecomponent.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
else:
HAS_OFFTK = True
import json
import logging
import os
from unittest import mock

Expand All @@ -21,7 +22,7 @@

import gufe
from gufe import SmallMoleculeComponent
from gufe.components.explicitmoleculecomponent import _ensure_ofe_name
from gufe.components.explicitmoleculecomponent import _check_partial_charges, _ensure_ofe_name
from gufe.tokenization import TOKENIZABLE_REGISTRY

from .test_explicitmoleculecomponent import ExplicitMoleculeComponentMixin
Expand Down Expand Up @@ -242,15 +243,22 @@ def test_to_off_name(self, named_ethane):
@pytest.mark.skipif(not HAS_OFFTK, reason="no openff tookit available")
class TestSmallMoleculeComponentPartialCharges:
@pytest.fixture(scope="function")
def charged_off_ethane(self, ethane):
off_ethane = ethane.to_openff()
def charged_off_ethane(self, named_ethane):
off_ethane = named_ethane.to_openff()
off_ethane.assign_partial_charges(partial_charge_method="am1bcc")
return off_ethane

def test_partial_charges_warning(self, charged_off_ethane):
matchmsg = "Partial charges have been provided"
with pytest.warns(UserWarning, match=matchmsg):
SmallMoleculeComponent.from_openff(charged_off_ethane)
def test_check_partial_charges_without_gufe_logger(self, charged_off_ethane, caplog):
rd_mol = charged_off_ethane.to_rdkit()
caplog.set_level(logging.INFO)
_check_partial_charges(rd_mol, logger=None)
assert "Partial charges have been provided for ethane, these" in caplog.text

def test_partial_charges_logging(self, charged_off_ethane, caplog):
caplog.set_level(logging.INFO)
SmallMoleculeComponent.from_openff(charged_off_ethane)

assert "Partial charges have been provided" in caplog.text

def test_partial_charges_zero_warning(self, charged_off_ethane):
charged_off_ethane.partial_charges[:] = 0 * unit.elementary_charge
Expand All @@ -271,7 +279,7 @@ def test_partial_charges_too_few_atoms(self):
with pytest.raises(ValueError, match="Incorrect number of"):
SmallMoleculeComponent.from_rdkit(mol)

def test_partial_charges_applied_to_atoms(self):
def test_partial_charges_applied_to_atoms(self, caplog):
"""
Make sure that charges set at the molecule level
are transferred to atoms and picked up by openFF.
Expand All @@ -280,9 +288,11 @@ def test_partial_charges_applied_to_atoms(self):
Chem.AllChem.Compute2DCoords(mol)
# add some fake charges at the molecule level
mol.SetProp("atom.dprop.PartialCharge", "-1 0.25 0.25 0.25 0.25")
matchmsg = "Partial charges have been provided"
with pytest.warns(UserWarning, match=matchmsg):
ofe = SmallMoleculeComponent.from_rdkit(mol)
caplog.set_level(logging.INFO)

ofe = SmallMoleculeComponent.from_rdkit(mol)
assert "Partial charges have been provided" in caplog.text

# convert to openff and make sure the charges are set
off_mol = ofe.to_openff()
assert off_mol.partial_charges is not None
Expand Down