diff --git a/isicle/geometry.py b/isicle/geometry.py index b2168fa..a6072f1 100644 --- a/isicle/geometry.py +++ b/isicle/geometry.py @@ -299,7 +299,7 @@ def __init__(self, **kwargs): self.__dict__.update(dict.fromkeys(self._defaults, self._default_value)) self.__dict__.update(kwargs) - def _is_embedded(self): + def _is_embedded(self, mol): """ Check if molecule has embedded 3D coordinates. @@ -311,7 +311,7 @@ def _is_embedded(self): """ try: - self.mol.GetConformers() + mol.GetConformer().Is3D() return True except: return False @@ -386,17 +386,17 @@ def _forcefield_selector(forcefield, mw): # Embed molecule 3D coordinates if embed is True: # Attempt embedding - try: - Chem.AllChem.EmbedMolecule(mol) - - # Use random coordinates - except: - Chem.AllChem.EmbedMolecule(mol, useRandomCoords=True) + res = Chem.AllChem.EmbedMolecule(mol) + if res == -1: + # Use random coordinates + res = Chem.AllChem.EmbedMolecule(mol, useRandomCoords=True) + if res == -1: + raise ValueError("Embedding failure.") # Optimize according to supplied forcefield if forcefield is not None: # Check if embedded - if self._is_embedded(): + if self._is_embedded(mol): # Forcefield selection if "mmff94s" in forcefield.lower(): _forcefield_selector(forcefield, mol)( diff --git a/isicle/md.py b/isicle/md.py index 0ee3bf6..67bfe49 100644 --- a/isicle/md.py +++ b/isicle/md.py @@ -519,7 +519,7 @@ def set_geometry(self, geom): self.geom = geom self.basename = self.geom.basename - def configure(self, method: str = "distance", numConfs: int = 10, **kwargs): + def configure(self, method: str = "etkdgv3", numConfs: int = 10, **kwargs): """ Set conformer generation parameters. Parameters @@ -600,12 +600,14 @@ def _configure_etkdg2(self): """ self.params = rdDistGeom.ETKDGv2() - def _configure_etkdg3(self): + def _configure_etkdg3(self, variant=True): """ Set parameters for ETKDG conformer generation, based on work by Riniker and Landrum. Version 3: Updated sampling small rings AND macrocycles """ self.params = rdDistGeom.ETKDGv3() + if variant is True: + self.params.useSmallRingTorsions = True def _configure_etkdg3_variant(self): """ diff --git a/tests/test_conformers.py b/tests/test_conformers.py index 590afe2..5f3adb2 100644 --- a/tests/test_conformers.py +++ b/tests/test_conformers.py @@ -26,140 +26,137 @@ def random_energies(): @pytest.fixture() def conformers(): - x = [isicle.geometry.load(localfile('resources/geom_test.mol')) - for i in range(30)] + x = [isicle.geometry.load(localfile("resources/geom_test.mol")) for i in range(30)] return isicle.conformers.ConformationalEnsemble(x) -@pytest.mark.parametrize('func,expected', - [('boltzmann', isicle.conformers.boltzmann), - ('simple', isicle.conformers.simple_average), - ('lowest', isicle.conformers.lowest_energy), - ('threshold', isicle.conformers.threshold)]) +@pytest.mark.parametrize( + "func,expected", + [ + ("boltzmann", isicle.conformers.boltzmann), + ("simple", isicle.conformers.simple_average), + ("lowest", isicle.conformers.lowest_energy), + ("threshold", isicle.conformers.energy_threshold), + ], +) def test__function_selector(func, expected): # Check correct class is yielded assert isicle.conformers._function_selector(func) == expected -@pytest.mark.parametrize('func', - [('boltzman'), - ('smple'), - ('lowest-energy'), - ('thresh')]) +@pytest.mark.parametrize( + "func", [("boltzman"), ("smple"), ("lowest-energy"), ("thresh")] +) def test__function_selector_fail(func): # Check unsupported selections with pytest.raises(ValueError): isicle.conformers._function_selector(func) -@pytest.mark.parametrize('func,expected', - [(isicle.conformers.boltzmann, True), - (isicle.conformers.simple_average, False), - (isicle.conformers.lowest_energy, True), - (isicle.conformers.threshold, True)]) +@pytest.mark.parametrize( + "func,expected", + [ + (isicle.conformers.boltzmann, True), + (isicle.conformers.simple_average, False), + (isicle.conformers.lowest_energy, True), + (isicle.conformers.energy_threshold, True), + ], +) def test__energy_based(func, expected): assert isicle.conformers._energy_based(func) is expected def test_reduce(random_values, random_energies): - result = isicle.conformers.reduce(random_values, - func='boltzmann', - energy=random_energies, - index=None) + result = isicle.conformers.reduce( + random_values, func="boltzmann", energy=random_energies, index=None + ) - assert abs(result['mean'] - 670.505) < 1E-3 - assert abs(result['std'] - 26.566) < 1E-3 - assert result['n'] == 30 + assert abs(result["mean"] - 670.505) < 1e-3 + assert abs(result["std"] - 26.566) < 1e-3 + assert result["n"] == 30 -@pytest.mark.parametrize('index', - [(None)]) +@pytest.mark.parametrize("index", [(None)]) def test_boltzmann(random_values, random_energies, index): - result = isicle.conformers.boltzmann(random_values, - random_energies, - index=index) + result = isicle.conformers.boltzmann(random_values, random_energies, index=index) - assert abs(result['mean'] - 670.505) < 1E-3 - assert abs(result['std'] - 26.566) < 1E-3 - assert result['n'] == 30 + assert abs(result["mean"] - 670.505) < 1e-3 + assert abs(result["std"] - 26.566) < 1e-3 + assert result["n"] == 30 -@pytest.mark.parametrize('index', - [(None)]) +@pytest.mark.parametrize("index", [(None)]) def test_simple_average(random_values, index): - result = isicle.conformers.simple_average(random_values, - index=index) + result = isicle.conformers.simple_average(random_values, index=index) - assert abs(result['mean'] - 451.660) < 1E-3 - assert abs(result['std'] - 276.717) < 1E-3 - assert result['n'] == 30 + assert abs(result["mean"] - 451.660) < 1e-3 + assert abs(result["std"] - 276.717) < 1e-3 + assert result["n"] == 30 -@pytest.mark.parametrize('index', - [(None)]) +@pytest.mark.parametrize("index", [(None)]) def test_lowest_energy(random_values, random_energies, index): - result = isicle.conformers.lowest_energy(random_values, - random_energies, - index=index) + result = isicle.conformers.lowest_energy( + random_values, random_energies, index=index + ) - assert abs(result['value'] - 667.237) < 1E-3 - assert abs(result['energy'] - 0.016) < 1E-3 + assert abs(result["value"] - 667.237) < 1e-3 + assert abs(result["energy"] - 0.016) < 1e-3 -@pytest.mark.parametrize('index', - [(None)]) +@pytest.mark.parametrize("index", [(None)]) def test_threshold(random_values, random_energies, index): - result = isicle.conformers.threshold(random_values, - random_energies, - threshold=0.5, - index=index) - - assert abs(result['mean'] - 414.716) < 1E-3 - assert abs(result['std'] - 289.999) < 1E-3 - assert result['n'] == 15 - - -@pytest.mark.parametrize('objects', - [([Geometry(), Geometry(), Geometry()]), - ([XYZGeometry(), XYZGeometry(), Geometry()])]) + result = isicle.conformers.energy_threshold( + random_values, random_energies, threshold=0.5, index=index + ) + + assert abs(result["mean"] - 414.716) < 1e-3 + assert abs(result["std"] - 289.999) < 1e-3 + assert result["n"] == 15 + + +@pytest.mark.parametrize( + "objects", + [ + ([Geometry(), Geometry(), Geometry()]), + ([XYZGeometry(), XYZGeometry(), Geometry()]), + ], +) def test_build_conformational_ensemble(objects): isicle.conformers.build_conformational_ensemble(objects) -@pytest.mark.parametrize('objects', - [([Geometry(), 'abc', Geometry()]), - ([XYZGeometry(), Geometry(), list()])]) +@pytest.mark.parametrize( + "objects", + [([Geometry(), "abc", Geometry()]), ([XYZGeometry(), Geometry(), list()])], +) def test_build_conformational_ensemble_fail(objects): with pytest.raises(TypeError): isicle.conformers.build_conformational_ensemble(objects) class TestConformationalEnsemble: - - @pytest.mark.parametrize('index', - [(False)]) + @pytest.mark.parametrize("index", [(False)]) def test_reduce(self, conformers, random_values, random_energies, index): # Set values for c, v, e in zip(conformers, random_values, random_energies): - c.global_properties = {'dummy': v, 'energy': {'energy': [e]}} + c.global_properties = {"dummy": v, "energy": {"energy": [e]}} # Reduce attribute - result = conformers.reduce('dummy', func='boltzmann') + result = conformers.reduce("dummy", func="boltzmann") # Verify result - assert abs(result['mean'] - 670.505) < 1E-3 - assert abs(result['std'] - 26.566) < 1E-3 - assert result['n'] == 30 + assert abs(result["mean"] - 670.505) < 1e-3 + assert abs(result["std"] - 26.566) < 1e-3 + assert result["n"] == 30 def test__apply_method(self, conformers): - result = conformers._apply_method('get_natoms') + result = conformers._apply_method("get_natoms") assert all(x == 2 for x in result) def test__apply_function(self, conformers): - result = conformers._apply_function(isicle.qm.dft, - program='NWChem', - fmt='xyz') + result = conformers._apply_function(isicle.qm.dft, program="NWChem", fmt="xyz") def test_apply(self, conformers): - result = conformers.apply(method='get_natoms') + result = conformers.apply(method="get_natoms") assert all(x == 2 for x in result)