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/xtb/wrapper.py ADDED
@@ -0,0 +1,304 @@
1
+ import os
2
+ import resource
3
+ import subprocess
4
+ import json
5
+ import tempfile
6
+ import logging
7
+
8
+ from pathlib import Path
9
+ from types import SimpleNamespace
10
+
11
+ from rdkit import Chem
12
+ from rdkit.Geometry import Point3D
13
+
14
+
15
+ main_logger = logging.getLogger()
16
+
17
+ # In ASE, the default energy unit is eV (electron volt).
18
+ # It will be converted to kcal/mol
19
+ # CODATA 2018 energy conversion factor
20
+ hartree2ev = 27.211386245988
21
+ hartree2kcalpermol = 627.50947337481
22
+ ev2kcalpermol = 23.060547830619026
23
+
24
+
25
+ class GFN2xTB:
26
+ def __init__(self, molecule: Chem.Mol | None = None, ncores: int = 4):
27
+ if isinstance(molecule, Chem.Mol):
28
+ assert molecule.GetConformer().Is3D(), "requires 3D coordinates"
29
+ self.rdmol = molecule
30
+ self.natoms = molecule.GetNumAtoms()
31
+ self.symbols = [ atom.GetSymbol() for atom in molecule.GetAtoms() ]
32
+ self.positions = molecule.GetConformer().GetPositions().tolist()
33
+
34
+ # Parallelisation
35
+ os.environ['OMP_STACKSIZE'] = '4G'
36
+ os.environ['OMP_NUM_THREADS'] = f'{ncores},1'
37
+ os.environ['OMP_MAX_ACTIVE_LEVELS'] = '1'
38
+ os.environ['MKL_NUM_THREADS'] = f'{ncores}'
39
+
40
+ # unlimit the system stack
41
+ resource.setrlimit(resource.RLIMIT_STACK, (resource.RLIM_INFINITY, resource.RLIM_INFINITY))
42
+
43
+
44
+ def version(self) -> str | None:
45
+ """Check xtb version.
46
+
47
+ Returns:
48
+ str | None: version statement.
49
+ """
50
+ cmd = ['xtb', '--version']
51
+ proc = subprocess.run(cmd, capture_output=True, text=True)
52
+ assert proc.returncode == 0, "GFN2xTB() Error: xtb not available"
53
+ for line in proc.stdout.split('\n'):
54
+ line = line.strip()
55
+ if 'version' in line:
56
+ return line
57
+
58
+ return None
59
+
60
+
61
+ def to_xyz(self) -> str:
62
+ """Export to XYZ formatted string.
63
+
64
+ Returns:
65
+ str: XYZ formatted string
66
+ """
67
+ lines = [f'{self.natoms}', ' ']
68
+ for e, (x, y, z) in zip(self.symbols, self.positions):
69
+ lines.append(f'{e:5} {x:23.14f} {y:23.14f} {z:23.14f}')
70
+
71
+ return '\n'.join(lines)
72
+
73
+
74
+ def load_xyz(self, geometry_path: Path) -> Chem.Mol:
75
+ """Load geometry.
76
+
77
+ Args:
78
+ geometry_path (Path): pathlib.Path to the xyz
79
+
80
+ Returns:
81
+ Chem.Mol: rdkit Chem.Mol object.
82
+ """
83
+ rdmol_opt = Chem.Mol(self.rdmol)
84
+ with open(geometry_path, 'r') as f:
85
+ for lineno, line in enumerate(f):
86
+ if lineno == 0:
87
+ assert int(line.strip()) == self.natoms
88
+ continue
89
+ elif lineno == 1: # comment or title
90
+ continue
91
+ (symbol, x, y, z) = line.strip().split()
92
+ x, y, z = float(x), float(y), float(z)
93
+ atom = rdmol_opt.GetAtomWithIdx(lineno-2)
94
+ assert symbol == atom.GetSymbol()
95
+ rdmol_opt.GetConformer().SetAtomPosition(atom.GetIdx(), Point3D(x, y, z))
96
+
97
+ return rdmol_opt
98
+
99
+
100
+ def load_wbo(self, wbo_path: Path) -> dict[tuple[int, int], float]:
101
+ """Load Wiberg bond order.
102
+
103
+ Args:
104
+ wbo_path (Path): path to the wbo file.
105
+
106
+ Returns:
107
+ dict(tuple[int, int], float): { (i, j) : wbo, ... } where i and j are atom indices for a bond.
108
+ """
109
+
110
+ with open(wbo_path, 'r') as f:
111
+ # Wiberg bond order (WBO)
112
+ Wiberg_bond_orders = {}
113
+ for line in f:
114
+ line = line.strip()
115
+ if line:
116
+ # wbo output has 1-based indices
117
+ (i, j, wbo) = line.split()
118
+ # changes to 0-based indices
119
+ i = int(i) - 1
120
+ j = int(j) - 1
121
+ # wbo ouput indices are ascending order
122
+ ij = (i, j) if i < j else (j, i)
123
+ Wiberg_bond_orders[ij] = float(wbo)
124
+
125
+ return Wiberg_bond_orders
126
+
127
+
128
+ def singlepoint(self, water: str | None = None, verbose: bool = False) -> SimpleNamespace:
129
+ """Calculate single point energy.
130
+
131
+ Total energy from xtb output in atomic units (Eh, hartree) is converted to kcal/mol.
132
+
133
+ Args:
134
+ water (str, optional) : water solvation model (choose 'gbsa' or 'alpb')
135
+ alpb: ALPB solvation model (Analytical Linearized Poisson-Boltzmann).
136
+ gbsa: generalized Born (GB) model with Surface Area contributions.
137
+
138
+ Returns:
139
+ SimpleNamespace(PE(total energy in kcal/mol), charges, wbo)
140
+ """
141
+
142
+ with tempfile.TemporaryDirectory() as temp_dir: # tmpdir is a string
143
+ workdir = Path(temp_dir)
144
+ if verbose:
145
+ main_logger.info(f'xtb.singlepoint workdir= {temp_dir}')
146
+
147
+ geometry_path = workdir / 'geometry.xyz'
148
+ xtbout_path = workdir / 'xtbout.json'
149
+ wbo_path = workdir / 'wbo'
150
+
151
+ with open(geometry_path, 'w') as geometry:
152
+ geometry.write(self.to_xyz())
153
+
154
+ cmd = ['xtb', geometry_path.as_posix()]
155
+
156
+ options = ['--gfn', '2', '--json']
157
+
158
+ if water is not None and isinstance(water, str):
159
+ if water == 'gbsa':
160
+ options += ['--gbsa', 'H2O']
161
+ elif water == 'alpb':
162
+ options += ['--alpb', 'water']
163
+
164
+ # 'xtbout.json', 'xtbrestart', 'xtbtopo.mol', 'charges', and 'wbo' files will be
165
+ # created in the current working directory.
166
+ proc = subprocess.run(cmd + options, cwd=temp_dir, capture_output=True, text=True)
167
+
168
+ # if proc.returncode == 0:
169
+ # print("Standard Output:")
170
+ # print(proc.stdout)
171
+ # else:
172
+ # print("Error:")
173
+ # print(proc.stderr)
174
+
175
+ if proc.returncode == 0 and xtbout_path.is_file():
176
+ with open(xtbout_path, 'r') as f:
177
+ datadict = json.load(f) # takes the file object as input
178
+
179
+ Wiberg_bond_orders = self.load_wbo(wbo_path)
180
+
181
+ return SimpleNamespace(
182
+ PE = datadict['total energy'] * hartree2kcalpermol,
183
+ charges = datadict['partial charges'],
184
+ wbo = Wiberg_bond_orders,
185
+ )
186
+
187
+ # something went wrong if it reaches here
188
+ return SimpleNamespace()
189
+
190
+
191
+
192
+ def optimize(self, water: str | None = None, verbose: bool = False) -> SimpleNamespace:
193
+ """Optimize geometry.
194
+
195
+ Fortran runtime errror:
196
+ At line 852 of file ../src/optimizer.f90 (unit = 6, file = 'stdout')
197
+ Fortran runtime error: Missing comma between descriptors
198
+ (1x,"("f7.2"%)")
199
+ ^
200
+ Error termination.
201
+
202
+ Args:
203
+ water (str, optional) : water solvation model (choose 'gbsa' or 'alpb')
204
+ alpb: ALPB solvation model (Analytical Linearized Poisson-Boltzmann).
205
+ gbsa: generalized Born (GB) model with Surface Area contributions.
206
+
207
+ Returns:
208
+ (total energy in kcal/mol, optimized geometry)
209
+ """
210
+ with tempfile.TemporaryDirectory() as temp_dir: # tmpdir is a string
211
+ workdir = Path(temp_dir)
212
+ if verbose:
213
+ main_logger.info(f'xtb.optimize workdir= {temp_dir}')
214
+
215
+ geometry_path = workdir / 'geometry.xyz'
216
+ xtbout_path = workdir / 'xtbout.json'
217
+ xtbopt_path = workdir / 'xtbopt.xyz'
218
+ wbo_path = workdir / 'wbo'
219
+
220
+ with open(geometry_path, 'w') as geometry:
221
+ geometry.write(self.to_xyz())
222
+
223
+ cmd = ['xtb', geometry_path.as_posix()]
224
+
225
+ options = ['--opt', '--gfn', '2', '--json']
226
+
227
+ if water is not None and isinstance(water, str):
228
+ if water == 'gbsa':
229
+ options += ['--gbsa', 'H2O']
230
+ elif water == 'alpb':
231
+ options += ['--alpb', 'water']
232
+
233
+ proc = subprocess.run(cmd + options, cwd=temp_dir, capture_output=True, text=True)
234
+
235
+ if proc.returncode == 0 and xtbout_path.is_file():
236
+ with open(xtbout_path, 'r') as f:
237
+ datadict = json.load(f) # takes the file object as input
238
+
239
+ Wiberg_bond_orders = self.load_wbo(wbo_path)
240
+ rdmol_opt = self.load_xyz(xtbopt_path)
241
+
242
+ return SimpleNamespace(
243
+ PE = datadict['total energy'] * hartree2kcalpermol,
244
+ charges = datadict['partial charges'],
245
+ wbo = Wiberg_bond_orders,
246
+ geometry = rdmol_opt,
247
+ )
248
+
249
+ # something went wrong if it reaches here
250
+ return SimpleNamespace()
251
+
252
+
253
+ def esp(self, water: str | None = None, verbose: bool = False) -> None:
254
+ """Calculate electrostatic potential
255
+
256
+ Example:
257
+ v = py3Dmol.view()
258
+ v.addVolumetricData(dt,
259
+ "cube.gz", {
260
+ 'isoval': 0.005,
261
+ 'smoothness': 2,
262
+ 'opacity':.9,
263
+ 'voldata': esp,
264
+ 'volformat': 'cube.gz',
265
+ 'volscheme': {
266
+ 'gradient':'rwb',
267
+ 'min':-.1,
268
+ 'max':.1,
269
+ }
270
+ });
271
+ v.addModel(dt,'cube')
272
+ v.setStyle({'stick':{}})
273
+ v.zoomTo()
274
+ v.show()
275
+ """
276
+ with tempfile.TemporaryDirectory() as temp_dir: # tmpdir is a string
277
+ workdir = Path(temp_dir)
278
+ if verbose:
279
+ main_logger.info(f'xtb.optimize workdir= {temp_dir}')
280
+
281
+ geometry_path = workdir / 'geometry.xyz'
282
+ xtb_esp_dat = workdir / 'xtb_esp_dat'
283
+
284
+ with open(geometry_path, 'w') as geometry:
285
+ geometry.write(self.to_xyz())
286
+
287
+ cmd = ['xtb', geometry_path.as_posix()]
288
+
289
+ options = ['--esp', '--gfn', '2']
290
+
291
+ if water is not None and isinstance(water, str):
292
+ if water == 'gbsa':
293
+ options += ['--gbsa', 'H2O']
294
+ elif water == 'alpb':
295
+ options += ['--alpb', 'water']
296
+
297
+ proc = subprocess.run(cmd + options, cwd=temp_dir, capture_output=True, text=True)
298
+ # output files: xtb_esp.cosmo, xtb_esp.dat, xtb_esp_profile.dat
299
+
300
+ if proc.returncode == 0 and xtb_esp_dat.is_file():
301
+ with open(xtb_esp_dat, 'r') as f:
302
+ pass
303
+
304
+ return None
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rdworks
3
- Version: 0.25.7
4
- Summary: Cheminformatics and AI/ML Work Built on RDKit
3
+ Version: 0.35.1
4
+ Summary: Frequently used tasks built on RDKit and other tools
5
5
  Author-email: Sung-Hun Bae <sunghun.bae@gmail.com>
