rdworks 0.36.4__tar.gz → 0.37.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {rdworks-0.36.4 → rdworks-0.37.1}/PKG-INFO +1 -1
- {rdworks-0.36.4 → rdworks-0.37.1}/src/rdworks/__init__.py +1 -1
- {rdworks-0.36.4 → rdworks-0.37.1}/src/rdworks/conf.py +133 -7
- {rdworks-0.36.4 → rdworks-0.37.1}/src/rdworks/mol.py +36 -95
- {rdworks-0.36.4 → rdworks-0.37.1}/src/rdworks/std.py +2 -0
- {rdworks-0.36.4 → rdworks-0.37.1}/src/rdworks.egg-info/PKG-INFO +1 -1
- {rdworks-0.36.4 → rdworks-0.37.1}/tests/test_basics.py +3 -0
- {rdworks-0.36.4 → rdworks-0.37.1}/LICENSE +0 -0
- {rdworks-0.36.4 → rdworks-0.37.1}/README.md +0 -0
- {rdworks-0.36.4 → rdworks-0.37.1}/pyproject.toml +0 -0
- {rdworks-0.36.4 → rdworks-0.37.1}/setup.cfg +0 -0
- {rdworks-0.36.4 → rdworks-0.37.1}/src/rdworks/autograph/__init__.py +0 -0
- {rdworks-0.36.4 → rdworks-0.37.1}/src/rdworks/autograph/autograph.py +0 -0
- {rdworks-0.36.4 → rdworks-0.37.1}/src/rdworks/autograph/centroid.py +0 -0
- {rdworks-0.36.4 → rdworks-0.37.1}/src/rdworks/autograph/dynamictreecut.py +0 -0
- {rdworks-0.36.4 → rdworks-0.37.1}/src/rdworks/autograph/nmrclust.py +0 -0
- {rdworks-0.36.4 → rdworks-0.37.1}/src/rdworks/autograph/rckmeans.py +0 -0
- {rdworks-0.36.4 → rdworks-0.37.1}/src/rdworks/bitqt/__init__.py +0 -0
- {rdworks-0.36.4 → rdworks-0.37.1}/src/rdworks/bitqt/bitqt.py +0 -0
- {rdworks-0.36.4 → rdworks-0.37.1}/src/rdworks/descriptor.py +0 -0
- {rdworks-0.36.4 → rdworks-0.37.1}/src/rdworks/display.py +0 -0
- {rdworks-0.36.4 → rdworks-0.37.1}/src/rdworks/ionized.py +0 -0
- {rdworks-0.36.4 → rdworks-0.37.1}/src/rdworks/matchedseries.py +0 -0
- {rdworks-0.36.4 → rdworks-0.37.1}/src/rdworks/mollibr.py +0 -0
- {rdworks-0.36.4 → rdworks-0.37.1}/src/rdworks/pka.py +0 -0
- {rdworks-0.36.4 → rdworks-0.37.1}/src/rdworks/predefined/Asinex_fragment.xml +0 -0
- {rdworks-0.36.4 → rdworks-0.37.1}/src/rdworks/predefined/Astex_RO3.xml +0 -0
- {rdworks-0.36.4 → rdworks-0.37.1}/src/rdworks/predefined/Baell2010_PAINS/Baell2010A.xml +0 -0
- {rdworks-0.36.4 → rdworks-0.37.1}/src/rdworks/predefined/Baell2010_PAINS/Baell2010B.xml +0 -0
- {rdworks-0.36.4 → rdworks-0.37.1}/src/rdworks/predefined/Baell2010_PAINS/Baell2010C.xml +0 -0
- {rdworks-0.36.4 → rdworks-0.37.1}/src/rdworks/predefined/Baell2010_PAINS/PAINS-less-than-015-hits.xml +0 -0
- {rdworks-0.36.4 → rdworks-0.37.1}/src/rdworks/predefined/Baell2010_PAINS/PAINS-less-than-150-hits.xml +0 -0
- {rdworks-0.36.4 → rdworks-0.37.1}/src/rdworks/predefined/Baell2010_PAINS/PAINS-more-than-150-hits.xml +0 -0
- {rdworks-0.36.4 → rdworks-0.37.1}/src/rdworks/predefined/Baell2010_PAINS/makexml.py +0 -0
- {rdworks-0.36.4 → rdworks-0.37.1}/src/rdworks/predefined/Brenk2008_Dundee/makexml.py +0 -0
- {rdworks-0.36.4 → rdworks-0.37.1}/src/rdworks/predefined/CNS.xml +0 -0
- {rdworks-0.36.4 → rdworks-0.37.1}/src/rdworks/predefined/ChEMBL_Walters/BMS.xml +0 -0
- {rdworks-0.36.4 → rdworks-0.37.1}/src/rdworks/predefined/ChEMBL_Walters/Dundee.xml +0 -0
- {rdworks-0.36.4 → rdworks-0.37.1}/src/rdworks/predefined/ChEMBL_Walters/Glaxo.xml +0 -0
- {rdworks-0.36.4 → rdworks-0.37.1}/src/rdworks/predefined/ChEMBL_Walters/Inpharmatica.xml +0 -0
- {rdworks-0.36.4 → rdworks-0.37.1}/src/rdworks/predefined/ChEMBL_Walters/LINT.xml +0 -0
- {rdworks-0.36.4 → rdworks-0.37.1}/src/rdworks/predefined/ChEMBL_Walters/MLSMR.xml +0 -0
- {rdworks-0.36.4 → rdworks-0.37.1}/src/rdworks/predefined/ChEMBL_Walters/PAINS.xml +0 -0
- {rdworks-0.36.4 → rdworks-0.37.1}/src/rdworks/predefined/ChEMBL_Walters/SureChEMBL.xml +0 -0
- {rdworks-0.36.4 → rdworks-0.37.1}/src/rdworks/predefined/ChEMBL_Walters/makexml.py +0 -0
- {rdworks-0.36.4 → rdworks-0.37.1}/src/rdworks/predefined/Hann1999_Glaxo/Hann1999.xml +0 -0
- {rdworks-0.36.4 → rdworks-0.37.1}/src/rdworks/predefined/Hann1999_Glaxo/Hann1999Acid.xml +0 -0
- {rdworks-0.36.4 → rdworks-0.37.1}/src/rdworks/predefined/Hann1999_Glaxo/Hann1999Base.xml +0 -0
- {rdworks-0.36.4 → rdworks-0.37.1}/src/rdworks/predefined/Hann1999_Glaxo/Hann1999ElPh.xml +0 -0
- {rdworks-0.36.4 → rdworks-0.37.1}/src/rdworks/predefined/Hann1999_Glaxo/Hann1999NuPh.xml +0 -0
- {rdworks-0.36.4 → rdworks-0.37.1}/src/rdworks/predefined/Hann1999_Glaxo/makexml.py +0 -0
- {rdworks-0.36.4 → rdworks-0.37.1}/src/rdworks/predefined/Kazius2005/Kazius2005.xml +0 -0
- {rdworks-0.36.4 → rdworks-0.37.1}/src/rdworks/predefined/Kazius2005/makexml.py +0 -0
- {rdworks-0.36.4 → rdworks-0.37.1}/src/rdworks/predefined/ZINC_druglike.xml +0 -0
- {rdworks-0.36.4 → rdworks-0.37.1}/src/rdworks/predefined/ZINC_fragment.xml +0 -0
- {rdworks-0.36.4 → rdworks-0.37.1}/src/rdworks/predefined/ZINC_leadlike.xml +0 -0
- {rdworks-0.36.4 → rdworks-0.37.1}/src/rdworks/predefined/fragment.xml +0 -0
- {rdworks-0.36.4 → rdworks-0.37.1}/src/rdworks/predefined/ionized/simple_smarts_pattern.csv +0 -0
- {rdworks-0.36.4 → rdworks-0.37.1}/src/rdworks/predefined/ionized/smarts_pattern.csv +0 -0
- {rdworks-0.36.4 → rdworks-0.37.1}/src/rdworks/predefined/misc/makexml.py +0 -0
- {rdworks-0.36.4 → rdworks-0.37.1}/src/rdworks/predefined/misc/reactive-part-2.xml +0 -0
- {rdworks-0.36.4 → rdworks-0.37.1}/src/rdworks/predefined/misc/reactive-part-3.xml +0 -0
- {rdworks-0.36.4 → rdworks-0.37.1}/src/rdworks/predefined/misc/reactive.xml +0 -0
- {rdworks-0.36.4 → rdworks-0.37.1}/src/rdworks/readin.py +0 -0
- {rdworks-0.36.4 → rdworks-0.37.1}/src/rdworks/rgroup.py +0 -0
- {rdworks-0.36.4 → rdworks-0.37.1}/src/rdworks/scaffold.py +0 -0
- {rdworks-0.36.4 → rdworks-0.37.1}/src/rdworks/stereoisomers.py +0 -0
- {rdworks-0.36.4 → rdworks-0.37.1}/src/rdworks/tautomers.py +0 -0
- {rdworks-0.36.4 → rdworks-0.37.1}/src/rdworks/torsion.py +0 -0
- {rdworks-0.36.4 → rdworks-0.37.1}/src/rdworks/units.py +0 -0
- {rdworks-0.36.4 → rdworks-0.37.1}/src/rdworks/utils.py +0 -0
- {rdworks-0.36.4 → rdworks-0.37.1}/src/rdworks/xml.py +0 -0
- {rdworks-0.36.4 → rdworks-0.37.1}/src/rdworks/xtb/__init__.py +0 -0
- {rdworks-0.36.4 → rdworks-0.37.1}/src/rdworks/xtb/wrapper.py +0 -0
- {rdworks-0.36.4 → rdworks-0.37.1}/src/rdworks.egg-info/SOURCES.txt +0 -0
- {rdworks-0.36.4 → rdworks-0.37.1}/src/rdworks.egg-info/dependency_links.txt +0 -0
- {rdworks-0.36.4 → rdworks-0.37.1}/src/rdworks.egg-info/requires.txt +0 -0
- {rdworks-0.36.4 → rdworks-0.37.1}/src/rdworks.egg-info/top_level.txt +0 -0
- {rdworks-0.36.4 → rdworks-0.37.1}/tests/test_decimals.py +0 -0
- {rdworks-0.36.4 → rdworks-0.37.1}/tests/test_gypsumdl.py +0 -0
- {rdworks-0.36.4 → rdworks-0.37.1}/tests/test_iupac_name.py +0 -0
- {rdworks-0.36.4 → rdworks-0.37.1}/tests/test_nn_xtb.py +0 -0
- {rdworks-0.36.4 → rdworks-0.37.1}/tests/test_web.py +0 -0
- {rdworks-0.36.4 → rdworks-0.37.1}/tests/test_xtb_wrapper.py +0 -0
@@ -3,6 +3,7 @@ import copy
|
|
3
3
|
import json
|
4
4
|
import numpy as np
|
5
5
|
import ase
|
6
|
+
import itertools
|
6
7
|
|
7
8
|
from collections.abc import Callable
|
8
9
|
from typing import Self
|
@@ -15,6 +16,8 @@ from rdkit.Chem import rdMolTransforms, AllChem, rdMolAlign, rdmolops
|
|
15
16
|
from rdkit.Chem.Draw import rdMolDraw2D
|
16
17
|
from PIL import Image
|
17
18
|
|
19
|
+
from rdworks.std import clean_2d
|
20
|
+
from rdworks.torsion import get_torsion_atoms, create_torsion_fragment
|
18
21
|
from rdworks.units import ev2kcalpermol, pm2angstrom
|
19
22
|
from rdworks.utils import recursive_round
|
20
23
|
from rdworks.xtb.wrapper import GFN2xTB
|
@@ -387,7 +390,124 @@ class Conf:
|
|
387
390
|
raise RuntimeError("ASE calculator error")
|
388
391
|
|
389
392
|
|
390
|
-
def
|
393
|
+
def torsion_atoms(self, strict: bool = True) -> dict[int, tuple]:
|
394
|
+
"""Determine torsion/dihedral angle atoms (i-j-k-l) and rotating group for each rotatable bond (j-k).
|
395
|
+
|
396
|
+
Args:
|
397
|
+
strict (bool): whether to exclude amide/imide/ester/acid bonds.
|
398
|
+
|
399
|
+
Returns:
|
400
|
+
{torsion_key: (i, j, k, l), ...,}
|
401
|
+
"""
|
402
|
+
return {i: d[:4] for i, d in enumerate(get_torsion_atoms(self.rdmol, strict))}
|
403
|
+
|
404
|
+
|
405
|
+
def torsion_energies(self,
|
406
|
+
calculator: str | Callable,
|
407
|
+
torsion_key: int | None = None,
|
408
|
+
simplify: bool = True,
|
409
|
+
fmax: float = 0.05,
|
410
|
+
interval: float = 20.0,
|
411
|
+
use_converged_only: bool = True,
|
412
|
+
**kwargs,
|
413
|
+
) -> Self:
|
414
|
+
"""Calculates potential energy profiles for each torsion angle using ASE optimizer.
|
415
|
+
|
416
|
+
It uses the first conformer as a reference.
|
417
|
+
|
418
|
+
Args:
|
419
|
+
calculator (str | Callable): 'MMFF', 'UFF', or ASE calculator.
|
420
|
+
torsion_key (int | None): torsion index to calculate. Defaults to None (all).
|
421
|
+
simplify (bool, optional): whether to use fragment surrogate. Defaults to True.
|
422
|
+
fmax (float, optional): fmax of ASE optimizer. Defaults to 0.05.
|
423
|
+
interval (float, optional): interval of torsion angles in degree. Defaults to 15.0.
|
424
|
+
use_converged_only (bool, optional): whether to use only converged data. Defaults to True.
|
425
|
+
|
426
|
+
Returns:
|
427
|
+
Self: modified self.
|
428
|
+
"""
|
429
|
+
|
430
|
+
if torsion_key is None:
|
431
|
+
torsion_atoms_indices = self.torsion_atoms()
|
432
|
+
# {0: (5, 4, 3, 1)}
|
433
|
+
else:
|
434
|
+
torsion_atoms_indices = {torsion_key: self.torsion_atoms()[torsion_key]}
|
435
|
+
|
436
|
+
ref_conf = self.copy()
|
437
|
+
|
438
|
+
data = {}
|
439
|
+
|
440
|
+
if simplify:
|
441
|
+
for tk, indices in torsion_atoms_indices.items():
|
442
|
+
frag, frag_ijkl = create_torsion_fragment(ref_conf.rdmol, indices)
|
443
|
+
frag_conf = Conf(frag)
|
444
|
+
data[tk] = {'indices': indices, 'angle':[], 'init':[], 'last':[], 'Converged':[]}
|
445
|
+
for angle in np.arange(-180.0, 180.0, interval):
|
446
|
+
# Iterated numpy.ndarray does not contain the last 180: -180., ..., (180).
|
447
|
+
conf = frag_conf.copy()
|
448
|
+
conf.props.update({'torsion_key': tk, 'angle': float(angle)})
|
449
|
+
conf.set_torsion(*frag_ijkl, angle) # atoms bonded to `l` move.
|
450
|
+
conf = conf.optimize(calculator, fmax, **kwargs)
|
451
|
+
# conf.optimize() updates coordinates and conf.props:
|
452
|
+
# `angle`, `E_tot_init(kcal/mol)`, `E_tot(kcal/mol)`, `Converged`.
|
453
|
+
tk = conf.props['torsion_key']
|
454
|
+
data[tk]['angle'].append(conf.props['angle'])
|
455
|
+
data[tk]['init'].append(conf.props['E_tot_init(kcal/mol)'])
|
456
|
+
data[tk]['last'].append(conf.props['E_tot(kcal/mol)'])
|
457
|
+
data[tk]['Converged'].append(conf.props['Converged'])
|
458
|
+
frag_cleaned, _ = clean_2d(frag, reset_isotope=True, remove_H=True)
|
459
|
+
# to serialize the molecule
|
460
|
+
data[tk]['frag'] = Chem.MolToMolBlock(frag_cleaned)
|
461
|
+
data[tk]['frag_indices'] = frag_ijkl
|
462
|
+
|
463
|
+
else:
|
464
|
+
# mol.confs will be populated with torsion conformers.
|
465
|
+
# It is designed for a batch optimization in the future.
|
466
|
+
torsion_angle_confs = []
|
467
|
+
for tk, indices in torsion_atoms_indices.items():
|
468
|
+
data[tk] = {'indices': indices, 'angle':[], 'init':[], 'last':[], 'Converged':[]}
|
469
|
+
for angle in np.arange(-180.0, 180.0, interval):
|
470
|
+
# Iterated numpy.ndarray does not contain the last 180: -180., ..., (180).
|
471
|
+
x = ref_conf.copy()
|
472
|
+
x.props.update({'torsion_key': tk, 'angle': float(angle)})
|
473
|
+
x.set_torsion(*indices, angle) # atoms bonded to `l` move.
|
474
|
+
torsion_angle_confs.append(x)
|
475
|
+
|
476
|
+
# Calculate relaxation energies
|
477
|
+
for conf in torsion_angle_confs:
|
478
|
+
conf = conf.optimize(calculator, fmax, **kwargs)
|
479
|
+
# conf.optimize() updates coordinates and conf.props:
|
480
|
+
# `angle`, `E_tot_init(kcal/mol)`, `E_tot(kcal/mol)`, `Converged`.
|
481
|
+
tk = conf.props['torsion_key']
|
482
|
+
data[tk]['angle'].append(conf.props['angle'])
|
483
|
+
data[tk]['init'].append(conf.props['E_tot_init(kcal/mol)'])
|
484
|
+
data[tk]['last'].append(conf.props['E_tot(kcal/mol)'])
|
485
|
+
data[tk]['Converged'].append(conf.props['Converged'])
|
486
|
+
|
487
|
+
# Post-processing
|
488
|
+
torsion_energy_profiles = {}
|
489
|
+
for tk, dictdata in data.items():
|
490
|
+
if use_converged_only:
|
491
|
+
dictdata['angle'] = list(itertools.compress(dictdata['angle'], dictdata['Converged']))
|
492
|
+
dictdata['init'] = list(itertools.compress(dictdata['init'], dictdata['Converged']))
|
493
|
+
dictdata['last'] = list(itertools.compress(dictdata['last'], dictdata['Converged']))
|
494
|
+
relax = np.array(dictdata['init']) - np.median(dictdata['last'])
|
495
|
+
E_rel = relax - np.min(relax)
|
496
|
+
torsion_energy_profiles[tk] = {
|
497
|
+
'indices' : dictdata['indices'],
|
498
|
+
'angle' : np.round(np.array(dictdata['angle']), 1).tolist(), # np.ndarray -> list for serialization
|
499
|
+
'E_rel(kcal/mol)': np.round(E_rel, 2).tolist(), # np.ndarray -> list for serialization
|
500
|
+
'frag' : dictdata.get('frag', None),
|
501
|
+
'frag_indices' : dictdata.get('frag_indices', None),
|
502
|
+
}
|
503
|
+
|
504
|
+
self.props['torsion'] = torsion_energy_profiles
|
505
|
+
self.props['torsion_calculator'] = str(calculator)
|
506
|
+
|
507
|
+
return self
|
508
|
+
|
509
|
+
|
510
|
+
def torsion_angle(self, i: int, j: int, k: int, l: int) -> float:
|
391
511
|
"""Get dihedral angle (i-j-k-l) in degrees.
|
392
512
|
|
393
513
|
Args:
|
@@ -419,8 +539,10 @@ class Conf:
|
|
419
539
|
return json.dumps(self.props)
|
420
540
|
|
421
541
|
|
422
|
-
def serialize(self, decimals:int=3) -> str:
|
423
|
-
"""Serialize information necessary to rebuild.
|
542
|
+
def serialize(self, decimals: int = 3) -> str:
|
543
|
+
"""Serialize information necessary to rebuild a Conf object.
|
544
|
+
Args:
|
545
|
+
decimals (int, optional): number of decimal places for float data type. Defaults to 3.
|
424
546
|
|
425
547
|
Returns:
|
426
548
|
str: serialized string for json.loads()
|
@@ -435,14 +557,18 @@ class Conf:
|
|
435
557
|
return serialized
|
436
558
|
|
437
559
|
|
438
|
-
def deserialize(self, serialized:str) -> Self:
|
439
|
-
"""De-serialize information and rebuild.
|
560
|
+
def deserialize(self, serialized: str) -> Self:
|
561
|
+
"""De-serialize information and rebuild a Conf object.
|
562
|
+
|
563
|
+
Example:
|
564
|
+
serialized = conf1.serialize()
|
565
|
+
conf2 = Conf().deserialize(serialized)
|
440
566
|
|
441
567
|
Args:
|
442
|
-
serialized (str):
|
568
|
+
serialized (str): serialized string.
|
443
569
|
|
444
570
|
Returns:
|
445
|
-
Self:
|
571
|
+
Self: modified self.
|
446
572
|
"""
|
447
573
|
data = json.loads(serialized)
|
448
574
|
|
@@ -942,18 +942,6 @@ class Mol:
|
|
942
942
|
return [atom.GetAtomicNum() for atom in self.rdmol.GetAtoms()]
|
943
943
|
|
944
944
|
|
945
|
-
def torsion_atoms(self, strict: bool = True) -> dict[int, tuple]:
|
946
|
-
"""Determine torsion/dihedral angle atoms (i-j-k-l) and rotating group for each rotatable bond (j-k).
|
947
|
-
|
948
|
-
Args:
|
949
|
-
strict (bool): whether to exclude amide/imide/ester/acid bonds.
|
950
|
-
|
951
|
-
Returns:
|
952
|
-
{torsion_key: (i, j, k, l), ...,}
|
953
|
-
"""
|
954
|
-
return {i: d[:4] for i, d in enumerate(get_torsion_atoms(self.rdmol, strict))}
|
955
|
-
|
956
|
-
|
957
945
|
def compute(self, **kwargs) -> Self:
|
958
946
|
"""Change settings for parallel computing.
|
959
947
|
|
@@ -972,6 +960,18 @@ class Mol:
|
|
972
960
|
return self
|
973
961
|
|
974
962
|
|
963
|
+
def torsion_atoms(self, strict: bool = True) -> dict[int, tuple]:
|
964
|
+
"""Determine torsion/dihedral angle atoms (i-j-k-l) and rotating group for each rotatable bond (j-k).
|
965
|
+
|
966
|
+
Args:
|
967
|
+
strict (bool): whether to exclude amide/imide/ester/acid bonds.
|
968
|
+
|
969
|
+
Returns:
|
970
|
+
{torsion_key: (i, j, k, l), ...,}
|
971
|
+
"""
|
972
|
+
return {i: d[:4] for i, d in enumerate(get_torsion_atoms(self.rdmol, strict))}
|
973
|
+
|
974
|
+
|
975
975
|
def torsion_energies(self,
|
976
976
|
calculator: str | Callable,
|
977
977
|
torsion_key: int | None = None,
|
@@ -997,87 +997,16 @@ class Mol:
|
|
997
997
|
Self: modified self.
|
998
998
|
"""
|
999
999
|
assert self.count() > 0, "torsion_energies() requires at least one conformer"
|
1000
|
-
|
1001
|
-
self = self.compute(**kwargs)
|
1002
|
-
|
1003
|
-
if torsion_key is None:
|
1004
|
-
torsion_atoms_indices = self.torsion_atoms()
|
1005
|
-
# {0: (5, 4, 3, 1)}
|
1006
|
-
else:
|
1007
|
-
torsion_atoms_indices = {torsion_key: self.torsion_atoms()[torsion_key]}
|
1008
|
-
|
1009
1000
|
ref_conf = self.confs[0].copy()
|
1010
|
-
|
1011
|
-
|
1012
|
-
|
1013
|
-
|
1014
|
-
|
1015
|
-
|
1016
|
-
|
1017
|
-
|
1018
|
-
|
1019
|
-
# Iterated numpy.ndarray does not contain the last 180: -180., ..., (180).
|
1020
|
-
conf = frag_conf.copy()
|
1021
|
-
conf.props.update({'torsion_key': tk, 'angle': float(angle)})
|
1022
|
-
conf.set_torsion(*frag_ijkl, angle) # atoms bonded to `l` move.
|
1023
|
-
conf = conf.optimize(calculator, fmax, **kwargs)
|
1024
|
-
# conf.optimize() updates coordinates and conf.props:
|
1025
|
-
# `angle`, `E_tot_init(kcal/mol)`, `E_tot(kcal/mol)`, `Converged`.
|
1026
|
-
tk = conf.props['torsion_key']
|
1027
|
-
data[tk]['angle'].append(conf.props['angle'])
|
1028
|
-
data[tk]['init'].append(conf.props['E_tot_init(kcal/mol)'])
|
1029
|
-
data[tk]['last'].append(conf.props['E_tot(kcal/mol)'])
|
1030
|
-
data[tk]['Converged'].append(conf.props['Converged'])
|
1031
|
-
frag_cleaned, _ = clean_2d(frag, reset_isotope=True, remove_H=True)
|
1032
|
-
rdDepictor.Compute2DCoords(frag_cleaned)
|
1033
|
-
# to serialize the molecule
|
1034
|
-
data[tk]['frag'] = Chem.MolToMolBlock(frag_cleaned)
|
1035
|
-
data[tk]['frag_indices'] = frag_ijkl
|
1036
|
-
|
1037
|
-
else:
|
1038
|
-
# mol.confs will be populated with torsion conformers.
|
1039
|
-
# It is designed for a batch optimization in the future.
|
1040
|
-
mol = self.copy()
|
1041
|
-
mol.confs = []
|
1042
|
-
for tk, indices in torsion_atoms_indices.items():
|
1043
|
-
data[tk] = {'indices': indices, 'angle':[], 'init':[], 'last':[], 'Converged':[]}
|
1044
|
-
for angle in np.arange(-180.0, 180.0, interval):
|
1045
|
-
# Iterated numpy.ndarray does not contain the last 180: -180., ..., (180).
|
1046
|
-
x = ref_conf.copy()
|
1047
|
-
x.props.update({'torsion_key': tk, 'angle': float(angle)})
|
1048
|
-
x.set_torsion(*indices, angle) # atoms bonded to `l` move.
|
1049
|
-
mol.confs.append(x)
|
1050
|
-
|
1051
|
-
# Calculate relaxation energies
|
1052
|
-
for conf in mol.confs:
|
1053
|
-
conf = conf.optimize(calculator, fmax, **kwargs)
|
1054
|
-
# conf.optimize() updates coordinates and conf.props:
|
1055
|
-
# `angle`, `E_tot_init(kcal/mol)`, `E_tot(kcal/mol)`, `Converged`.
|
1056
|
-
tk = conf.props['torsion_key']
|
1057
|
-
data[tk]['angle'].append(conf.props['angle'])
|
1058
|
-
data[tk]['init'].append(conf.props['E_tot_init(kcal/mol)'])
|
1059
|
-
data[tk]['last'].append(conf.props['E_tot(kcal/mol)'])
|
1060
|
-
data[tk]['Converged'].append(conf.props['Converged'])
|
1061
|
-
|
1062
|
-
# Post-processing
|
1063
|
-
torsion_energy_profiles = {}
|
1064
|
-
for tk, dictdata in data.items():
|
1065
|
-
if use_converged_only:
|
1066
|
-
dictdata['angle'] = list(itertools.compress(dictdata['angle'], dictdata['Converged']))
|
1067
|
-
dictdata['init'] = list(itertools.compress(dictdata['init'], dictdata['Converged']))
|
1068
|
-
dictdata['last'] = list(itertools.compress(dictdata['last'], dictdata['Converged']))
|
1069
|
-
relax = np.array(dictdata['init']) - np.median(dictdata['last'])
|
1070
|
-
E_rel = relax - np.min(relax)
|
1071
|
-
torsion_energy_profiles[tk] = {
|
1072
|
-
'indices' : dictdata['indices'],
|
1073
|
-
'angle' : np.round(np.array(dictdata['angle']), 1).tolist(), # np.ndarray -> list for serialization
|
1074
|
-
'E_rel(kcal/mol)': np.round(E_rel, 2).tolist(), # np.ndarray -> list for serialization
|
1075
|
-
'frag' : dictdata.get('frag', None),
|
1076
|
-
'frag_indices' : dictdata.get('frag_indices', None),
|
1077
|
-
}
|
1078
|
-
|
1079
|
-
self.props['torsion'] = torsion_energy_profiles
|
1080
|
-
self.props['torsion_calculator'] = str(calculator)
|
1001
|
+
ref_conf = ref_conf.torsion_energies(calculator,
|
1002
|
+
torsion_key,
|
1003
|
+
simplify,
|
1004
|
+
fmax,
|
1005
|
+
interval,
|
1006
|
+
use_converged_only,
|
1007
|
+
**kwargs)
|
1008
|
+
for k in ['torsion', 'torsion_calculator']:
|
1009
|
+
self.props[k] = ref_conf.props[k]
|
1081
1010
|
|
1082
1011
|
return self
|
1083
1012
|
|
@@ -1629,7 +1558,15 @@ class Mol:
|
|
1629
1558
|
return json.dumps(props)
|
1630
1559
|
|
1631
1560
|
|
1632
|
-
def serialize(self, decimals: int = 2) -> str:
|
1561
|
+
def serialize(self, decimals: int = 2) -> str:
|
1562
|
+
"""Serialize information necessary to rebuild a Mol object.
|
1563
|
+
|
1564
|
+
Args:
|
1565
|
+
decimals (int, optional): number of decimal places for float data type. Defaults to 2.
|
1566
|
+
|
1567
|
+
Returns:
|
1568
|
+
str: serialized string for json.loads()
|
1569
|
+
"""
|
1633
1570
|
serialized = json.dumps({
|
1634
1571
|
'name' : self.name,
|
1635
1572
|
'smiles': self.smiles,
|
@@ -1641,10 +1578,14 @@ class Mol:
|
|
1641
1578
|
|
1642
1579
|
|
1643
1580
|
def deserialize(self, serialized: str) -> Self:
|
1644
|
-
"""
|
1581
|
+
"""De-serialize the information and build a new Mol object.
|
1582
|
+
|
1583
|
+
Example:
|
1584
|
+
serialized = mol1.serialize()
|
1585
|
+
mol2 = Mol().deserialize(serialized)
|
1645
1586
|
|
1646
1587
|
Args:
|
1647
|
-
serialized (str):
|
1588
|
+
serialized (str): serialized string.
|
1648
1589
|
|
1649
1590
|
Returns:
|
1650
1591
|
Self: modified self.
|
@@ -481,6 +481,9 @@ def test_torsion_fragment():
|
|
481
481
|
# {0: (5, 4, 3, 1)}
|
482
482
|
assert len(ta2) == 1
|
483
483
|
frag, frag_ijkl = create_torsion_fragment(mol2.confs[0].rdmol, ta2[0])
|
484
|
+
# expects no fragmentation
|
485
|
+
assert frag == mol2.confs[0].rdmol
|
486
|
+
assert frag_ijkl == ta2[0]
|
484
487
|
|
485
488
|
|
486
489
|
def test_torsion_energies():
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|