rdworks 0.25.7__py3-none-any.whl → 0.35.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 +19 -20
- rdworks/conf.py +308 -117
- rdworks/display.py +244 -83
- rdworks/mol.py +621 -493
- rdworks/mollibr.py +336 -182
- rdworks/readin.py +2 -4
- rdworks/scaffold.py +1 -1
- rdworks/std.py +64 -24
- rdworks/torsion.py +477 -0
- rdworks/units.py +7 -58
- rdworks/utils.py +141 -258
- rdworks/xtb/__init__.py +0 -0
- rdworks/xtb/wrapper.py +304 -0
- {rdworks-0.25.7.dist-info → rdworks-0.35.1.dist-info}/METADATA +7 -10
- {rdworks-0.25.7.dist-info → rdworks-0.35.1.dist-info}/RECORD +18 -15
- {rdworks-0.25.7.dist-info → rdworks-0.35.1.dist-info}/WHEEL +1 -1
- {rdworks-0.25.7.dist-info → rdworks-0.35.1.dist-info}/licenses/LICENSE +0 -0
- {rdworks-0.25.7.dist-info → rdworks-0.35.1.dist-info}/top_level.txt +0 -0
rdworks/__init__.py
CHANGED
@@ -1,35 +1,34 @@
|
|
1
|
-
__version__ = '0.
|
1
|
+
__version__ = '0.35.1'
|
2
|
+
|
3
|
+
from rdworks.conf import Conf
|
4
|
+
from rdworks.mol import Mol
|
5
|
+
from rdworks.mollibr import MolLibr
|
2
6
|
|
3
|
-
from rdworks.xml import list_predefined_xml, get_predefined_xml, parse_xml
|
4
|
-
from rdworks.units import ev2kcalpermol, hartree2ev, hartree2kcalpermol, periodictable
|
5
|
-
from rdworks.readin import read_csv, merge_csv, read_dataframe, read_smi, read_sdf, read_mae
|
6
|
-
from rdworks.std import desalt_smiles, standardize_smiles, standardize
|
7
|
-
from rdworks.tautomers import complete_tautomers
|
8
7
|
from rdworks.stereoisomers import complete_stereoisomers
|
8
|
+
from rdworks.tautomers import complete_tautomers
|
9
9
|
from rdworks.ionized import IonizedStates
|
10
|
+
|
11
|
+
from rdworks.readin import read_csv, merge_csv, read_dataframe, read_smi, read_sdf, read_mae
|
12
|
+
from rdworks.std import desalt_smiles, standardize_smiles, standardize
|
13
|
+
|
10
14
|
from rdworks.rgroup import expand_rgroup, most_common, most_common_in_NP
|
11
15
|
from rdworks.scaffold import scaffold_network, scaffold_tree, BRICS_fragmented, BRICS_fragment_indices
|
12
16
|
from rdworks.matchedseries import MatchedSeries
|
13
|
-
from rdworks.descriptor import rd_descriptor, rd_descriptor_f
|
14
|
-
from rdworks.utils import fix_decimal_places_in_list, fix_decimal_places_in_dict, mae_to_dict, mae_rd_index
|
15
|
-
from rdworks.display import svg
|
16
|
-
from rdworks.conf import Conf
|
17
|
-
from rdworks.mol import Mol
|
18
|
-
from rdworks.mollibr import MolLibr
|
19
17
|
|
20
|
-
from
|
21
|
-
|
18
|
+
from rdworks.descriptor import rd_descriptor, rd_descriptor_f
|
19
|
+
from rdworks.xml import list_predefined_xml, get_predefined_xml, parse_xml
|
22
20
|
|
21
|
+
import rdkit
|
23
22
|
import logging
|
24
23
|
|
24
|
+
__rdkit_version__ = rdkit.rdBase.rdkitVersion
|
25
|
+
|
26
|
+
rdkit_logger = rdkit.RDLogger.logger().setLevel(rdkit.RDLogger.CRITICAL)
|
27
|
+
|
25
28
|
main_logger = logging.getLogger()
|
26
29
|
main_logger.setLevel(logging.INFO) # level: DEBUG < INFO < WARNING < ERROR < CRITICAL
|
27
|
-
logger_formatter = logging.Formatter(
|
28
|
-
|
29
|
-
datefmt='%Y-%m-%d %H:%M:%S')
|
30
|
+
logger_formatter = logging.Formatter(fmt='%(asctime)s %(levelname)s %(message)s',
|
31
|
+
datefmt='%Y-%m-%d %H:%M:%S')
|
30
32
|
logger_ch = logging.StreamHandler()
|
31
33
|
logger_ch.setFormatter(logger_formatter)
|
32
34
|
main_logger.addHandler(logger_ch)
|
33
|
-
|
34
|
-
|
35
|
-
__rdkit_version__ = rdBase.rdkitVersion
|
rdworks/conf.py
CHANGED
@@ -1,46 +1,69 @@
|
|
1
1
|
import io
|
2
2
|
import copy
|
3
3
|
import json
|
4
|
-
import types
|
5
4
|
import numpy as np
|
6
|
-
|
7
5
|
import ase
|
8
|
-
from ase.optimize import FIRE
|
9
6
|
|
10
7
|
from collections.abc import Callable
|
8
|
+
from typing import Self
|
9
|
+
|
10
|
+
from mendeleev import element
|
11
|
+
from ase.optimize import FIRE
|
11
12
|
|
12
13
|
from rdkit import Chem
|
13
14
|
from rdkit.Chem import rdMolTransforms, AllChem, rdMolAlign
|
14
15
|
from rdkit.Chem.Draw import rdMolDraw2D
|
16
|
+
from PIL import Image
|
15
17
|
|
16
|
-
from
|
18
|
+
from rdworks.units import ev2kcalpermol, pm2angstrom
|
19
|
+
from rdworks.utils import recursive_round
|
20
|
+
from rdworks.xtb.wrapper import GFN2xTB
|
21
|
+
from rdworks.display import render_png, render_svg
|
17
22
|
|
18
|
-
from .units import ev2kcalpermol
|
19
|
-
from .element import radii
|
20
23
|
|
21
24
|
class Conf:
|
22
|
-
"""Container for 3D conformers.
|
23
|
-
"""
|
25
|
+
"""Container for 3D conformers."""
|
24
26
|
|
25
|
-
def __init__(self,
|
26
|
-
"""
|
27
|
+
def __init__(self, molecule: str | Chem.Mol | None = None, name: str='') -> None:
|
28
|
+
"""Initialize.
|
27
29
|
|
28
30
|
Args:
|
29
|
-
|
30
|
-
name (str
|
31
|
+
molecule (Chem.Mol | MolBlock string): Molecule for 3D conformer.
|
32
|
+
name (str): Name prefix of the generated conformers. Defaults to ''.
|
31
33
|
|
32
34
|
Raises:
|
33
|
-
ValueError: if `
|
35
|
+
ValueError: if `molecule` is not rdkit.Chem.Mol object.
|
34
36
|
"""
|
35
|
-
|
37
|
+
assert isinstance(molecule, str | Chem.Mol) or molecule is None
|
38
|
+
|
39
|
+
self.rdmol = None # must contain one and only one rdkit conformer
|
36
40
|
self.name = name
|
41
|
+
self.natoms = 0
|
37
42
|
self.props = {}
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
43
|
+
|
44
|
+
if molecule is None:
|
45
|
+
return
|
46
|
+
|
47
|
+
if isinstance(molecule, str): # 3-D MolBLock string
|
48
|
+
try:
|
49
|
+
self.rdmol = Chem.MolFromMolBlock(molecule)
|
50
|
+
except:
|
51
|
+
ValueError(f'Conf() Error: invalid MolBlock string')
|
52
|
+
|
53
|
+
elif isinstance(molecule, Chem.Mol): # 3-D
|
54
|
+
try:
|
55
|
+
self.rdmol = molecule
|
56
|
+
except:
|
57
|
+
ValueError(f'Conf() Error: invalid Chem.Mol object')
|
58
|
+
|
59
|
+
num_atoms = self.rdmol.GetNumAtoms()
|
60
|
+
tot_atoms = self.rdmol.GetNumAtoms(onlyExplicit=False)
|
61
|
+
assert num_atoms == tot_atoms, "Conf() Error: missing hydrogens"
|
62
|
+
self.natoms = num_atoms
|
63
|
+
self.props.update({'atoms': num_atoms})
|
64
|
+
|
65
|
+
assert self.rdmol.GetConformer().Is3D(), "Conf() Error: not 3D"
|
66
|
+
|
44
67
|
|
45
68
|
|
46
69
|
def __str__(self) -> str:
|
@@ -50,12 +73,7 @@ class Conf:
|
|
50
73
|
str: string representation.
|
51
74
|
"""
|
52
75
|
return f"<rdworks.Conf({self.rdmol} name={self.name} atoms={self.natoms})>"
|
53
|
-
|
54
|
-
|
55
|
-
##################################################
|
56
|
-
### Cascading methods
|
57
|
-
##################################################
|
58
|
-
|
76
|
+
|
59
77
|
|
60
78
|
def copy(self) -> Self:
|
61
79
|
"""Returns a copy of self.
|
@@ -85,7 +103,7 @@ class Conf:
|
|
85
103
|
return self
|
86
104
|
|
87
105
|
|
88
|
-
def sync(self, coord:
|
106
|
+
def sync(self, coord: np.ndarray | list) -> Self:
|
89
107
|
"""Synchronize the conformer coordinates with the provided `coord`.
|
90
108
|
|
91
109
|
Args:
|
@@ -107,56 +125,31 @@ class Conf:
|
|
107
125
|
return self
|
108
126
|
|
109
127
|
|
110
|
-
def
|
111
|
-
"""
|
128
|
+
def set_torsion(self, i:int, j:int, k:int, l:int, degree:float) -> Self:
|
129
|
+
"""Set dihedral angle (i-j-k-l) in degrees.
|
112
130
|
|
113
131
|
Args:
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
bending and dihedral torsions to favor planar geometries for specific nitrogen atoms.
|
120
|
-
This makes it better suited for geometry optimization studies where a static,
|
121
|
-
time-averaged structure is desired. The "s" stands for "static".
|
122
|
-
`UFF` - UFF refers to the "Universal Force Field," a force field model used for
|
123
|
-
molecular mechanics calculations. It's a tool for geometry optimization,
|
124
|
-
energy minimization, and exploring molecular conformations in 3D space.
|
125
|
-
UFF is often used to refine conformers generated by other methods,
|
126
|
-
such as random conformer generation, to produce more physically plausible
|
127
|
-
and stable structures.
|
132
|
+
i (int): atom index
|
133
|
+
j (int): atom index
|
134
|
+
k (int): atom index
|
135
|
+
l (int): atom index
|
136
|
+
degree (float): dihedral angle in degrees
|
128
137
|
|
129
138
|
Returns:
|
130
|
-
|
139
|
+
Self: modified Conf object
|
131
140
|
"""
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
mp = AllChem.MMFFGetMoleculeProperties(self.rdmol, mmffVariant='MMFF94')
|
136
|
-
ff = AllChem.MMFFGetMoleculeForceField(self.rdmol, mp)
|
137
|
-
elif calculator == 'MMFF94s':
|
138
|
-
mp = AllChem.MMFFGetMoleculeProperties(self.rdmol, mmffVariant='MMFF94s')
|
139
|
-
ff = AllChem.MMFFGetMoleculeForceField(self.rdmol, mp)
|
140
|
-
elif calculator == 'UFF':
|
141
|
-
ff = AllChem.UFFGetMoleculeForceField(self.rdmol)
|
142
|
-
else:
|
143
|
-
raise ValueError("Unsupported calculator")
|
144
|
-
PE = ff.CalcEnergy()
|
145
|
-
self.props.update({'E_tot(kcal/mol)': PE})
|
146
|
-
else:
|
147
|
-
try:
|
148
|
-
ase_atoms = ase.Atoms(symbols=self.symbols(), positions=self.positions())
|
149
|
-
ase_atoms.calc = calculator
|
150
|
-
PE = ase_atoms.get_potential_energy() # np.array
|
151
|
-
PE = ev2kcalpermol * float(PE[0]) # np.float64 to float
|
152
|
-
self.props.update({'E_tot(kcal/mol)': PE})
|
153
|
-
except:
|
154
|
-
raise RuntimeError("ASE calculator error")
|
155
|
-
return PE
|
141
|
+
rdMolTransforms.SetDihedralDeg(self.rdmol.GetConformer(), i, j, k, l, degree)
|
142
|
+
|
143
|
+
return self
|
156
144
|
|
157
145
|
|
158
|
-
|
159
|
-
|
146
|
+
|
147
|
+
def optimize(self,
|
148
|
+
calculator: str | Callable = 'MMFF94',
|
149
|
+
fmax:float=0.05,
|
150
|
+
max_iter:int=1000,
|
151
|
+
**kwargs) -> Self:
|
152
|
+
"""Optimize 3D geometry.
|
160
153
|
|
161
154
|
Args:
|
162
155
|
calculator (str | Callable): MMFF94 (= MMFF), MMFF94s, UFF, or ASE calculator.
|
@@ -173,31 +166,52 @@ class Conf:
|
|
173
166
|
UFF is often used to refine conformers generated by other methods,
|
174
167
|
such as random conformer generation, to produce more physically plausible
|
175
168
|
and stable structures.
|
176
|
-
fmax (float, optional): fmax for the calculator. Defaults to 0.05.
|
169
|
+
fmax (float, optional): fmax for the calculator convergence. Defaults to 0.05.
|
170
|
+
max_iter (int, optional): max iterations for the calculator. Defaults to 1000.
|
171
|
+
|
172
|
+
Args for xTB:
|
173
|
+
water (str, optional): water solvation model (choose 'gbsa' or 'alpb')
|
174
|
+
alpb: ALPB solvation model (Analytical Linearized Poisson-Boltzmann).
|
175
|
+
gbsa: generalized Born (GB) model with Surface Area contributions.
|
177
176
|
|
178
177
|
Returns:
|
179
178
|
Self: self
|
180
179
|
"""
|
181
180
|
if isinstance(calculator, str) :
|
182
|
-
|
183
|
-
|
184
|
-
|
181
|
+
|
182
|
+
PE_start = self.potential_energy(calculator)
|
183
|
+
|
184
|
+
if calculator.lower() == 'xTB'.lower():
|
185
|
+
water = kwargs.get('water', None)
|
186
|
+
PE_final, self.rdmol = GFN2xTB(self.rdmol).optimize(water=water)
|
187
|
+
|
188
|
+
elif calculator.lower() == 'MMFF94'.lower() or calculator.lower() == 'MMFF'.lower():
|
189
|
+
retcode = Chem.rdForceFieldHelpers.MMFFOptimizeMolecule(self.rdmol,
|
190
|
+
mmffVariant='MMFF94',
|
191
|
+
maxIters=max_iter)
|
185
192
|
# returns 0 if the optimization converged
|
186
|
-
elif calculator == 'MMFF94s':
|
187
|
-
retcode =
|
193
|
+
elif calculator.lower() == 'MMFF94s'.lower():
|
194
|
+
retcode = Chem.rdForceFieldHelpers.MMFFOptimizeMolecule(self.rdmol,
|
195
|
+
mmffVariant='MMFF94s',
|
196
|
+
maxIters=max_iter)
|
188
197
|
# returns 0 if the optimization converged
|
189
|
-
elif calculator == 'UFF':
|
190
|
-
retcode =
|
198
|
+
elif calculator.lower() == 'UFF'.lower():
|
199
|
+
retcode = Chem.rdForceFieldHelpers.UFFOptimizeMolecule(self.rdmol,
|
200
|
+
maxIters=max_iter)
|
191
201
|
# returns 0 if the optimization converged
|
192
|
-
|
202
|
+
|
203
|
+
PE_final = self.potential_energy(calculator)
|
204
|
+
|
193
205
|
self.props.update({
|
194
|
-
'E_tot_init(kcal/mol)':
|
195
|
-
'E_tot(kcal/mol)':
|
206
|
+
'E_tot_init(kcal/mol)': PE_start , # energy before optimization
|
207
|
+
'E_tot(kcal/mol)': PE_final, # energy after optimization
|
196
208
|
'Converged' : retcode == 0, # True or False
|
197
209
|
})
|
210
|
+
|
198
211
|
return self
|
199
212
|
|
200
213
|
else:
|
214
|
+
# assuming ASE calculator
|
201
215
|
with io.StringIO() as logfile:
|
202
216
|
ase_atoms = ase.Atoms(symbols=self.symbols(), positions=self.positions())
|
203
217
|
ase_atoms.calc = calculator
|
@@ -209,9 +223,11 @@ class Conf:
|
|
209
223
|
'E_tot(kcal/mol)': data[-1][0] * ev2kcalpermol, # energy after optimization
|
210
224
|
'Converged' : data[-1][1] < fmax, # True or False
|
211
225
|
})
|
226
|
+
|
212
227
|
# update atomic coordinates
|
213
228
|
return self.sync(ase_atoms.get_positions())
|
214
229
|
|
230
|
+
|
215
231
|
|
216
232
|
##################################################
|
217
233
|
### Endpoint methods
|
@@ -233,13 +249,13 @@ class Conf:
|
|
233
249
|
idx2 = bond.GetEndAtomIdx()
|
234
250
|
nuc1 = self.rdmol.GetAtomWithIdx(idx1).GetAtomicNum()
|
235
251
|
nuc2 = self.rdmol.GetAtomWithIdx(idx2).GetAtomicNum()
|
236
|
-
sum_radii = (
|
252
|
+
sum_radii = (element(nuc1).vdw_radius + element(nuc2).vdw_radius) * pm2angstrom
|
237
253
|
bond_length = rdMolTransforms.GetBondLength(self.rdmol.GetConformer(), idx1, idx2)
|
238
254
|
if abs(bond_length - sum_radii) > tolerance:
|
239
255
|
return False
|
240
256
|
|
241
257
|
return True
|
242
|
-
|
258
|
+
|
243
259
|
|
244
260
|
def positions(self) -> np.array:
|
245
261
|
"""Returns the coordinates.
|
@@ -298,14 +314,94 @@ class Conf:
|
|
298
314
|
return np.sqrt(np.mean(b))
|
299
315
|
|
300
316
|
|
301
|
-
def
|
317
|
+
def potential_energy(self, calculator: str | Callable = 'MMFF94', **kwargs) -> float:
|
318
|
+
"""Get potential energy and set `E_tot(kcal/mol)` in the self.props.
|
319
|
+
|
320
|
+
Args:
|
321
|
+
calculator (str | Callable): MMFF94 (= MMFF), MMFF94s, UFF, or ASE calculator.
|
322
|
+
`MMFF94` or `MMFF` - Intended for general use, including organic molecules and proteins,
|
323
|
+
and primarily relies on data from quantum mechanical calculations.
|
324
|
+
It's often used in molecular dynamics simulations.
|
325
|
+
`MMFF94s` - A "static" variant of MMFF94, with adjusted parameters for out-of-plane
|
326
|
+
bending and dihedral torsions to favor planar geometries for specific nitrogen atoms.
|
327
|
+
This makes it better suited for geometry optimization studies where a static,
|
328
|
+
time-averaged structure is desired. The "s" stands for "static".
|
329
|
+
`UFF` - UFF refers to the "Universal Force Field," a force field model used for
|
330
|
+
molecular mechanics calculations. It's a tool for geometry optimization,
|
331
|
+
energy minimization, and exploring molecular conformations in 3D space.
|
332
|
+
UFF is often used to refine conformers generated by other methods,
|
333
|
+
such as random conformer generation, to produce more physically plausible
|
334
|
+
and stable structures.
|
335
|
+
|
336
|
+
Returns:
|
337
|
+
float | None: potential energy in kcal/mol or None.
|
338
|
+
"""
|
339
|
+
|
340
|
+
if isinstance(calculator, str):
|
341
|
+
if calculator.lower() == 'xTB'.lower():
|
342
|
+
water = kwargs.get('water', None)
|
343
|
+
PE = GFN2xTB(self.rdmol).singlepoint(water=water)
|
344
|
+
|
345
|
+
elif calculator.lower() == 'MMFF94'.lower() or calculator.lower() == 'MMFF'.lower():
|
346
|
+
mp = Chem.rdForceFieldHelpers.MMFFGetMoleculeProperties(self.rdmol, mmffVariant='MMFF94')
|
347
|
+
ff = Chem.rdForceFieldHelpers.MMFFGetMoleculeForceField(self.rdmol, mp)
|
348
|
+
PE = ff.CalcEnergy()
|
349
|
+
|
350
|
+
elif calculator.lower() == 'MMFF94s'.lower():
|
351
|
+
mp = Chem.rdForceFieldHelpers.MMFFGetMoleculeProperties(self.rdmol, mmffVariant='MMFF94s')
|
352
|
+
ff = Chem.rdForceFieldHelpers.MMFFGetMoleculeForceField(self.rdmol, mp)
|
353
|
+
PE = ff.CalcEnergy()
|
354
|
+
|
355
|
+
elif calculator.lower() == 'UFF'.lower():
|
356
|
+
ff = Chem.rdForceFieldHelpers.UFFGetMoleculeForceField(self.rdmol)
|
357
|
+
PE = ff.CalcEnergy()
|
358
|
+
|
359
|
+
else:
|
360
|
+
raise ValueError("Unsupported calculator")
|
361
|
+
|
362
|
+
self.props.update({'E_tot(kcal/mol)': PE})
|
363
|
+
|
364
|
+
return PE
|
365
|
+
|
366
|
+
else:
|
367
|
+
try:
|
368
|
+
ase_atoms = ase.Atoms(symbols=self.symbols(), positions=self.positions())
|
369
|
+
ase_atoms.calc = calculator
|
370
|
+
PE = ase_atoms.get_potential_energy() # np.array
|
371
|
+
PE = ev2kcalpermol * float(PE[0]) # np.float64 to float
|
372
|
+
self.props.update({'E_tot(kcal/mol)': PE})
|
373
|
+
|
374
|
+
return PE
|
375
|
+
|
376
|
+
except:
|
377
|
+
raise RuntimeError("ASE calculator error")
|
378
|
+
|
379
|
+
|
380
|
+
def torsion_angle(self, i:int, j:int, k:int, l:int) -> float:
|
381
|
+
"""Get dihedral angle (i-j-k-l) in degrees.
|
382
|
+
|
383
|
+
Args:
|
384
|
+
i (int): atom index
|
385
|
+
j (int): atom index
|
386
|
+
k (int): atom index
|
387
|
+
l (int): atom index
|
388
|
+
|
389
|
+
Returns:
|
390
|
+
float: dihedral angle in degrees.
|
391
|
+
"""
|
392
|
+
degree = rdMolTransforms.GetDihedralDeg(self.rdmol.GetConformer(), i, j, k, l)
|
393
|
+
|
394
|
+
return degree
|
395
|
+
|
396
|
+
|
397
|
+
def dumps(self, key:str='') -> str:
|
302
398
|
"""Returns JSON dumps of the `props`.
|
303
399
|
|
304
400
|
Args:
|
305
401
|
key (str): a key for the `props` dictionary. Defaults to '' (all).
|
306
402
|
|
307
403
|
Returns:
|
308
|
-
|
404
|
+
str: JSON dumps.
|
309
405
|
"""
|
310
406
|
if key:
|
311
407
|
return json.dumps({key:self.props[key]})
|
@@ -313,6 +409,59 @@ class Conf:
|
|
313
409
|
return json.dumps(self.props)
|
314
410
|
|
315
411
|
|
412
|
+
def serialize(self, decimals:int=3) -> str:
|
413
|
+
"""Serialize information necessary to rebuild.
|
414
|
+
|
415
|
+
Returns:
|
416
|
+
str: serialized string for json.loads()
|
417
|
+
"""
|
418
|
+
serialized = json.dumps({
|
419
|
+
'name' : self.name,
|
420
|
+
'natoms': self.natoms,
|
421
|
+
'props' : recursive_round(self.props, decimals),
|
422
|
+
'molblock' : self.to_molblock(),
|
423
|
+
})
|
424
|
+
|
425
|
+
return serialized
|
426
|
+
|
427
|
+
|
428
|
+
def deserialize(self, serialized:str) -> Self:
|
429
|
+
"""De-serialize information and rebuild.
|
430
|
+
|
431
|
+
Args:
|
432
|
+
serialized (str): _description_
|
433
|
+
|
434
|
+
Returns:
|
435
|
+
Self: _description_
|
436
|
+
"""
|
437
|
+
data = json.loads(serialized)
|
438
|
+
|
439
|
+
self.name = data['name']
|
440
|
+
self.natoms = data['natoms']
|
441
|
+
self.props = data['props']
|
442
|
+
self.rdmol = Chem.MolFromMolBlock(data['molblock'], sanitize=False, removeHs=False)
|
443
|
+
|
444
|
+
return self
|
445
|
+
|
446
|
+
|
447
|
+
def to_molblock(self) -> str:
|
448
|
+
"""Returns MolBlock"""
|
449
|
+
return Chem.MolToMolBlock(self.rdmol)
|
450
|
+
|
451
|
+
|
452
|
+
def to_xyz(self) -> str:
|
453
|
+
"""Returns XYZ formatted strings.
|
454
|
+
|
455
|
+
Returns:
|
456
|
+
str: XYZ formatted strings.
|
457
|
+
"""
|
458
|
+
lines = [f'{self.natoms}', ' ']
|
459
|
+
for e, (x, y, z) in zip(self.symbols(), self.positions()):
|
460
|
+
lines.append(f'{e:5} {x:23.14f} {y:23.14f} {z:23.14f}')
|
461
|
+
|
462
|
+
return '\n'.join(lines)
|
463
|
+
|
464
|
+
|
316
465
|
def to_sdf(self, props:bool=True) -> str:
|
317
466
|
"""Returns the SDF-formatted strings.
|
318
467
|
|
@@ -332,43 +481,85 @@ class Conf:
|
|
332
481
|
f.write(rdmol)
|
333
482
|
return in_memory.getvalue()
|
334
483
|
|
484
|
+
|
485
|
+
def to_png(self,
|
486
|
+
width: int = 300,
|
487
|
+
height: int = 300,
|
488
|
+
legend: str = '',
|
489
|
+
atom_index: bool = False,
|
490
|
+
highlight_atoms: list[int] | None = None,
|
491
|
+
highlight_bonds: list[int] | None = None,
|
492
|
+
redraw: bool = False,
|
493
|
+
coordgen: bool = False,
|
494
|
+
trim: bool = True) -> Image.Image:
|
495
|
+
"""Draw 2D molecule in PNG format.
|
496
|
+
|
497
|
+
Args:
|
498
|
+
width (int, optional): width. Defaults to 300.
|
499
|
+
height (int, optional): height. Defaults to 300.
|
500
|
+
legend (str, optional): legend. Defaults to ''.
|
501
|
+
atom_index (bool, optional): whether to show atom index. Defaults to False.
|
502
|
+
highlight_atoms (list[int] | None, optional): atom(s) to highlight. Defaults to None.
|
503
|
+
highlight_bonds (list[int] | None, optional): bond(s) to highlight. Defaults to None.
|
504
|
+
redraw (bool, optional): whether to redraw. Defaults to False.
|
505
|
+
coordgen (bool, optional): whether to use coordgen. Defaults to False.
|
506
|
+
trim (bool, optional): whether to trim white margins. Default to True.
|
507
|
+
|
508
|
+
Returns:
|
509
|
+
Image.Image: output PIL Image object.
|
510
|
+
"""
|
511
|
+
|
512
|
+
return render_png(self.rdmol,
|
513
|
+
width = width,
|
514
|
+
height = height,
|
515
|
+
legend = legend,
|
516
|
+
atom_index = atom_index,
|
517
|
+
highlight_atoms = highlight_atoms,
|
518
|
+
highlight_bonds = highlight_bonds,
|
519
|
+
redraw = redraw,
|
520
|
+
coordgen = coordgen,
|
521
|
+
trim = trim)
|
522
|
+
|
335
523
|
|
336
|
-
def to_svg(self,
|
337
|
-
width:int=
|
338
|
-
height:int=
|
339
|
-
legend:
|
340
|
-
atom_index:bool=False,
|
341
|
-
|
342
|
-
|
524
|
+
def to_svg(self,
|
525
|
+
width: int = 300,
|
526
|
+
height: int = 300,
|
527
|
+
legend: str = '',
|
528
|
+
atom_index: bool = False,
|
529
|
+
highlight_atoms: list[int] | None = None,
|
530
|
+
highlight_bonds: list[int] | None = None,
|
531
|
+
redraw: bool = False,
|
532
|
+
coordgen: bool = False,
|
533
|
+
optimize: bool = True) -> str:
|
534
|
+
"""Draw 2D molecule in SVG format.
|
343
535
|
|
344
536
|
Examples:
|
537
|
+
For Jupyternotebook, wrap the output with SVG:
|
538
|
+
|
345
539
|
>>> from IPython.display import SVG
|
346
|
-
>>> SVG(libr[0].
|
540
|
+
>>> SVG(libr[0].to_svg())
|
347
541
|
|
348
542
|
Args:
|
349
|
-
width (int): width
|
350
|
-
height (int): height
|
351
|
-
legend (str, optional):
|
352
|
-
atom_index (bool):
|
353
|
-
|
354
|
-
|
543
|
+
width (int, optional): width. Defaults to 300.
|
544
|
+
height (int, optional): height. Defaults to 300.
|
545
|
+
legend (str, optional): legend. Defaults to ''.
|
546
|
+
atom_index (bool, optional): whether to show atom index. Defaults to False.
|
547
|
+
highlight_atoms (list[int] | None, optional): atom(s) to highlight. Defaults to None.
|
548
|
+
highlight_bonds (list[int] | None, optional): bond(s) to highlight. Defaults to None.
|
549
|
+
redraw (bool, optional): whether to redraw. Defaults to False.
|
550
|
+
coordgen (bool, optional): whether to use coordgen. Defaults to False.
|
551
|
+
optimize (bool, optional): whether to optimize SVG string. Defaults to True.
|
552
|
+
|
355
553
|
Returns:
|
356
|
-
str: SVG
|
554
|
+
str: SVG string
|
357
555
|
"""
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
atom.SetProp("atomLabel", str(atom.GetIdx()))
|
369
|
-
if highlight:
|
370
|
-
drawer.DrawMolecule(rdmol_3d, legend=legend, highlightAtoms=highlight)
|
371
|
-
else:
|
372
|
-
drawer.DrawMolecule(rdmol_3d, legend=legend)
|
373
|
-
drawer.FinishDrawing()
|
374
|
-
return drawer.GetDrawingText()
|
556
|
+
return render_svg(self.rdmol,
|
557
|
+
width = width,
|
558
|
+
height = height,
|
559
|
+
legend = legend,
|
560
|
+
atom_index = atom_index,
|
561
|
+
highlight_atoms = highlight_atoms,
|
562
|
+
highlight_bonds = highlight_bonds,
|
563
|
+
redraw = redraw,
|
564
|
+
coordgen = coordgen,
|
565
|
+
optimize = optimize)
|