6
6
  Maintainer-email: Sung-Hun Bae <sunghun.bae@gmail.com>
7
7
  License-Expression: MIT
@@ -10,7 +10,7 @@ Project-URL: Repository, https://github.com/sunghunbae/rdworks.git
10
10
  Project-URL: Issues, https://github.com/sunghunbae/rdworks/issues
11
11
  Project-URL: Changelog, https://github.com/sunghunbae/rdworks/blob/master/CHANGELOG.md
12
12
  Project-URL: Documentation, https://sunghunbae.github.io/rdworks/
13
- Keywords: neural-network-potential,cheminformatics,rdkit
13
+ Keywords: cheminformatics,rdkit
14
14
  Classifier: Development Status :: 3 - Alpha
15
15
  Classifier: Intended Audience :: Developers
16
16
  Classifier: Programming Language :: Python :: 3
@@ -18,18 +18,15 @@ Classifier: Operating System :: OS Independent
18
18
  Requires-Python: >=3.11
19
19
  Description-Content-Type: text/markdown
20
20
  License-File: LICENSE
21
- Requires-Dist: numpy
22
- Requires-Dist: scipy
23
- Requires-Dist: scikit-learn
21
+ Requires-Dist: rdkit>=2024
22
+ Requires-Dist: cdpkit
24
23
  Requires-Dist: pandas
