rdworks 0.51.1__tar.gz → 0.52.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.51.1 → rdworks-0.52.1}/PKG-INFO +1 -1
- {rdworks-0.51.1 → rdworks-0.52.1}/src/rdworks/__init__.py +1 -1
- {rdworks-0.51.1 → rdworks-0.52.1}/src/rdworks/conf.py +9 -0
- rdworks-0.52.1/src/rdworks/microstates.py +138 -0
- {rdworks-0.51.1 → rdworks-0.52.1}/src/rdworks/readin.py +1 -0
- {rdworks-0.51.1 → rdworks-0.52.1}/src/rdworks/xtb/wrapper.py +94 -124
- {rdworks-0.51.1 → rdworks-0.52.1}/src/rdworks.egg-info/PKG-INFO +1 -1
- {rdworks-0.51.1 → rdworks-0.52.1}/src/rdworks.egg-info/SOURCES.txt +1 -0
- {rdworks-0.51.1 → rdworks-0.52.1}/tests/test_basics.py +75 -29
- {rdworks-0.51.1 → rdworks-0.52.1}/tests/test_qupkake.py +5 -2
- {rdworks-0.51.1 → rdworks-0.52.1}/tests/test_xtb.py +3 -3
- {rdworks-0.51.1 → rdworks-0.52.1}/LICENSE +0 -0
- {rdworks-0.51.1 → rdworks-0.52.1}/README.md +0 -0
- {rdworks-0.51.1 → rdworks-0.52.1}/pyproject.toml +0 -0
- {rdworks-0.51.1 → rdworks-0.52.1}/setup.cfg +0 -0
- {rdworks-0.51.1 → rdworks-0.52.1}/src/rdworks/autograph/__init__.py +0 -0
- {rdworks-0.51.1 → rdworks-0.52.1}/src/rdworks/autograph/autograph.py +0 -0
- {rdworks-0.51.1 → rdworks-0.52.1}/src/rdworks/autograph/centroid.py +0 -0
- {rdworks-0.51.1 → rdworks-0.52.1}/src/rdworks/autograph/dynamictreecut.py +0 -0
- {rdworks-0.51.1 → rdworks-0.52.1}/src/rdworks/autograph/nmrclust.py +0 -0
- {rdworks-0.51.1 → rdworks-0.52.1}/src/rdworks/autograph/rckmeans.py +0 -0
- {rdworks-0.51.1 → rdworks-0.52.1}/src/rdworks/bitqt/__init__.py +0 -0
- {rdworks-0.51.1 → rdworks-0.52.1}/src/rdworks/bitqt/bitqt.py +0 -0
- {rdworks-0.51.1 → rdworks-0.52.1}/src/rdworks/descriptor.py +0 -0
- {rdworks-0.51.1 → rdworks-0.52.1}/src/rdworks/display.py +0 -0
- {rdworks-0.51.1 → rdworks-0.52.1}/src/rdworks/ionized.py +0 -0
- {rdworks-0.51.1 → rdworks-0.52.1}/src/rdworks/matchedseries.py +0 -0
- {rdworks-0.51.1 → rdworks-0.52.1}/src/rdworks/mol.py +0 -0
- {rdworks-0.51.1 → rdworks-0.52.1}/src/rdworks/mollibr.py +0 -0
- {rdworks-0.51.1 → rdworks-0.52.1}/src/rdworks/pka.py +0 -0
- {rdworks-0.51.1 → rdworks-0.52.1}/src/rdworks/predefined/Asinex_fragment.xml +0 -0
- {rdworks-0.51.1 → rdworks-0.52.1}/src/rdworks/predefined/Astex_RO3.xml +0 -0
- {rdworks-0.51.1 → rdworks-0.52.1}/src/rdworks/predefined/Baell2010_PAINS/Baell2010A.xml +0 -0
- {rdworks-0.51.1 → rdworks-0.52.1}/src/rdworks/predefined/Baell2010_PAINS/Baell2010B.xml +0 -0
- {rdworks-0.51.1 → rdworks-0.52.1}/src/rdworks/predefined/Baell2010_PAINS/Baell2010C.xml +0 -0
- {rdworks-0.51.1 → rdworks-0.52.1}/src/rdworks/predefined/Baell2010_PAINS/PAINS-less-than-015-hits.xml +0 -0
- {rdworks-0.51.1 → rdworks-0.52.1}/src/rdworks/predefined/Baell2010_PAINS/PAINS-less-than-150-hits.xml +0 -0
- {rdworks-0.51.1 → rdworks-0.52.1}/src/rdworks/predefined/Baell2010_PAINS/PAINS-more-than-150-hits.xml +0 -0
- {rdworks-0.51.1 → rdworks-0.52.1}/src/rdworks/predefined/Baell2010_PAINS/makexml.py +0 -0
- {rdworks-0.51.1 → rdworks-0.52.1}/src/rdworks/predefined/Brenk2008_Dundee/makexml.py +0 -0
- {rdworks-0.51.1 → rdworks-0.52.1}/src/rdworks/predefined/CNS.xml +0 -0
- {rdworks-0.51.1 → rdworks-0.52.1}/src/rdworks/predefined/ChEMBL_Walters/BMS.xml +0 -0
- {rdworks-0.51.1 → rdworks-0.52.1}/src/rdworks/predefined/ChEMBL_Walters/Dundee.xml +0 -0
- {rdworks-0.51.1 → rdworks-0.52.1}/src/rdworks/predefined/ChEMBL_Walters/Glaxo.xml +0 -0
- {rdworks-0.51.1 → rdworks-0.52.1}/src/rdworks/predefined/ChEMBL_Walters/Inpharmatica.xml +0 -0
- {rdworks-0.51.1 → rdworks-0.52.1}/src/rdworks/predefined/ChEMBL_Walters/LINT.xml +0 -0
- {rdworks-0.51.1 → rdworks-0.52.1}/src/rdworks/predefined/ChEMBL_Walters/MLSMR.xml +0 -0
- {rdworks-0.51.1 → rdworks-0.52.1}/src/rdworks/predefined/ChEMBL_Walters/PAINS.xml +0 -0
- {rdworks-0.51.1 → rdworks-0.52.1}/src/rdworks/predefined/ChEMBL_Walters/SureChEMBL.xml +0 -0
- {rdworks-0.51.1 → rdworks-0.52.1}/src/rdworks/predefined/ChEMBL_Walters/makexml.py +0 -0
- {rdworks-0.51.1 → rdworks-0.52.1}/src/rdworks/predefined/Hann1999_Glaxo/Hann1999.xml +0 -0
- {rdworks-0.51.1 → rdworks-0.52.1}/src/rdworks/predefined/Hann1999_Glaxo/Hann1999Acid.xml +0 -0
- {rdworks-0.51.1 → rdworks-0.52.1}/src/rdworks/predefined/Hann1999_Glaxo/Hann1999Base.xml +0 -0
- {rdworks-0.51.1 → rdworks-0.52.1}/src/rdworks/predefined/Hann1999_Glaxo/Hann1999ElPh.xml +0 -0
- {rdworks-0.51.1 → rdworks-0.52.1}/src/rdworks/predefined/Hann1999_Glaxo/Hann1999NuPh.xml +0 -0
- {rdworks-0.51.1 → rdworks-0.52.1}/src/rdworks/predefined/Hann1999_Glaxo/makexml.py +0 -0
- {rdworks-0.51.1 → rdworks-0.52.1}/src/rdworks/predefined/Kazius2005/Kazius2005.xml +0 -0
- {rdworks-0.51.1 → rdworks-0.52.1}/src/rdworks/predefined/Kazius2005/makexml.py +0 -0
- {rdworks-0.51.1 → rdworks-0.52.1}/src/rdworks/predefined/ZINC_druglike.xml +0 -0
- {rdworks-0.51.1 → rdworks-0.52.1}/src/rdworks/predefined/ZINC_fragment.xml +0 -0
- {rdworks-0.51.1 → rdworks-0.52.1}/src/rdworks/predefined/ZINC_leadlike.xml +0 -0
- {rdworks-0.51.1 → rdworks-0.52.1}/src/rdworks/predefined/fragment.xml +0 -0
- {rdworks-0.51.1 → rdworks-0.52.1}/src/rdworks/predefined/ionized/simple_smarts_pattern.csv +0 -0
- {rdworks-0.51.1 → rdworks-0.52.1}/src/rdworks/predefined/ionized/smarts_pattern.csv +0 -0
- {rdworks-0.51.1 → rdworks-0.52.1}/src/rdworks/predefined/misc/makexml.py +0 -0
- {rdworks-0.51.1 → rdworks-0.52.1}/src/rdworks/predefined/misc/reactive-part-2.xml +0 -0
- {rdworks-0.51.1 → rdworks-0.52.1}/src/rdworks/predefined/misc/reactive-part-3.xml +0 -0
- {rdworks-0.51.1 → rdworks-0.52.1}/src/rdworks/predefined/misc/reactive.xml +0 -0
- {rdworks-0.51.1 → rdworks-0.52.1}/src/rdworks/rgroup.py +0 -0
- {rdworks-0.51.1 → rdworks-0.52.1}/src/rdworks/scaffold.py +0 -0
- {rdworks-0.51.1 → rdworks-0.52.1}/src/rdworks/std.py +0 -0
- {rdworks-0.51.1 → rdworks-0.52.1}/src/rdworks/stereoisomers.py +0 -0
- {rdworks-0.51.1 → rdworks-0.52.1}/src/rdworks/tautomers.py +0 -0
- {rdworks-0.51.1 → rdworks-0.52.1}/src/rdworks/testdata.py +0 -0
- {rdworks-0.51.1 → rdworks-0.52.1}/src/rdworks/torsion.py +0 -0
- {rdworks-0.51.1 → rdworks-0.52.1}/src/rdworks/units.py +0 -0
- {rdworks-0.51.1 → rdworks-0.52.1}/src/rdworks/utils.py +0 -0
- {rdworks-0.51.1 → rdworks-0.52.1}/src/rdworks/xml.py +0 -0
- {rdworks-0.51.1 → rdworks-0.52.1}/src/rdworks/xtb/__init__.py +0 -0
- {rdworks-0.51.1 → rdworks-0.52.1}/src/rdworks.egg-info/dependency_links.txt +0 -0
- {rdworks-0.51.1 → rdworks-0.52.1}/src/rdworks.egg-info/requires.txt +0 -0
- {rdworks-0.51.1 → rdworks-0.52.1}/src/rdworks.egg-info/top_level.txt +0 -0
- {rdworks-0.51.1 → rdworks-0.52.1}/tests/test_ionized.py +0 -0
- {rdworks-0.51.1 → rdworks-0.52.1}/tests/test_round.py +0 -0
- {rdworks-0.51.1 → rdworks-0.52.1}/tests/test_torsion.py +0 -0
@@ -355,6 +355,15 @@ class Conf:
|
|
355
355
|
return True
|
356
356
|
|
357
357
|
|
358
|
+
def charge(self) -> int:
|
359
|
+
"""Returns molecular formal charge.
|
360
|
+
|
361
|
+
Returns:
|
362
|
+
int: charge
|
363
|
+
"""
|
364
|
+
return self.charge
|
365
|
+
|
366
|
+
|
358
367
|
def positions(self) -> np.array:
|
359
368
|
"""Returns the coordinates.
|
360
369
|
|
@@ -0,0 +1,138 @@
|
|
1
|
+
import numpy as np
|
2
|
+
import math
|
3
|
+
import itertools
|
4
|
+
|
5
|
+
from types import SimpleNamespace
|
6
|
+
from rdworks import Conf, Mol
|
7
|
+
from rdworks.xtb.wrapper import GFN2xTB
|
8
|
+
|
9
|
+
|
10
|
+
kT = 0.001987 * 298.0 # (kcal/mol K), standard condition
|
11
|
+
C = math.log(10) * kT
|
12
|
+
|
13
|
+
|
14
|
+
|
15
|
+
class Microstates():
|
16
|
+
|
17
|
+
def __init__(self, origin: Mol, calculator: str = 'xTB'):
|
18
|
+
self.origin = origin
|
19
|
+
self.calculator = calculator
|
20
|
+
self.basic_sites = []
|
21
|
+
self.acidic_sites = []
|
22
|
+
self.states = []
|
23
|
+
self.mols = []
|
24
|
+
self.reference = None
|
25
|
+
|
26
|
+
# read QupKake results
|
27
|
+
for conf in self.origin:
|
28
|
+
print(conf.props)
|
29
|
+
pka = conf.props.get('pka', None)
|
30
|
+
if pka is None:
|
31
|
+
# no protonation/deprotonation sites
|
32
|
+
continue
|
33
|
+
if isinstance(pka, str) and pka.startswith('tensor'):
|
34
|
+
# ex. 'tensor(9.5784)'
|
35
|
+
pka = float(pka.replace('tensor(','').replace(')',''))
|
36
|
+
if conf.props.get('pka_type') == 'basic':
|
37
|
+
self.basic_sites.append(conf.props.get('idx'))
|
38
|
+
elif conf.props.get('pka_type') == 'acidic':
|
39
|
+
self.acidic_sites.append(conf.props.get('idx'))
|
40
|
+
|
41
|
+
# enumerate protonation/deprotonation sites to generate microstates
|
42
|
+
|
43
|
+
np = len(self.basic_sites)
|
44
|
+
nd = len(self.acidic_sites)
|
45
|
+
P = [c for n in range(np+1) for c in itertools.combinations(self.basic_sites, n)]
|
46
|
+
D = [c for n in range(nd+1) for c in itertools.combinations(self.acidic_sites, n)]
|
47
|
+
|
48
|
+
PD = list(itertools.product(P, D))
|
49
|
+
|
50
|
+
for (p, d) in PD:
|
51
|
+
conf = self.origin.confs[0].copy()
|
52
|
+
conf = conf.protonate(p).deprotonate(d).optimize(calculator=calculator)
|
53
|
+
charge = len(p) - len(d)
|
54
|
+
self.states.append(SimpleNamespace(
|
55
|
+
charge=charge,
|
56
|
+
protonation_sites=p,
|
57
|
+
deprotonation_sites=d,
|
58
|
+
conf=conf,
|
59
|
+
smiles=Mol(conf).smiles,
|
60
|
+
delta_m=None,
|
61
|
+
PE=None))
|
62
|
+
|
63
|
+
# sort microstates by ascending charges
|
64
|
+
self.states = sorted(self.states, key=lambda x: x.charge)
|
65
|
+
|
66
|
+
|
67
|
+
@staticmethod
|
68
|
+
def Boltzmann_weighted_average(potential_energies: list) -> float:
|
69
|
+
"""Calculate Boltzmann weighted average potential energy at pH 0.
|
70
|
+
|
71
|
+
Args:
|
72
|
+
potential_energies (list): a list of potential energies.
|
73
|
+
|
74
|
+
Returns:
|
75
|
+
float: Boltzmann weighted average potential energy.
|
76
|
+
"""
|
77
|
+
pe_array = np.array(potential_energies)
|
78
|
+
pe = pe_array - min(potential_energies)
|
79
|
+
Boltzmann_factors = np.exp(-pe/kT)
|
80
|
+
Z = np.sum(Boltzmann_factors)
|
81
|
+
p = Boltzmann_factors/Z
|
82
|
+
|
83
|
+
return float(np.dot(p, pe_array))
|
84
|
+
|
85
|
+
|
86
|
+
def potential_energy(self) -> None:
|
87
|
+
for microstate in self.states:
|
88
|
+
mol = Mol(microstate.conf).make_confs(n=4).optimize_confs()
|
89
|
+
# mol = mol.drop_confs(similar=True, similar_rmsd=0.3, verbose=True)
|
90
|
+
# mol = mol.optimize_confs(calculator=calculator)
|
91
|
+
# mol = mol.drop_confs(k=10, window=15.0, verbose=True)
|
92
|
+
PE = []
|
93
|
+
for conf in mol.confs:
|
94
|
+
conf = conf.optimize(calculator=self.calculator, verbose=True)
|
95
|
+
# GFN2xTB requires 3D coordinates
|
96
|
+
# xtb = GFN2xTB(conf.rdmol).singlepoint(water='cpcmx', verbose=True)
|
97
|
+
xtb = GFN2xTB(conf.rdmol).singlepoint(verbose=True)
|
98
|
+
PE.append(xtb.PE)
|
99
|
+
# SimpleNamespace(
|
100
|
+
# PE = datadict['total energy'] * hartree2kcalpermol,
|
101
|
+
# Gsolv = Gsolv,
|
102
|
+
# charges = datadict['partial charges'],
|
103
|
+
# wbo = Wiberg_bond_orders,
|
104
|
+
# )
|
105
|
+
print("PE=", PE)
|
106
|
+
microstate.PE = self.Boltzmann_weighted_average(PE)
|
107
|
+
print("Boltzmann weighted=", microstate.PE)
|
108
|
+
|
109
|
+
self.mols.append(mol)
|
110
|
+
print("microstate.energy", microstate)
|
111
|
+
|
112
|
+
|
113
|
+
def populations(self, pH: float) -> list[tuple]:
|
114
|
+
# set the lowest dG as the reference
|
115
|
+
self.reference = self.states[np.argmin([microstate.PE for microstate in self.states])]
|
116
|
+
for microstate in self.states:
|
117
|
+
microstate.delta_m = microstate.charge - self.reference.charge
|
118
|
+
dG = []
|
119
|
+
for microstate in self.states:
|
120
|
+
dG.append((microstate.PE - self.reference.PE) + microstate.delta_m * C * pH)
|
121
|
+
dG = np.array(dG)
|
122
|
+
|
123
|
+
print("dG=", dG)
|
124
|
+
Boltzmann_factors = np.exp(-dG/kT)
|
125
|
+
Z = np.sum(Boltzmann_factors)
|
126
|
+
p = Boltzmann_factors/Z
|
127
|
+
idx_p = sorted(list(enumerate(p)), key=lambda x: x[1], reverse=True)
|
128
|
+
# [(0, p0), (1, p1), ...]
|
129
|
+
|
130
|
+
return idx_p
|
131
|
+
|
132
|
+
|
133
|
+
def count(self) -> int:
|
134
|
+
return len(self.states)
|
135
|
+
|
136
|
+
|
137
|
+
def get_mol(self, idx: int) -> Mol:
|
138
|
+
return self.mols[idx]
|
@@ -232,6 +232,7 @@ def read_sdf(path:str | Path, std:bool=False, confs:bool=False, props:bool=True,
|
|
232
232
|
# start a new molecule
|
233
233
|
rdmol_2d = Chem.RemoveHs(rdmol)
|
234
234
|
AllChem.Compute2DCoords(rdmol_2d)
|
235
|
+
# initialize a new molecule with the H-removed 2D
|
235
236
|
new_mol = Mol(rdmol_2d, isomer_name, std=False) # atom indices remain unchanged.
|
236
237
|
new_conf = Conf(rdmol)
|
237
238
|
new_conf.props.update(props)
|
@@ -11,6 +11,7 @@ from pathlib import Path
|
|
11
11
|
from types import SimpleNamespace
|
12
12
|
|
13
13
|
from rdkit import Chem
|
14
|
+
from rdkit.Chem import rdmolops
|
14
15
|
from rdkit.Geometry import Point3D
|
15
16
|
|
16
17
|
|
@@ -32,6 +33,7 @@ class GFN2xTB:
|
|
32
33
|
assert self.is_xtb_ready(), "xtb is not accessible"
|
33
34
|
|
34
35
|
self.rdmol = molecule
|
36
|
+
self.charge = rdmolops.GetFormalCharge(self.rdmol)
|
35
37
|
self.natoms = molecule.GetNumAtoms()
|
36
38
|
self.symbols = [ atom.GetSymbol() for atom in molecule.GetAtoms() ]
|
37
39
|
self.positions = molecule.GetConformer().GetPositions().tolist()
|
@@ -74,7 +76,8 @@ class GFN2xTB:
|
|
74
76
|
test_geometry = os.path.join(temp_dir, 'coord')
|
75
77
|
with open(test_geometry, 'w') as f:
|
76
78
|
f.write('\n'.join(h2o))
|
77
|
-
proc = subprocess.run(['xtb', test_geometry, '--opt'],
|
79
|
+
proc = subprocess.run(['xtb', test_geometry, '--opt'],
|
80
|
+
cwd=temp_dir,
|
78
81
|
capture_output=True,
|
79
82
|
text=True)
|
80
83
|
assert proc.returncode == 0
|
@@ -117,14 +120,15 @@ $ cp -r xtb-dist/share /usr/local/ """)
|
|
117
120
|
bool: True if the --cpcmx option is working, False otherwise.
|
118
121
|
"""
|
119
122
|
if GFN2xTB.is_xtb_ready():
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
line
|
126
|
-
|
127
|
-
|
123
|
+
with tempfile.TemporaryDirectory() as temp_dir: # tmpdir is a string
|
124
|
+
cmd = ['xtb', '--cpcmx']
|
125
|
+
proc = subprocess.run(cmd, cwd=temp_dir, capture_output=True, text=True)
|
126
|
+
# we are expecting an error because no input file is given
|
127
|
+
assert proc.returncode != 0
|
128
|
+
for line in proc.stdout.split('\n'):
|
129
|
+
line = line.strip()
|
130
|
+
if 'CPCM-X library was not included' in line:
|
131
|
+
return False
|
128
132
|
|
129
133
|
return True
|
130
134
|
|
@@ -150,12 +154,13 @@ $ cp -r xtb-dist/share /usr/local/ """)
|
|
150
154
|
str | None: version statement.
|
151
155
|
"""
|
152
156
|
if GFN2xTB.is_xtb_ready():
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
157
|
+
with tempfile.TemporaryDirectory() as temp_dir: # tmpdir is a string
|
158
|
+
cmd = ['xtb', '--version']
|
159
|
+
proc = subprocess.run(cmd, cwd=temp_dir, capture_output=True, text=True)
|
160
|
+
assert proc.returncode == 0, "GFN2xTB() Error: xtb not available"
|
161
|
+
match = re.search('xtb\s+version\s+(?P<version>[\d.]+)', proc.stdout)
|
162
|
+
if match:
|
163
|
+
return match.group('version')
|
159
164
|
|
160
165
|
return None
|
161
166
|
|
@@ -265,109 +270,56 @@ $ cp -r xtb-dist/share /usr/local/ """)
|
|
265
270
|
return Wiberg_bond_orders
|
266
271
|
|
267
272
|
|
268
|
-
def cpx(self, verbose: bool = False) -> float | None:
|
269
|
-
"""Runs cpx and returns Gsolv (kcal/mol)
|
270
|
-
|
271
|
-
Warning:
|
272
|
-
Solvation energy obtained from `xtb --cpcmx water` differs from
|
273
|
-
`cpx --solvent water` (difference between gas.out and solv.out in terms of total energy).
|
274
|
-
There are other correction terms not clearly defined in the output files.
|
275
|
-
So, this method is not reliable and should be discarded
|
276
|
-
|
277
|
-
Returns:
|
278
|
-
float or None: Gsolv energy in kcal/mol or None.
|
279
|
-
"""
|
280
|
-
with tempfile.TemporaryDirectory() as temp_dir: # tmpdir is a string
|
281
|
-
workdir = Path(temp_dir)
|
282
|
-
if verbose:
|
283
|
-
logger.info(f'xtb.cpx workdir= {temp_dir}')
|
284
|
-
|
285
|
-
geometry_input_path = workdir / 'coord'
|
286
|
-
geometry_output_path = workdir / 'xtbtopo.mol'
|
287
|
-
gas_out_path = workdir / 'gas.out'
|
288
|
-
solv_out_path = workdir / 'solv.out'
|
289
|
-
wbo_path = workdir / 'wbo'
|
290
|
-
|
291
|
-
with open(geometry_input_path, 'w') as f:
|
292
|
-
f.write(self.to_turbomole_coord())
|
293
|
-
|
294
|
-
cmd = ['cpx']
|
295
|
-
options = ['--solvent', 'water']
|
296
|
-
|
297
|
-
proc = subprocess.run(cmd + options, cwd=temp_dir, capture_output=True, text=True)
|
298
|
-
# cpx creates the following files:
|
299
|
-
# charges gas.energy solute_sigma.txt solvent_sigma.txt xtbtopo.mol
|
300
|
-
# coord gas.out solute_sigma3.txt solvent_sigma3.txt
|
301
|
-
# error solute.cosmo solv.out wbo
|
302
|
-
|
303
|
-
# example of solv.out
|
304
|
-
# :::::::::::::::::::::::::::::::::::::::::::::::::::::
|
305
|
-
# :: SUMMARY ::
|
306
|
-
# :::::::::::::::::::::::::::::::::::::::::::::::::::::
|
307
|
-
# :: total energy -119.507131639760 Eh ::
|
308
|
-
# :: w/o Gsasa/hb/shift -119.494560363045 Eh ::
|
309
|
-
# :: gradient norm 0.084154442395 Eh/a0 ::
|
310
|
-
# :: HOMO-LUMO gap 2.966157362876 eV ::
|
311
|
-
# ::.................................................::
|
312
|
-
# :: SCC energy -121.121278922798 Eh ::
|
313
|
-
# :: -> isotropic ES 0.180705208303 Eh ::
|
314
|
-
# :: -> anisotropic ES 0.003924951393 Eh ::
|
315
|
-
# :: -> anisotropic XC 0.040710819025 Eh ::
|
316
|
-
# :: -> dispersion -0.088336282215 Eh ::
|
317
|
-
# :: -> Gsolv -0.039236762590 Eh ::
|
318
|
-
# :: -> Gelec -0.026665485874 Eh ::
|
319
|
-
# :: -> Gsasa -0.012571276716 Eh ::
|
320
|
-
# :: -> Ghb 0.000000000000 Eh ::
|
321
|
-
# :: -> Gshift 0.000000000000 Eh ::
|
322
|
-
# :: repulsion energy 1.614147283037 Eh ::
|
323
|
-
# :: add. restraining 0.000000000000 Eh ::
|
324
|
-
# :: total charge -0.000000000000 e ::
|
325
|
-
# :::::::::::::::::::::::::::::::::::::::::::::::::::::
|
326
|
-
|
327
|
-
# example gas.out
|
328
|
-
# :::::::::::::::::::::::::::::::::::::::::::::::::::::
|
329
|
-
# :: SUMMARY ::
|
330
|
-
# :::::::::::::::::::::::::::::::::::::::::::::::::::::
|
331
|
-
# :: total energy -119.473726280382 Eh ::
|
332
|
-
# :: gradient norm 0.085445002241 Eh/a0 ::
|
333
|
-
# :: HOMO-LUMO gap 2.562893747102 eV ::
|
334
|
-
# ::.................................................::
|
335
|
-
# :: SCC energy -121.087873563419 Eh ::
|
336
|
-
# :: -> isotropic ES 0.152557320965 Eh ::
|
337
|
-
# :: -> anisotropic ES 0.007343156635 Eh ::
|
338
|
-
# :: -> anisotropic XC 0.039625076440 Eh ::
|
339
|
-
# :: -> dispersion -0.088605122696 Eh ::
|
340
|
-
# :: repulsion energy 1.614147283037 Eh ::
|
341
|
-
# :: add. restraining 0.000000000000 Eh ::
|
342
|
-
# :: total charge -0.000000000000 e ::
|
343
|
-
# :::::::::::::::::::::::::::::::::::::::::::::::::::::
|
344
|
-
|
345
|
-
if proc.returncode == 0:
|
346
|
-
total_energy_solv = None
|
347
|
-
total_energy_gas = None
|
348
|
-
|
349
|
-
with open(solv_out_path, 'r') as f:
|
350
|
-
for line in f:
|
351
|
-
if 'total energy' in line:
|
352
|
-
m = re.search(r"total energy\s+(?P<solv>[-+]?\d*\.?\d+)\s+Eh", line)
|
353
|
-
total_energy_solv = float(m.group('solv'))
|
354
|
-
with open(gas_out_path, 'r') as f:
|
355
|
-
for line in f:
|
356
|
-
if 'total energy' in line:
|
357
|
-
m = re.search(r"total energy\s+(?P<gas>[-+]?\d*.?\d+)\s+Eh", line)
|
358
|
-
total_energy_gas = float(m.group('gas'))
|
359
|
-
|
360
|
-
if total_energy_solv and total_energy_gas:
|
361
|
-
return (total_energy_solv - total_energy_gas) * hartree2kcalpermol
|
362
|
-
|
363
|
-
return None
|
364
|
-
|
365
|
-
|
366
273
|
def singlepoint(self, water: str | None = None, verbose: bool = False) -> SimpleNamespace:
|
367
274
|
"""Calculate single point energy.
|
368
275
|
|
369
276
|
Total energy from xtb output in atomic units (Eh, hartree) is converted to kcal/mol.
|
370
277
|
|
278
|
+
Options:
|
279
|
+
```sh
|
280
|
+
-c, --chrg INT
|
281
|
+
specify molecular charge as INT, overrides .CHRG file and xcontrol option
|
282
|
+
|
283
|
+
--scc, --sp
|
284
|
+
performs a single point calculation
|
285
|
+
|
286
|
+
--gfn INT
|
287
|
+
specify parametrisation of GFN-xTB (default = 2)
|
288
|
+
|
289
|
+
--json
|
290
|
+
write xtbout.json file
|
291
|
+
|
292
|
+
--alpb SOLVENT [STATE]
|
293
|
+
analytical linearized Poisson-Boltzmann (ALPB) model,
|
294
|
+
available solvents are acetone, acetonitrile, aniline, benzaldehyde,
|
295
|
+
benzene, ch2cl2, chcl3, cs2, dioxane, dmf, dmso, ether, ethylacetate, furane,
|
296
|
+
hexandecane, hexane, methanol, nitromethane, octanol, woctanol, phenol, toluene,
|
297
|
+
thf, water.
|
298
|
+
The solvent input is not case-sensitive. The Gsolv
|
299
|
+
reference state can be chosen as reference, bar1M, or gsolv (default).
|
300
|
+
|
301
|
+
-g, --gbsa SOLVENT [STATE]
|
302
|
+
generalized born (GB) model with solvent accessable surface (SASA) model,
|
303
|
+
available solvents are acetone, acetonitrile, benzene (only GFN1-xTB), CH2Cl2,
|
304
|
+
CHCl3, CS2, DMF (only GFN2-xTB), DMSO, ether, H2O, methanol,
|
305
|
+
n-hexane (only GFN2-xTB), THF and toluene.
|
306
|
+
The solvent input is not case-sensitive.
|
307
|
+
The Gsolv reference state can be chosen as reference, bar1M, or gsolv (default).
|
308
|
+
|
309
|
+
--cosmo SOLVENT/EPSILON
|
310
|
+
domain decomposition conductor-like screening model (ddCOSMO),
|
311
|
+
available solvents are all solvents that are available for alpb.
|
312
|
+
Additionally, the dielectric constant can be set manually or an ideal conductor
|
313
|
+
can be chosen by setting epsilon to infinity.
|
314
|
+
|
315
|
+
--tmcosmo SOLVENT/EPSILON
|
316
|
+
same as --cosmo, but uses TM convention for writing the .cosmo files.
|
317
|
+
|
318
|
+
--cpcmx SOLVENT
|
319
|
+
extended conduction-like polarizable continuum solvation model (CPCM-X),
|
320
|
+
available solvents are all solvents included in the Minnesota Solvation Database.
|
321
|
+
```
|
322
|
+
|
371
323
|
Args:
|
372
324
|
water (str, optional) : water solvation model (choose 'gbsa' or 'alpb')
|
373
325
|
alpb: ALPB solvation model (Analytical Linearized Poisson-Boltzmann).
|
@@ -389,8 +341,7 @@ $ cp -r xtb-dist/share /usr/local/ """)
|
|
389
341
|
geometry.write(self.to_xyz())
|
390
342
|
|
391
343
|
cmd = ['xtb', geometry_input_path.as_posix()]
|
392
|
-
|
393
|
-
options = ['--gfn', '2', '--json']
|
344
|
+
options = ['-c', str(self.charge), '--sp', '--gfn', '2', '--json']
|
394
345
|
|
395
346
|
if water is not None and isinstance(water, str):
|
396
347
|
if water == 'gbsa':
|
@@ -408,7 +359,6 @@ $ cp -r xtb-dist/share /usr/local/ """)
|
|
408
359
|
# 'xtbout.json', 'xtbrestart', 'xtbtopo.mol', 'charges', and 'wbo' files will be
|
409
360
|
# created in the current working directory.
|
410
361
|
proc = subprocess.run(cmd + options, cwd=temp_dir, capture_output=True, text=True)
|
411
|
-
|
412
362
|
# if proc.returncode == 0:
|
413
363
|
# print("Standard Output:")
|
414
364
|
# print(proc.stdout)
|
@@ -438,6 +388,8 @@ $ cp -r xtb-dist/share /usr/local/ """)
|
|
438
388
|
Wiberg_bond_orders = self.load_wbo(wbo_path)
|
439
389
|
|
440
390
|
return SimpleNamespace(
|
391
|
+
natoms = self.natoms,
|
392
|
+
charge = self.charge,
|
441
393
|
PE = datadict['total energy'] * hartree2kcalpermol,
|
442
394
|
Gsolv = Gsolv,
|
443
395
|
charges = datadict['partial charges'],
|
@@ -452,12 +404,29 @@ $ cp -r xtb-dist/share /usr/local/ """)
|
|
452
404
|
def optimize(self, water: str | None = None, verbose: bool = False) -> SimpleNamespace:
|
453
405
|
"""Optimize geometry.
|
454
406
|
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
407
|
+
Options:
|
408
|
+
```sh
|
409
|
+
-c, --chrg INT
|
410
|
+
specify molecular charge as INT, overrides .CHRG file and xcontrol option
|
411
|
+
-o, --opt [LEVEL]
|
412
|
+
call ancopt(3) to perform a geometry optimization, levels from crude, sloppy,
|
413
|
+
loose, normal (default), tight, verytight to extreme can be chosen
|
414
|
+
--gfn INT
|
415
|
+
specify parametrisation of GFN-xTB (default = 2)
|
416
|
+
--json
|
417
|
+
write xtbout.json file
|
418
|
+
```
|
419
|
+
|
420
|
+
Notes:
|
421
|
+
Conda installed xtb has Fortran runtime error when optimizing geometry.
|
422
|
+
```sh
|
423
|
+
Fortran runtime errror:
|
424
|
+
At line 852 of file ../src/optimizer.f90 (unit = 6, file = 'stdout')
|
425
|
+
Fortran runtime error: Missing comma between descriptors
|
426
|
+
(1x,"("f7.2"%)")
|
427
|
+
^
|
428
|
+
Error termination.
|
429
|
+
```
|
461
430
|
|
462
431
|
Args:
|
463
432
|
water (str, optional) : water solvation model (choose 'gbsa' or 'alpb')
|
@@ -479,8 +448,7 @@ $ cp -r xtb-dist/share /usr/local/ """)
|
|
479
448
|
geometry.write(self.to_xyz())
|
480
449
|
|
481
450
|
cmd = ['xtb', geometry_input_path.as_posix()]
|
482
|
-
|
483
|
-
options = ['--opt', '--gfn', '2', '--json']
|
451
|
+
options = ['-c', str(self.charge), '-o', 'normal', '--gfn', '2', '--json']
|
484
452
|
|
485
453
|
if water is not None and isinstance(water, str):
|
486
454
|
if water == 'gbsa':
|
@@ -503,6 +471,8 @@ $ cp -r xtb-dist/share /usr/local/ """)
|
|
503
471
|
rdmol_opt = self.load_xyz(geometry_output_path)
|
504
472
|
|
505
473
|
return SimpleNamespace(
|
474
|
+
natoms = self.natoms,
|
475
|
+
charge = self.charge,
|
506
476
|
PE = datadict['total energy'] * hartree2kcalpermol,
|
507
477
|
charges = datadict['partial charges'],
|
508
478
|
wbo = Wiberg_bond_orders,
|
@@ -6,15 +6,13 @@ import rdworks.autograph
|
|
6
6
|
import math
|
7
7
|
import copy
|
8
8
|
import numpy as np
|
9
|
+
import tempfile
|
9
10
|
|
10
11
|
from rdworks import Conf, Mol, MolLibr
|
11
12
|
from rdworks.utils import recursive_round
|
12
13
|
|
13
14
|
|
14
15
|
datadir = Path(__file__).parent.resolve() / "data"
|
15
|
-
workdir = Path(__file__).parent.resolve() / "outfiles"
|
16
|
-
|
17
|
-
workdir.mkdir(exist_ok=True)
|
18
16
|
|
19
17
|
|
20
18
|
# python >=3.12 raises SyntaxWarning: invalid escape sequence
|
@@ -190,8 +188,10 @@ def test_has_substr():
|
|
190
188
|
def test_merge_csv():
|
191
189
|
libr = MolLibr(drug_smiles, drug_names)
|
192
190
|
libr = rdworks.merge_csv(libr, datadir / "drugs_20.csv", on='name')
|
193
|
-
|
194
|
-
|
191
|
+
with tempfile.TemporaryDirectory() as temp_dir: # tmpdir is a string
|
192
|
+
workdir = Path(temp_dir)
|
193
|
+
libr.to_csv(workdir / "test_merge_csv.csv")
|
194
|
+
assert libr.count() == 20
|
195
195
|
|
196
196
|
|
197
197
|
def test_read_smi():
|
@@ -217,42 +217,52 @@ def test_read_mae():
|
|
217
217
|
|
218
218
|
def test_to_csv():
|
219
219
|
libr1 = MolLibr(drug_smiles, drug_names, progress=False)
|
220
|
-
|
221
|
-
|
222
|
-
|
220
|
+
with tempfile.TemporaryDirectory() as temp_dir: # tmpdir is a string
|
221
|
+
workdir = Path(temp_dir)
|
222
|
+
libr1.qed(progress=False).to_csv(workdir / "test_to_csv.csv")
|
223
|
+
libr2 = rdworks.read_csv(workdir / "test_to_csv.csv", smiles='smiles', name='name', progress=False)
|
224
|
+
assert libr1 == libr2
|
223
225
|
|
224
226
|
|
225
227
|
def test_to_smi():
|
226
228
|
libr = MolLibr(drug_smiles, drug_names, progress=False)
|
227
|
-
|
228
|
-
|
229
|
+
with tempfile.TemporaryDirectory() as temp_dir: # tmpdir is a string
|
230
|
+
workdir = Path(temp_dir)
|
231
|
+
libr.to_smi(workdir / "test_to_smi.smi.gz")
|
232
|
+
libr.to_smi(workdir / "test_to_smi.smi")
|
229
233
|
|
230
234
|
|
231
235
|
def test_to_sdf():
|
232
236
|
libr = MolLibr(drug_smiles, drug_names, progress=False)
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
237
|
+
with tempfile.TemporaryDirectory() as temp_dir: # tmpdir is a string
|
238
|
+
workdir = Path(temp_dir)
|
239
|
+
libr.to_sdf(workdir / "test_to_sdf.sdf.gz")
|
240
|
+
libr.to_sdf(workdir / "test_to_sdf.sdf")
|
241
|
+
libr.qed().to_sdf(workdir / "test_to_sdf_with_qed.sdf") # QED and other properties should be here
|
242
|
+
supp = Chem.SDMolSupplier(workdir / "test_to_sdf_with_qed.sdf")
|
243
|
+
for m, mol in zip(supp, libr):
|
244
|
+
assert math.isclose(float(m.GetProp('MolWt')),
|
245
|
+
mol.props['MolWt'], rel_tol=1.0e-6, abs_tol=1.0e-3)
|
246
|
+
assert math.isclose(float(m.GetProp('QED')),
|
247
|
+
mol.props['QED'], rel_tol=1.0e-6, abs_tol=1.0e-3)
|
242
248
|
|
243
249
|
|
244
250
|
def test_to_png():
|
245
251
|
libr = MolLibr(drug_smiles, drug_names, progress=False)
|
246
|
-
|
247
|
-
|
252
|
+
with tempfile.TemporaryDirectory() as temp_dir: # tmpdir is a string
|
253
|
+
workdir = Path(temp_dir)
|
254
|
+
libr.to_png(workdir / "test_to_png.png")
|
255
|
+
libr.to_png(workdir / "test_to_png_with_index.png", atom_index=True)
|
248
256
|
|
249
257
|
|
250
258
|
def test_to_svg():
|
251
259
|
libr = MolLibr(drug_smiles, drug_names, progress=False)
|
252
|
-
with
|
253
|
-
|
254
|
-
|
255
|
-
|
260
|
+
with tempfile.TemporaryDirectory() as temp_dir: # tmpdir is a string
|
261
|
+
workdir = Path(temp_dir)
|
262
|
+
with open(workdir / "test_to_svg.svg", "w") as svg:
|
263
|
+
svg.write(libr.to_svg())
|
264
|
+
head = libr.to_svg()[:100]
|
265
|
+
assert head.startswith('<?xml') and ("<svg" in head)
|
256
266
|
|
257
267
|
|
258
268
|
def test_expand_rgroup():
|
@@ -265,9 +275,11 @@ def test_expand_rgroup():
|
|
265
275
|
|
266
276
|
def test_scaffold_tree():
|
267
277
|
libr = MolLibr(drug_smiles[:4], drug_names[:4])
|
268
|
-
|
269
|
-
|
270
|
-
|
278
|
+
with tempfile.TemporaryDirectory() as temp_dir: # tmpdir is a string
|
279
|
+
workdir = Path(temp_dir)
|
280
|
+
for mol in libr:
|
281
|
+
adhoc_libr = MolLibr(rdworks.scaffold_tree(mol.rdmol)).rename(prefix=mol.name)
|
282
|
+
adhoc_libr.to_png(workdir / f'unittest_84_{mol.name}.png')
|
271
283
|
|
272
284
|
|
273
285
|
def test_MatchedSeries():
|
@@ -465,4 +477,38 @@ def test_serialization():
|
|
465
477
|
rebuilt = Mol().deserialize(serialized)
|
466
478
|
assert rebuilt.count() == 10
|
467
479
|
assert rebuilt.name == name
|
468
|
-
assert rebuilt == mol
|
480
|
+
assert rebuilt == mol
|
481
|
+
|
482
|
+
|
483
|
+
def test_protonate_deprotonate():
|
484
|
+
_ = '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'
|
485
|
+
mol = Mol().deserialize(_, compressed=True)
|
486
|
+
|
487
|
+
assert mol.confs[0].props == {'atoms': 60, 'charge': 0, 'idx': 11, 'pka_type': 'basic', 'pka': 5.066}
|
488
|
+
assert mol.confs[1].props == {'atoms': 60, 'charge': 0, 'idx': 16, 'pka_type': 'basic', 'pka': 5.663}
|
489
|
+
assert mol.confs[2].props == {'atoms': 60, 'charge': 0, 'idx': 17, 'pka_type': 'basic', 'pka': 5.298}
|
490
|
+
assert mol.confs[3].props == {'atoms': 60, 'charge': 0, 'idx': 4, 'pka_type': 'acidic', 'pka': 11.705}
|
491
|
+
|
492
|
+
conf = mol.confs[0].copy()
|
493
|
+
conf = conf.protonate([11])
|
494
|
+
assert conf.positions().shape == (61, 3)
|
495
|
+
|
496
|
+
conf = mol.confs[0].copy()
|
497
|
+
conf = conf.protonate([11,16])
|
498
|
+
assert conf.positions().shape == (62, 3)
|
499
|
+
|
500
|
+
conf = mol.confs[0].copy()
|
501
|
+
conf = conf.protonate([11,16,17])
|
502
|
+
assert conf.positions().shape == (63, 3)
|
503
|
+
|
504
|
+
conf = mol.confs[0].copy()
|
505
|
+
conf = conf.deprotonate([4])
|
506
|
+
assert conf.positions().shape == (59, 3)
|
507
|
+
|
508
|
+
|
509
|
+
def test_from_molblock():
|
510
|
+
_ = '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'
|
511
|
+
mol = Mol().deserialize(_, compressed=True)
|
512
|
+
conf = mol.confs[0].copy()
|
513
|
+
mb = conf.to_molblock()
|
514
|
+
mol2 = Mol().from_molblock(mb)
|
@@ -1,11 +1,14 @@
|
|
1
1
|
import rdworks
|
2
|
+
from pathlib import Path
|
3
|
+
|
4
|
+
datadir = Path(__file__).parent.resolve() / "data"
|
2
5
|
|
3
6
|
def test_readin_qupkake_output():
|
4
|
-
libr = rdworks.read_sdf('
|
7
|
+
libr = rdworks.read_sdf(datadir / 'qupkake_output_SAMPL6_SM07.sdf', confs=True)
|
5
8
|
# libr contains one molecule because of confs=True
|
6
9
|
assert libr.count() == 1
|
7
10
|
for m in libr:
|
8
|
-
assert m.count() ==
|
11
|
+
assert m.count() == 3
|
9
12
|
print(m.props)
|
10
13
|
print()
|
11
14
|
for c in m:
|
@@ -4,6 +4,7 @@ from rdworks.testdata import drugs
|
|
4
4
|
|
5
5
|
from pathlib import Path
|
6
6
|
|
7
|
+
import tempfile
|
7
8
|
|
8
9
|
# In ASE, the default energy unit is eV (electron volt).
|
9
10
|
# It will be converted to kcal/mol
|
@@ -24,7 +25,6 @@ testmol = testmol.drop_confs(similar=True, verbose=True).sort_confs()
|
|
24
25
|
|
25
26
|
|
26
27
|
def test_xtb_wrapper():
|
27
|
-
from rdworks.xtb.wrapper import GFN2xTB
|
28
28
|
assert GFN2xTB.is_xtb_ready() == True
|
29
29
|
assert GFN2xTB.is_cpx_ready() == True
|
30
30
|
assert GFN2xTB.is_cpcmx_ready() == True
|
@@ -72,5 +72,5 @@ def test_optimize():
|
|
72
72
|
|
73
73
|
if __name__ == '__main__':
|
74
74
|
test_xtb_wrapper()
|
75
|
-
test_singlepoint()
|
76
|
-
test_optimize()
|
75
|
+
# test_singlepoint()
|
76
|
+
# test_optimize()
|
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
|