Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update to rdkit md default #35

Merged
merged 4 commits into from
Apr 30, 2024
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
18 changes: 9 additions & 9 deletions isicle/geometry.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand All @@ -311,7 +311,7 @@ def _is_embedded(self):
"""

try:
self.mol.GetConformers()
mol.GetConformer().Is3D()
return True
except:
return False
Expand Down Expand Up @@ -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)(
Expand Down
6 changes: 4 additions & 2 deletions isicle/md.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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):
"""
Expand Down
151 changes: 74 additions & 77 deletions tests/test_conformers.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Loading