25
24
  Requires-Dist: seaborn
26
- Requires-Dist: networkx
27
25
  Requires-Dist: tqdm
28
- Requires-Dist: psutil
29
26
  Requires-Dist: ase
30
- Requires-Dist: rdkit>=2023
27
+ Requires-Dist: mendeleev
28
+ Requires-Dist: scour
31
29
  Requires-Dist: bitarray
32
- Requires-Dist: cdpkit
33
30
  Requires-Dist: pytest
34
31
  Dynamic: license-file
35
32
 
@@ -1,20 +1,21 @@
1
- rdworks/__init__.py,sha256=dZaI7Hby8O_6cqWwxH9ea5_w5sLsHo3AVgUff8uXEzU,1561
2
- rdworks/conf.py,sha256=c7BFSZ_WhlqJJjtqca2yS7c8OdWUz1XZwR4n3CewqB8,14563
1
+ rdworks/__init__.py,sha256=UPZKHw1RajTvab15-wzdsP4UjD27yQT0n6Q5waUaJQE,1368
2
+ rdworks/conf.py,sha256=BPp_uZAXXOU53tKzjZz8SsUdAvi7aK1s_zCeHfiRATk,21744
3
3
  rdworks/descriptor.py,sha256=34T_dQ6g8v3u-ym8TLKbQtxIIV5TEo-d3pdedq3o-cg,2106
