rdworks 0.38.1__py3-none-any.whl → 0.40.1__py3-none-any.whl
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/__init__.py +1 -1
- rdworks/conf.py +139 -84
- rdworks/mol.py +15 -7
- rdworks/testdata.py +24 -0
- rdworks/utils.py +29 -0
- {rdworks-0.38.1.dist-info → rdworks-0.40.1.dist-info}/METADATA +1 -1
- {rdworks-0.38.1.dist-info → rdworks-0.40.1.dist-info}/RECORD +10 -9
- {rdworks-0.38.1.dist-info → rdworks-0.40.1.dist-info}/WHEEL +0 -0
- {rdworks-0.38.1.dist-info → rdworks-0.40.1.dist-info}/licenses/LICENSE +0 -0
- {rdworks-0.38.1.dist-info → rdworks-0.40.1.dist-info}/top_level.txt +0 -0
rdworks/__init__.py
CHANGED
rdworks/conf.py
CHANGED
@@ -19,7 +19,7 @@ from PIL import Image
|
|
19
19
|
from rdworks.std import clean_2d
|
20
20
|
from rdworks.torsion import get_torsion_atoms, create_torsion_fragment
|
21
21
|
from rdworks.units import ev2kcalpermol, pm2angstrom
|
22
|
-
from rdworks.utils import recursive_round
|
22
|
+
from rdworks.utils import recursive_round, compress_string, decompress_string
|
23
23
|
from rdworks.xtb.wrapper import GFN2xTB
|
24
24
|
from rdworks.display import render_png, render_svg
|
25
25
|
|
@@ -39,11 +39,20 @@ class Conf:
|
|
39
39
|
"""
|
40
40
|
assert isinstance(molecule, str | Chem.Mol) or molecule is None
|
41
41
|
|
42
|
-
self.rdmol = None # must contain one and only one rdkit conformer
|
43
42
|
self.name = name
|
43
|
+
self.rdmol = None # must contain one and only one rdkit conformer
|
44
44
|
self.natoms = 0
|
45
|
-
self.charge = 0
|
46
|
-
self.spin = 1
|
45
|
+
self.charge = 0 # molecular formal charge
|
46
|
+
self.spin = 1 # molecular spin multiplicity for ASE
|
47
|
+
# Molecular spin multiplicity describes the number of possible orientations of
|
48
|
+
# spin angular momentum for a given molecule, essentially indicating the total
|
49
|
+
# number of unpaired electrons.
|
50
|
+
# Spin Angular Momentum (S): up (+1/2) or down (-1/2)
|
51
|
+
# Spin Multiplicity (2S + 1)
|
52
|
+
# 0 unpaired electron has S = 0, 2S + 1 = 0, called a singlet.
|
53
|
+
# 1 unpaired electron has S = 1/2, 2S + 1 = 2, called a doublet (radical).
|
54
|
+
# 2 unpaired electrons has S = 1, 2S + 1 = 3, called a triplet.
|
55
|
+
|
47
56
|
self.props = {}
|
48
57
|
|
49
58
|
if molecule is None:
|
@@ -63,10 +72,12 @@ class Conf:
|
|
63
72
|
|
64
73
|
num_atoms = self.rdmol.GetNumAtoms()
|
65
74
|
tot_atoms = self.rdmol.GetNumAtoms(onlyExplicit=False)
|
75
|
+
|
66
76
|
assert num_atoms == tot_atoms, "Conf() Error: missing hydrogens"
|
77
|
+
|
67
78
|
self.natoms = num_atoms
|
68
79
|
self.charge = rdmolops.GetFormalCharge(self.rdmol)
|
69
|
-
self.props.update({'atoms':
|
80
|
+
self.props.update({'atoms': self.natoms, 'charge': self.charge})
|
70
81
|
|
71
82
|
assert self.rdmol.GetConformer().Is3D(), "Conf() Error: not 3D"
|
72
83
|
|
@@ -148,7 +159,6 @@ class Conf:
|
|
148
159
|
|
149
160
|
return self
|
150
161
|
|
151
|
-
|
152
162
|
|
153
163
|
def optimize(self,
|
154
164
|
calculator: str | Callable = 'MMFF94',
|
@@ -402,6 +412,95 @@ class Conf:
|
|
402
412
|
return {i: d[:4] for i, d in enumerate(get_torsion_atoms(self.rdmol, strict))}
|
403
413
|
|
404
414
|
|
415
|
+
def torsion_energies_one(self,
|
416
|
+
calculator: str | Callable,
|
417
|
+
indices: tuple,
|
418
|
+
simplify: bool = True,
|
419
|
+
fmax: float = 0.05,
|
420
|
+
interval: float = 20.0,
|
421
|
+
use_converged_only: bool = True,
|
422
|
+
**kwargs) -> Self:
|
423
|
+
"""Calculate potential energy profile for a torsion angle.
|
424
|
+
|
425
|
+
Args:
|
426
|
+
calculator (str | Callable): 'MMFF', 'UFF', or ASE calculator.
|
427
|
+
indices (tuple): atom indices (i,j,k,l) for a torsion angle
|
428
|
+
simplify (bool, optional): whether to use fragementation. Defaults to True.
|
429
|
+
fmax (float, optional): convergence limit for optimize. Defaults to 0.05.
|
430
|
+
interval (float, optional): angle intervals. Defaults to 20.0.
|
431
|
+
use_converged_only (bool, optional): whether to use only converged data. Defaults to True.
|
432
|
+
|
433
|
+
Returns:
|
434
|
+
Self: modified self.
|
435
|
+
"""
|
436
|
+
ref_conf = self.copy()
|
437
|
+
|
438
|
+
data = {'indices': indices,
|
439
|
+
'angle': [],
|
440
|
+
'init': [],
|
441
|
+
'last': [],
|
442
|
+
'Converged': [],
|
443
|
+
}
|
444
|
+
|
445
|
+
if simplify:
|
446
|
+
frag, frag_ijkl = create_torsion_fragment(ref_conf.rdmol, indices)
|
447
|
+
frag_conf = Conf(frag)
|
448
|
+
for angle in np.arange(-180.0, 180.0, interval):
|
449
|
+
# Iterated numpy.ndarray does not contain the last 180: -180., ..., (180).
|
450
|
+
conf = frag_conf.copy()
|
451
|
+
conf.set_torsion(*frag_ijkl, angle) # atoms bonded to `l` move.
|
452
|
+
conf = conf.optimize(calculator, fmax, **kwargs)
|
453
|
+
# conf.optimize() updates coordinates and conf.props:
|
454
|
+
# `E_tot_init(kcal/mol)`, `E_tot(kcal/mol)`, `Converged`.
|
455
|
+
data['angle'].append(angle)
|
456
|
+
data['init'].append(conf.props['E_tot_init(kcal/mol)'])
|
457
|
+
data['last'].append(conf.props['E_tot(kcal/mol)'])
|
458
|
+
data['Converged'].append(conf.props['Converged'])
|
459
|
+
frag_cleaned, _ = clean_2d(frag, reset_isotope=True, remove_H=True)
|
460
|
+
# to serialize the molecule
|
461
|
+
data['frag'] = Chem.MolToMolBlock(frag_cleaned)
|
462
|
+
data['frag_indices'] = frag_ijkl
|
463
|
+
else:
|
464
|
+
for angle in np.arange(-180.0, 180.0, interval):
|
465
|
+
# Iterated numpy.ndarray does not contain the last 180: -180., ..., (180).
|
466
|
+
conf = ref_conf.copy()
|
467
|
+
conf.set_torsion(*indices, angle) # atoms bonded to `l` move.
|
468
|
+
conf = conf.optimize(calculator, fmax, **kwargs)
|
469
|
+
# conf.optimize() updates coordinates and conf.props:
|
470
|
+
# `E_tot_init(kcal/mol)`, `E_tot(kcal/mol)`, `Converged`.
|
471
|
+
data['angle'].append(conf.props['angle'])
|
472
|
+
data['init'].append(conf.props['E_tot_init(kcal/mol)'])
|
473
|
+
data['last'].append(conf.props['E_tot(kcal/mol)'])
|
474
|
+
data['Converged'].append(conf.props['Converged'])
|
475
|
+
|
476
|
+
# Post-processing
|
477
|
+
if use_converged_only:
|
478
|
+
data['angle'] = list(itertools.compress(data['angle'], data['Converged']))
|
479
|
+
data['init' ] = list(itertools.compress(data['init' ], data['Converged']))
|
480
|
+
data['last' ] = list(itertools.compress(data['last' ], data['Converged']))
|
481
|
+
|
482
|
+
relax = np.array(data['init']) - np.median(data['last'])
|
483
|
+
E_rel = relax - np.min(relax)
|
484
|
+
|
485
|
+
torsion_energy_profile = {
|
486
|
+
'indices' : data['indices'],
|
487
|
+
'angle' : np.round(np.array(data['angle']), 1).tolist(), # np.ndarray -> list for serialization
|
488
|
+
'E_rel(kcal/mol)': np.round(E_rel, 2).tolist(), # np.ndarray -> list for serialization
|
489
|
+
}
|
490
|
+
|
491
|
+
if simplify:
|
492
|
+
torsion_energy_profile.update({
|
493
|
+
'frag' : data.get('frag', None),
|
494
|
+
'frag_indices' : data.get('frag_indices', None),
|
495
|
+
})
|
496
|
+
|
497
|
+
self.props['torsion'] = torsion_energy_profile
|
498
|
+
self.props['torsion_calculator'] = str(calculator)
|
499
|
+
|
500
|
+
return self
|
501
|
+
|
502
|
+
|
503
|
+
|
405
504
|
def torsion_energies(self,
|
406
505
|
calculator: str | Callable,
|
407
506
|
torsion_key: int | None = None,
|
@@ -427,80 +526,23 @@ class Conf:
|
|
427
526
|
Self: modified self.
|
428
527
|
"""
|
429
528
|
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
torsion_atoms_indices = {torsion_key: self.torsion_atoms()[torsion_key]}
|
435
|
-
|
436
|
-
ref_conf = self.copy()
|
437
|
-
|
438
|
-
data = {}
|
529
|
+
torsion_atoms_dict = self.torsion_atoms() # {0: (5, 4, 3, 1)}
|
530
|
+
if (torsion_key is not None) and torsion_atoms_dict.get(torsion_key):
|
531
|
+
torsion_atoms_dict = {torsion_key: torsion_atoms_dict.get(torsion_key)}
|
532
|
+
# single torsion angle atom indices
|
439
533
|
|
440
|
-
|
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
|
534
|
+
conf = self.copy()
|
462
535
|
|
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
536
|
torsion_energy_profiles = {}
|
489
|
-
for tk,
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
torsion_energy_profiles[tk] =
|
497
|
-
|
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
|
-
|
537
|
+
for tk, indices in torsion_atoms_dict.items():
|
538
|
+
conf = conf.torsion_energies_one(calculator,
|
539
|
+
indices,
|
540
|
+
simplify,
|
541
|
+
fmax,
|
542
|
+
interval,
|
543
|
+
use_converged_only)
|
544
|
+
torsion_energy_profiles[tk] = conf.props['torsion']
|
545
|
+
|
504
546
|
self.props['torsion'] = torsion_energy_profiles
|
505
547
|
self.props['torsion_calculator'] = str(calculator)
|
506
548
|
|
@@ -539,7 +581,7 @@ class Conf:
|
|
539
581
|
return json.dumps(self.props)
|
540
582
|
|
541
583
|
|
542
|
-
def serialize(self, decimals: int = 3) -> str:
|
584
|
+
def serialize(self, decimals: int = 3, compressed: bool = False) -> str:
|
543
585
|
"""Serialize information necessary to rebuild a Conf object.
|
544
586
|
Args:
|
545
587
|
decimals (int, optional): number of decimal places for float data type. Defaults to 3.
|
@@ -548,16 +590,21 @@ class Conf:
|
|
548
590
|
str: serialized string for json.loads()
|
549
591
|
"""
|
550
592
|
serialized = json.dumps({
|
551
|
-
'name' : self.name,
|
552
|
-
'natoms': self.natoms,
|
593
|
+
'name' : self.name,
|
594
|
+
'natoms': self.natoms,
|
595
|
+
'charge': self.charge,
|
596
|
+
'spin': self.spin,
|
553
597
|
'props' : recursive_round(self.props, decimals),
|
554
598
|
'molblock' : self.to_molblock(),
|
555
599
|
})
|
556
600
|
|
601
|
+
if compressed:
|
602
|
+
serialized = compress_string(serialized)
|
603
|
+
|
557
604
|
return serialized
|
558
605
|
|
559
606
|
|
560
|
-
def deserialize(self, serialized: str) -> Self:
|
607
|
+
def deserialize(self, serialized: str, compressed: bool = False) -> Self:
|
561
608
|
"""De-serialize information and rebuild a Conf object.
|
562
609
|
|
563
610
|
Example:
|
@@ -570,19 +617,27 @@ class Conf:
|
|
570
617
|
Returns:
|
571
618
|
Self: modified self.
|
572
619
|
"""
|
620
|
+
if compressed:
|
621
|
+
serialized = decompress_string(serialized)
|
622
|
+
|
573
623
|
data = json.loads(serialized)
|
574
624
|
|
575
625
|
self.name = data['name']
|
576
|
-
self.natoms = data['natoms']
|
626
|
+
self.natoms = int(data['natoms'])
|
627
|
+
self.charge = int(data['charge'])
|
628
|
+
self.spin = int(data['spin'])
|
577
629
|
self.props = data['props']
|
578
630
|
self.rdmol = Chem.MolFromMolBlock(data['molblock'], sanitize=False, removeHs=False)
|
579
631
|
|
580
632
|
return self
|
581
633
|
|
582
634
|
|
583
|
-
def to_molblock(self) -> str:
|
635
|
+
def to_molblock(self, compressed: bool = False) -> str:
|
584
636
|
"""Returns MolBlock"""
|
585
|
-
|
637
|
+
molblock = Chem.MolToMolBlock(self.rdmol)
|
638
|
+
if compressed:
|
639
|
+
molblock = compress_string(molblock)
|
640
|
+
return molblock
|
586
641
|
|
587
642
|
|
588
643
|
def to_xyz(self) -> str:
|
rdworks/mol.py
CHANGED
@@ -37,7 +37,7 @@ from rdworks.std import generate_inchi_key, desalt_smiles, standardize, clean_2d
|
|
37
37
|
from rdworks.xml import list_predefined_xml, get_predefined_xml, parse_xml
|
38
38
|
from rdworks.scaffold import rigid_fragment_indices
|
39
39
|
from rdworks.descriptor import rd_descriptor, rd_descriptor_f
|
40
|
-
from rdworks.utils import convert_tril_to_symm, QT, recursive_round
|
40
|
+
from rdworks.utils import convert_tril_to_symm, QT, recursive_round, compress_string, decompress_string
|
41
41
|
from rdworks.units import ev2kcalpermol
|
42
42
|
from rdworks.autograph import NMRCLUST, DynamicTreeCut, RCKmeans, AutoGraph
|
43
43
|
from rdworks.bitqt import BitQT
|
@@ -83,17 +83,18 @@ class Mol:
|
|
83
83
|
"""
|
84
84
|
assert isinstance(molecule, str | Chem.Mol | Conf) or molecule is None
|
85
85
|
|
86
|
+
self.name = ''
|
86
87
|
self.rdmol = None # 2D, one and only one Conformer
|
87
88
|
self.smiles = '' # isomeric SMILES
|
88
89
|
self.confs = [] # container for 3D conformers
|
89
|
-
self.name = ''
|
90
90
|
self.InChIKey = '' # 27 characters (SHA-256 hash of InChI)
|
91
|
-
self.InChI = ''
|
92
91
|
self.props = {}
|
93
|
-
|
92
|
+
|
94
93
|
self.max_workers = max_workers
|
95
94
|
self.chunksize = chunksize
|
96
95
|
self.progress = progress
|
96
|
+
|
97
|
+
self.fp = None
|
97
98
|
|
98
99
|
if molecule is None:
|
99
100
|
return
|
@@ -1557,7 +1558,7 @@ class Mol:
|
|
1557
1558
|
return json.dumps(props)
|
1558
1559
|
|
1559
1560
|
|
1560
|
-
def serialize(self, decimals: int = 2) -> str:
|
1561
|
+
def serialize(self, decimals: int = 2, compressed: bool = False) -> str:
|
1561
1562
|
"""Serialize information necessary to rebuild a Mol object.
|
1562
1563
|
|
1563
1564
|
Args:
|
@@ -1569,14 +1570,18 @@ class Mol:
|
|
1569
1570
|
serialized = json.dumps({
|
1570
1571
|
'name' : self.name,
|
1571
1572
|
'smiles': self.smiles,
|
1573
|
+
'InChIKey': self.InChIKey,
|
1572
1574
|
'props' : recursive_round(self.props, decimals),
|
1573
1575
|
'confs' : [conf.serialize() for conf in self.confs],
|
1574
1576
|
})
|
1575
1577
|
|
1578
|
+
if compressed:
|
1579
|
+
serialized = compress_string(serialized)
|
1580
|
+
|
1576
1581
|
return serialized
|
1577
1582
|
|
1578
1583
|
|
1579
|
-
def deserialize(self, serialized: str) -> Self:
|
1584
|
+
def deserialize(self, serialized: str, compressed: bool = False) -> Self:
|
1580
1585
|
"""De-serialize the information and build a new Mol object.
|
1581
1586
|
|
1582
1587
|
Example:
|
@@ -1589,13 +1594,16 @@ class Mol:
|
|
1589
1594
|
Returns:
|
1590
1595
|
Self: modified self.
|
1591
1596
|
"""
|
1597
|
+
if compressed:
|
1598
|
+
serialized = decompress_string(serialized)
|
1599
|
+
|
1592
1600
|
data = json.loads(serialized)
|
1593
1601
|
|
1594
1602
|
self.name = data['name']
|
1595
1603
|
self.smiles = data['smiles'] # isomeric SMILES, no H
|
1596
1604
|
self.rdmol = Chem.MolFromSmiles(data['smiles']) # for 2D depiction
|
1597
1605
|
self.rdmol.SetProp('_Name', self.name)
|
1598
|
-
self.InChIKey =
|
1606
|
+
self.InChIKey = data['InChIKey']
|
1599
1607
|
self.props = data['props']
|
1600
1608
|
self.confs = [Conf().deserialize(_) for _ in data['confs']] # for 3D conformers (iterable)
|
1601
1609
|
|
rdworks/testdata.py
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
drugs = {
|
2
|
+
'Acetaminophen': 'CC(=O)Nc1ccc(O)cc1',
|
3
|
+
'Aspirin': 'CC(=O)OC1=CC=CC=C1C(=O)O',
|
4
|
+
'Atorvastatin': 'CC(C)C1=C(C(=C(N1CC[C@H](C[C@H](CC(=O)O)O)O)C2=CC=C(C=C2)F)C3=CC=CC=C3)C(=O)NC4=CC=CC=C4',
|
5
|
+
'Atovaquone': 'C1CC(CCC1C2=CC=C(C=C2)Cl)C3=C(C4=CC=CC=C4C(=O)C3=O)O',
|
6
|
+
'Cefdinir': 'C=CC1=C(N2[C@@H]([C@@H](C2=O)NC(=O)/C(=N\\O)/C3=CSC(=N3)N)SC1)C(=O)O',
|
7
|
+
'Chlorprothixene': 'CN(CC/C=C1C2=CC=CC=C2SC3=C/1C=C(Cl)C=C3)C',
|
8
|
+
'Cimetidine': 'CC1=C(N=CN1)CSCCNC(=NC)NC#N',
|
9
|
+
'Clomipramine': 'CN(C)CCCN1C2=CC=CC=C2CCC3=C1C=C(C=C3)Cl',
|
10
|
+
'Ethopropazine': 'CCN(CC)C(C)CN1C2=CC=CC=C2SC3=CC=CC=C31',
|
11
|
+
'Famotidine': 'C1=C(N=C(S1)N=C(N)N)CSCC/C(=N/S(=O)(=O)N)/N',
|
12
|
+
'Fluconazole': 'C1=CC(=C(C=C1F)F)C(CN2C=NC=N2)(CN3C=NC=N3)O',
|
13
|
+
'Granisetron': 'CN1[C@@H]2CCC[C@H]1CC(C2)NC(=O)C3=NN(C4=CC=CC=C43)C',
|
14
|
+
'Leflunomide': 'CC1=C(C=NO1)C(=O)NC2=CC=C(C=C2)C(F)(F)F',
|
15
|
+
'Linezolid': 'CC(=O)NC[C@H]1CN(C(=O)O1)C2=CC(=C(C=C2)N3CCOCC3)F',
|
16
|
+
'Methixene': 'CN1CCCC(C1)CC2C3=CC=CC=C3SC4=CC=CC=C24',
|
17
|
+
'Molindone': 'CCC1=C(NC2=C1C(=O)C(CC2)CN3CCOCC3)C',
|
18
|
+
'Paroxetine': 'C1CNC[C@H]([C@@H]1C2=CC=C(C=C2)F)COC3=CC4=C(C=C3)OCO4',
|
19
|
+
'Pergolide': 'CCCN1C[C@@H](C[C@H]2[C@H]1CC3=CNC4=CC=CC2=C34)CSC',
|
20
|
+
'Rifampin': 'C[C@H]1/C=C/C=C(\\C(=O)NC2=C(C(=C3C(=C2O)C(=C(C4=C3C(=O)[C@](O4)(O/C=C/[C@@H]([C@H]([C@H]([C@@H]([C@@H]([C@@H]([C@H]1O)C)O)C)OC(=O)C)C)OC)C)C)O)O)/C=N/N5CCN(CC5)C)/C',
|
21
|
+
'Simvastatin': 'O=C(O[C@@H]1[C@H]3C(=C/[C@H](C)C1)\\C=C/[C@@H]([C@@H]3CC[C@H]2OC(=O)C[C@H](O)C2)C)C(C)(C)CC',
|
22
|
+
'Sitagliptin': 'Fc1cc(c(F)cc1F)C[C@@H](N)CC(=O)N3Cc2nnc(n2CC3)C(F)(F)F',
|
23
|
+
'Sofosbuvir': 'C[C@@H](C(OC(C)C)=O)N[P@](OC[C@@H]1[C@H]([C@@](F)([C@@H](O1)N2C=CC(NC2=O)=O)C)O)(OC3=CC=CC=C3)=O',
|
24
|
+
}
|
rdworks/utils.py
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
import numpy as np
|
2
2
|
import math
|
3
3
|
import operator
|
4
|
+
import gzip
|
5
|
+
import base64
|
4
6
|
|
5
7
|
from pathlib import Path
|
6
8
|
from types import SimpleNamespace
|
@@ -14,6 +16,33 @@ from rdkit import Chem
|
|
14
16
|
from rdworks.autograph.centroid import centroid_medoid
|
15
17
|
|
16
18
|
|
19
|
+
def compress_string(text: str) -> str:
|
20
|
+
"""compress string to base64-encoded string.
|
21
|
+
|
22
|
+
Args:
|
23
|
+
text (str): original string.
|
24
|
+
|
25
|
+
Returns:
|
26
|
+
str: base64-encoded compressed string.
|
27
|
+
"""
|
28
|
+
compressed_bytes = gzip.compress(text.encode('utf-8'))
|
29
|
+
return base64.b64encode(compressed_bytes).decode('utf-8')
|
30
|
+
|
31
|
+
|
32
|
+
def decompress_string(compressed_text: str) -> str:
|
33
|
+
"""decompress base64-encoded string to original string.
|
34
|
+
|
35
|
+
Args:
|
36
|
+
compressed_text (str): base64-encoded compressed string.
|
37
|
+
|
38
|
+
Returns:
|
39
|
+
str: original string.
|
40
|
+
"""
|
41
|
+
compressed_bytes = base64.b64decode(compressed_text)
|
42
|
+
decompressed_text = gzip.decompress(compressed_bytes).decode('utf-8')
|
43
|
+
return decompressed_text
|
44
|
+
|
45
|
+
|
17
46
|
def compute(fn:Callable, largs: list, **kwargs) -> list:
|
18
47
|
max_workers = kwargs.get('max_workers', 1)
|
19
48
|
chunksize = kwargs.get('chunksize', 10)
|
@@ -1,10 +1,10 @@
|
|
1
|
-
rdworks/__init__.py,sha256=
|
2
|
-
rdworks/conf.py,sha256=
|
1
|
+
rdworks/__init__.py,sha256=u0oNboUCvBT6mkw6z5qRQiMVr-aglMbFITjb7Ut-DEM,1368
|
2
|
+
rdworks/conf.py,sha256=vMKVaHKvlPQ87CNfROodzwZ7l9h-tFCs8MGwon6_sJU,30823
|
3
3
|
rdworks/descriptor.py,sha256=34T_dQ6g8v3u-ym8TLKbQtxIIV5TEo-d3pdedq3o-cg,2106
|
4
4
|
rdworks/display.py,sha256=JR0gR26UpH-JCxVOaqXZCUj2MiGZSrx9Me87FncspVI,13469
|
5
5
|
rdworks/ionized.py,sha256=5oIjMRpkX792RIpEEE2Ir96icfFaN_h21mSihhfQPAw,6713
|
6
6
|
rdworks/matchedseries.py,sha256=A3ON4CUpQV159mu9VqgNiJ8uoQ9ePOry9d3ra4NCAgc,10377
|
7
|
-
rdworks/mol.py,sha256=
|
7
|
+
rdworks/mol.py,sha256=JC1IHM6mw9uap_uV3i5d6ZAnZqA1kcyOnvwB6lgH4xA,68070
|
8
8
|
rdworks/mollibr.py,sha256=X4UBO6Ga-QmNS7RwUiaDYAx0Q5hnWs71yTkEpH02Qb4,37696
|
9
9
|
rdworks/pka.py,sha256=NVJVfpcNEMlX5QRyLBgUM7GIT7VMjO-llAR4LWc8J2c,1656
|
10
10
|
rdworks/readin.py,sha256=0bnVcZcAmSLqc6zu1mYcv0LdBv2agQfOpKGwpSRL9VE,11742
|
@@ -13,9 +13,10 @@ rdworks/scaffold.py,sha256=60T5YacyxZsEpDo_J5Qxulm2YNQO4EQR8PcNUwjn1QU,22026
|
|
13
13
|
rdworks/std.py,sha256=qOVS_lGogueLKh4rsbrsYIMR0c7z_xh6BqLEzD4X9sE,7938
|
14
14
|
rdworks/stereoisomers.py,sha256=g8hhPI-mbYX-MzbF1uAqo5fDZOCNiKYjxI-kLBGdGgg,4980
|
15
15
|
rdworks/tautomers.py,sha256=gtZHZJ-aJbryhBdljHbfjx7xhVW3u_OzdYPtwPail54,610
|
16
|
+
rdworks/testdata.py,sha256=TmbNPA-ju6nTBt_Yts4EJUFmL9Cd6DCVXrDF42QLlHw,1732
|
16
17
|
rdworks/torsion.py,sha256=qTRJWsxSktqprL8pUHWEOoV2dKEgoMozh3BB0eGNlZ8,18571
|
17
18
|
rdworks/units.py,sha256=nljKPHcr6IWoAp0CkL7y1gSNDd6a07NeVfxXwSMuHQM,365
|
18
|
-
rdworks/utils.py,sha256=
|
19
|
+
rdworks/utils.py,sha256=d2Sio8WTlGPsmBOHIYDCMWg_7X4rTWjJQAqzd7ywo2A,14191
|
19
20
|
rdworks/xml.py,sha256=aaMhwVRGvt1VzasaKDnkYnZ4kp2cIgvGb1CsmMgwQ_c,10704
|
20
21
|
rdworks/autograph/__init__.py,sha256=0Qfjwo0h4Q0n08zsqHRbuNOZms6MuNXnWErnQpQ6Px0,140
|
21
22
|
rdworks/autograph/autograph.py,sha256=frjsUaCTOD-Z1lYPzOxRoTtqMMiYroWAy6tSwKn3CUA,8769
|
@@ -65,8 +66,8 @@ rdworks/predefined/misc/reactive-part-3.xml,sha256=LgWHSEbRTVmgBoIO45xbTo1xQJs0X
|
|
65
66
|
rdworks/predefined/misc/reactive.xml,sha256=syedoQ6VYUfRLnxy99ObuDniJ_a_WhrWAJbTKFfJ6VY,11248
|
66
67
|
rdworks/xtb/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
67
68
|
rdworks/xtb/wrapper.py,sha256=I0nW89vlJZ5Za5pCjIpjsEOFbTm7HpeNGiPgssheWn8,11350
|
68
|
-
rdworks-0.
|
69
|
-
rdworks-0.
|
70
|
-
rdworks-0.
|
71
|
-
rdworks-0.
|
72
|
-
rdworks-0.
|
69
|
+
rdworks-0.40.1.dist-info/licenses/LICENSE,sha256=UOkJSBqYyQUvtCp7a-vdCANeEcLE2dnTie_eB1By5SY,1074
|
70
|
+
rdworks-0.40.1.dist-info/METADATA,sha256=ksYcRcoRSez6WZGRR-0mEMLWk0aO_A3fvK3QVHcHEpw,1183
|
71
|
+
rdworks-0.40.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
72
|
+
rdworks-0.40.1.dist-info/top_level.txt,sha256=05C98HbvBK2axUBogC_hAT_CdpOeQYGnQ6vRAgawr8s,8
|
73
|
+
rdworks-0.40.1.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|