4
- rdworks/display.py,sha256=_OSARhvAPL9MZq4MHzNWS3eU3FiOThVGHhhB2PUEuZE,6736
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=aeTMesuG6QbyOR71gWRhoBp_1A7EdrKDzDCBfXLqtZ8,64965
8
- rdworks/mollibr.py,sha256=o3O1-Fz4J9QpCT15n7h-MygBFKNP-P3v8jEni36itCM,33553
7
+ rdworks/mol.py,sha256=5ZaBIpCnKIqxbIZM0IAJ2uG5fEIlZotw1Lb2QT_IXe0,71145
8
+ rdworks/mollibr.py,sha256=X4UBO6Ga-QmNS7RwUiaDYAx0Q5hnWs71yTkEpH02Qb4,37696
9
9
  rdworks/pka.py,sha256=NVJVfpcNEMlX5QRyLBgUM7GIT7VMjO-llAR4LWc8J2c,1656
10
- rdworks/readin.py,sha256=7j0r0U6BifZCAQ74Z5fFqmiq25mYClnenii0CtBCINI,11805
10
+ rdworks/readin.py,sha256=0bnVcZcAmSLqc6zu1mYcv0LdBv2agQfOpKGwpSRL9VE,11742
11
11
  rdworks/rgroup.py,sha256=ivF2gzmRtt339rxEnkv2KfnCs0CUdBbnSje7Y54rtFI,57996
12
- rdworks/scaffold.py,sha256=LTazmJ5uydUZSo-i4XDowGO7Bvx3M9H1Ke-XfS5UP94,22023
13
- rdworks/std.py,sha256=0EIrI_49npO0-XlJiMYuBo_SIhqzj8qD8YijunfWJXE,6096
12
+ rdworks/scaffold.py,sha256=60T5YacyxZsEpDo_J5Qxulm2YNQO4EQR8PcNUwjn1QU,22026
13
+ rdworks/std.py,sha256=p-Ha8uJla_6bDLkf-zvdsCeXqrV8jJTLYiV6IkSW9FE,7147
14
14
  rdworks/stereoisomers.py,sha256=g8hhPI-mbYX-MzbF1uAqo5fDZOCNiKYjxI-kLBGdGgg,4980
15
15
  rdworks/tautomers.py,sha256=gtZHZJ-aJbryhBdljHbfjx7xhVW3u_OzdYPtwPail54,610
16
- rdworks/units.py,sha256=2bkig_WyjkmdgCQIKL96VZwBAinFlIXDvJaEAaYEjAk,4240
17
- rdworks/utils.py,sha256=puIMK41sry8FKGQ9-RrlqSYUQhiMtaE18C1HIZsVHlI,16794
16
+ rdworks/torsion.py,sha256=Y0QOi5JEc7-0YpJ7b0rzA1UuuJxymzjm9Ap-9u8udfg,18429
17
+ rdworks/units.py,sha256=nljKPHcr6IWoAp0CkL7y1gSNDd6a07NeVfxXwSMuHQM,365
18
+ rdworks/utils.py,sha256=IxgFniUvjXlJuNJ1Sx9hsJknNNSglP6qzFyz8vdgDcw,13406
18
19
  rdworks/xml.py,sha256=aaMhwVRGvt1VzasaKDnkYnZ4kp2cIgvGb1CsmMgwQ_c,10704
19
20
  rdworks/autograph/__init__.py,sha256=0Qfjwo0h4Q0n08zsqHRbuNOZms6MuNXnWErnQpQ6Px0,140
20
21
  rdworks/autograph/autograph.py,sha256=frjsUaCTOD-Z1lYPzOxRoTtqMMiYroWAy6tSwKn3CUA,8769
@@ -62,8 +63,10 @@ rdworks/predefined/misc/makexml.py,sha256=T9c6ssKYdDzMkkcaCjEUe59nVPJfwJEoHm6Rhk
62
63
  rdworks/predefined/misc/reactive-part-2.xml,sha256=0vNTMwWrrQmxBpbgbyRHx8sVs83cqn7xsfr5qqrelRA,3676
63
64
  rdworks/predefined/misc/reactive-part-3.xml,sha256=LgWHSEbRTVmgBoIO45xbTo1xQJs0Xu51j3JnIapRYo4,3094
64
65
  rdworks/predefined/misc/reactive.xml,sha256=syedoQ6VYUfRLnxy99ObuDniJ_a_WhrWAJbTKFfJ6VY,11248
65
- rdworks-0.25.7.dist-info/licenses/LICENSE,sha256=UOkJSBqYyQUvtCp7a-vdCANeEcLE2dnTie_eB1By5SY,1074
66
- rdworks-0.25.7.dist-info/METADATA,sha256=MPPTPV31tli5A7BDNvxgk6v8Zc-E_et8eIrP22C7gkU,1271
67
- rdworks-0.25.7.dist-info/WHEEL,sha256=ck4Vq1_RXyvS4Jt6SI0Vz6fyVs4GWg7AINwpsaGEgPE,91
68
- rdworks-0.25.7.dist-info/top_level.txt,sha256=05C98HbvBK2axUBogC_hAT_CdpOeQYGnQ6vRAgawr8s,8
69
- rdworks-0.25.7.dist-info/RECORD,,
66
+ rdworks/xtb/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
67
+ rdworks/xtb/wrapper.py,sha256=I0nW89vlJZ5Za5pCjIpjsEOFbTm7HpeNGiPgssheWn8,11350
68
+ rdworks-0.35.1.dist-info/licenses/LICENSE,sha256=UOkJSBqYyQUvtCp7a-vdCANeEcLE2dnTie_eB1By5SY,1074
69
+ rdworks-0.35.1.dist-info/METADATA,sha256=cmN6_DkuVc8s0zE1LClwGTv2RGbwP6lrVxPOt2hST5k,1183
70
+ rdworks-0.35.1.dist-info/WHEEL,sha256=zaaOINJESkSfm_4HQVc5ssNzHCPXhJm0kEUakpsEHaU,91
71
+ rdworks-0.35.1.dist-info/top_level.txt,sha256=05C98HbvBK2axUBogC_hAT_CdpOeQYGnQ6vRAgawr8s,8
72
+ rdworks-0.35.1.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.0.0)
2
+ Generator: setuptools (80.8.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5