Skip to content

Commit 7b66aeb

Browse files
committed
bug fixes with cached old jobs and %Vbur differences
1 parent 505c518 commit 7b66aeb

10 files changed

+118
-56
lines changed

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
![SEQCROW](SEQCROW.png)
1+
![SEQCROW](SEQCROW_dev.png)
22
# SEQCROW
33
SEQCROW is an AaronTools-based plugin for <a href="https://www.cgl.ucsf.edu/chimerax/" target="_blank">UCSF ChimeraX</a>, a cross-platform 3D molecular graphics program.
44
SEQCROW extends ChimeraX by adding tools to build and modify complex molecular structures, map new catalysts and ligands onto previously-computed structures, and manage AaronTools libraries.

SEQCROW.png SEQCROW_dev.png

File renamed without changes.

dist/SEQCROW-1.4.5a1-py3-none-any.whl

625 Bytes
Binary file not shown.

src/commands/percent_Vbur.py

+21-14
Original file line numberDiff line numberDiff line change
@@ -1036,11 +1036,14 @@ def vbur_difference_vis(
10361036
coords1 = geom1.coordinates(atoms_within_radius1)
10371037
coords2 = geom2.coordinates(atoms_within_radius2)
10381038
coords2 -= center_coords2
1039-
basis2_inv = np.linalg.inv(basis2)
1040-
coords2 = np.dot(coords2, basis2_inv)
1041-
coords2 = np.dot(coords2, basis1)
1039+
h = np.dot(basis2.T, basis1)
1040+
u, s, v = np.linalg.svd(h)
1041+
R = np.matmul(v, u.T)
1042+
if np.sign(np.linalg.det(R)) < 0:
1043+
R[:, 2] *= -1
1044+
coords2 = np.matmul(coords2, R.T)
10421045
coords2 += center_coords1
1043-
1046+
10441047
atom_dist1 = distance_matrix(coords1, coords1)
10451048
atom_dist12 = distance_matrix(coords1, coords2)
10461049
atom_dist2 = distance_matrix(coords2, coords2)
@@ -1195,6 +1198,8 @@ def vbur_difference_vis(
11951198
# intersection with big sphere
11961199
if d + r1 > radius:
11971200
theta = np.arccos((r1 ** 2 - radius ** 2 - d ** 2) / (-2 * d * radius))
1201+
if np.isnan(theta):
1202+
continue
11981203
h = radius * np.sin(theta)
11991204
b = radius * np.cos(theta)
12001205
p = b * v_n
@@ -1500,10 +1505,11 @@ def vbur_difference_vis(
15001505
sphere = sphere[mask]
15011506

15021507
sphere = np.array(sphere)
1503-
sphere = np.concatenate((
1504-
sphere,
1505-
np.array(center_added_points1),
1506-
))
1508+
1509+
sphere = np.concatenate((
1510+
sphere,
1511+
np.array(center_added_points1),
1512+
))
15071513

15081514
if len(center_added_points2) > 1:
15091515
mask = np.ones(len(sphere), dtype=bool)
@@ -1516,10 +1522,11 @@ def vbur_difference_vis(
15161522

15171523
sphere = np.array(sphere)
15181524
n_sphere = len(sphere)
1519-
sphere = np.concatenate((
1520-
sphere,
1521-
np.array(center_added_points2),
1522-
))
1525+
1526+
sphere = np.concatenate((
1527+
sphere,
1528+
np.array(center_added_points2),
1529+
))
15231530

15241531
center_hull = ConvexHull(sphere / radius)
15251532
sphere += center_coords1
@@ -1546,7 +1553,7 @@ def vbur_difference_vis(
15461553
norms = -keep_sphere / radius
15471554

15481555
triangles1.extend(keep_tri + len(vertices1))
1549-
vertices1.extend(keep_sphere + center_coords1)
1556+
vertices1.extend(keep_sphere)
15501557
normals1.extend(norms)
15511558

15521559
if len(add_to_mdl_2_verts) > 3:
@@ -1559,7 +1566,7 @@ def vbur_difference_vis(
15591566
norms = -keep_sphere / radius
15601567

15611568
triangles2.extend(keep_tri + len(vertices2))
1562-
vertices2.extend(keep_sphere + center_coords1)
1569+
vertices2.extend(keep_sphere)
15631570
normals2.extend(norms)
15641571

15651572
# the triangles need to be reordered so the points are

src/jobs.py

+6-8
Original file line numberDiff line numberDiff line change
@@ -481,14 +481,12 @@ def run(self):
481481
else:
482482
self.process = subprocess.Popen(args, cwd=self.scratch_dir, stdout=log, stderr=log)
483483

484-
possible_fchk_name = os.path.join(
485-
self.scratch_dir, self.name + ".fchk"
486-
)
487-
if os.path.exists(possible_fchk_name):
488-
self.output_name = [
489-
self.output_name,
490-
possible_fchk_name
491-
]
484+
for f in os.listdir(self.scratch_dir):
485+
if f.lower().endswith("fchk") or f.lower().endswith("fch"):
486+
self.output_name = {
487+
"out": self.output_name,
488+
"fchk": os.path.join(self.scratch_dir, f),
489+
}
492490

493491
self.process.communicate()
494492
self.process = None

src/managers/job_manager.py

+4-1
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,10 @@ def init_queue(self):
9292
self.session,
9393
job['theory'],
9494
]
95-
kwargs = job["job_options"]
95+
try:
96+
kwargs = job["job_options"]
97+
except KeyError:
98+
kwargs = {}
9699
if issubclass(job_cls, TSSJob):
97100
args.extend([
98101
job["reactant"],

src/residue_collection.py

+20
Original file line numberDiff line numberDiff line change
@@ -933,6 +933,26 @@ def get_chimera(self, session, coordsets=False, filereader=None, discard_residue
933933

934934
self.update_geometry(cur_coords)
935935

936+
if filereader is not None and "Löwdin Charges" in filereader.other:
937+
for atom, charge in zip(struc.atoms, filereader.other["Löwdin Charges"]):
938+
atom.loewdinCharge = charge
939+
atom.charge = charge
940+
941+
if not any(attr[0] == "loewdinCharge" for attr in atom.custom_attrs):
942+
atom.register_attr(
943+
session,
944+
"loewdinCharge",
945+
"seqcrow ResidueCollection.get_chimera",
946+
attr_type=float
947+
)
948+
if not any(attr[0] == "charge" for attr in atom.custom_attrs):
949+
atom.register_attr(
950+
session,
951+
"charge",
952+
"seqcrow ResidueCollection.get_chimera",
953+
attr_type=float
954+
)
955+
936956
if filereader is not None and "Mulliken Charges" in filereader.other:
937957
for atom, charge in zip(struc.atoms, filereader.other["Mulliken Charges"]):
938958
atom.mullikenCharge = charge

src/tests/substitute_command.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ def test_substitute_modify(self):
2121
mdl = self.session.models.list()[0]
2222
rescol = ResidueCollection(mdl)
2323

24-
self.assertTrue(validate(ref, rescol))
24+
self.assertTrue(validate(ref, rescol, thresh="loose"))
2525

2626
def test_substitute_copy(self):
2727
ref1 = ResidueCollection(self.chlorobenzene)
@@ -35,6 +35,6 @@ def test_substitute_copy(self):
3535
mdl2 = self.session.models.list()[2]
3636
rescol2 = ResidueCollection(mdl2)
3737

38-
self.assertTrue(validate(ref1, rescol1))
39-
self.assertTrue(validate(ref2, rescol2))
38+
self.assertTrue(validate(ref1, rescol1, thresh="loose"))
39+
self.assertTrue(validate(ref2, rescol2, thresh="loose"))
4040

src/tools/cone_angle.py

+36-18
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@
2121
QTableWidgetItem,
2222
QHeaderView,
2323
QMessageBox,
24+
QLabel,
25+
QTabWidget,
26+
QWidget,
2427
)
2528

2629
from AaronTools.component import Component
@@ -59,43 +62,60 @@ def __init__(self, session, name):
5962
self._build_ui()
6063

6164
def _build_ui(self):
65+
tabs = QTabWidget()
66+
6267
layout = QFormLayout()
68+
layout.addRow(tabs)
69+
70+
cone_widget = QWidget()
71+
cone_layout = QFormLayout(cone_widget)
72+
73+
cone_layout.addRow("1.", QLabel("select ligand"))
74+
75+
set_ligand_button = QPushButton("set ligand to current selection")
76+
set_ligand_button.clicked.connect(self.set_ligand)
77+
cone_layout.addRow("2.", set_ligand_button)
78+
self.set_ligand_button = set_ligand_button
79+
80+
cone_layout.addRow("3.", QLabel("change selection to metal center"))
81+
82+
calc_cone_button = QPushButton("calculate cone angle")
83+
calc_cone_button.clicked.connect(self.calc_cone)
84+
cone_layout.addRow("4.", calc_cone_button)
85+
self.calc_cone_button = calc_cone_button
86+
87+
tabs.addTab(cone_widget, "cone angle")
88+
89+
settings = QWidget()
90+
settings_layout = QFormLayout(settings)
6391

6492
self.cone_option = QComboBox()
6593
self.cone_option.addItems(["Tolman (Unsymmetrical)", "Exact"])
6694
ndx = self.cone_option.findText(self.settings.cone_option, Qt.MatchExactly)
6795
self.cone_option.setCurrentIndex(ndx)
68-
layout.addRow("method:", self.cone_option)
96+
settings_layout.addRow("method:", self.cone_option)
6997

7098
self.radii_option = QComboBox()
7199
self.radii_option.addItems(["Bondi", "UMN"])
72100
ndx = self.radii_option.findText(self.settings.radii, Qt.MatchExactly)
73101
self.radii_option.setCurrentIndex(ndx)
74-
layout.addRow("radii:", self.radii_option)
102+
settings_layout.addRow("radii:", self.radii_option)
75103

76104
self.display_cone = QCheckBox()
77105
self.display_cone.setChecked(self.settings.display_cone)
78-
layout.addRow("show cone:", self.display_cone)
79-
106+
settings_layout.addRow("show cone:", self.display_cone)
107+
80108
self.display_radii = QCheckBox()
81109
self.display_radii.setChecked(self.settings.display_radii)
82-
layout.addRow("show radii:", self.display_radii)
110+
settings_layout.addRow("show radii:", self.display_radii)
83111

84-
set_ligand_button = QPushButton("set ligand to current selection")
85-
set_ligand_button.clicked.connect(self.set_ligand)
86-
layout.addRow(set_ligand_button)
87-
self.set_ligand_button = set_ligand_button
88-
89-
calc_cone_button = QPushButton("calculate cone angle for ligand on selected center")
90-
calc_cone_button.clicked.connect(self.calc_cone)
91-
layout.addRow(calc_cone_button)
92-
self.calc_cone_button = calc_cone_button
93-
94112
remove_cone_button = QPushButton("remove cone visualizations")
95113
remove_cone_button.clicked.connect(self.del_cone)
96-
layout.addRow(remove_cone_button)
114+
settings_layout.addRow(remove_cone_button)
97115
self.remove_cone_button = remove_cone_button
98116

117+
tabs.addTab(settings, "options")
118+
99119
self.table = QTableWidget()
100120
self.table.setColumnCount(3)
101121
self.table.setHorizontalHeaderLabels(
@@ -291,8 +311,6 @@ def calc_cone(self, *args):
291311
at_center = rescol.find_exact(AtomSpec(center_atom.atomspec))[0]
292312
if center_atom.structure in self.ligands:
293313
lig_atoms = [AtomSpec(atom.atomspec) for atom in self.ligands[center_atom.structure]]
294-
print("structure in ligand list")
295-
print(rescol.find(BondedTo(at_center), lig_atoms))
296314
comp = Component(
297315
rescol.find(
298316
lig_atoms,

src/tools/percent_Vbur.py

+27-11
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,26 @@
88

99
from Qt.QtCore import Qt
1010
from Qt.QtGui import QKeySequence
11-
from Qt.QtWidgets import QPushButton, QFormLayout, QComboBox, QCheckBox, QMenuBar, QAction, \
12-
QFileDialog, QApplication, QTableWidget, QTableWidgetItem, \
13-
QHeaderView, QSpinBox, QWidget, QGridLayout, \
14-
QTabWidget, QDoubleSpinBox, QMessageBox
11+
from Qt.QtWidgets import (
12+
QPushButton,
13+
QFormLayout,
14+
QComboBox,
15+
QCheckBox,
16+
QMenuBar,
17+
QAction,
18+
QFileDialog,
19+
QApplication,
20+
QTableWidget,
21+
QTableWidgetItem,
22+
QHeaderView,
23+
QSpinBox,
24+
QWidget,
25+
QGridLayout,
26+
QTabWidget,
27+
QDoubleSpinBox,
28+
QMessageBox,
29+
QLabel,
30+
)
1531

1632
from SEQCROW.commands.percent_Vbur import percent_vbur as percent_vbur_cmd
1733
from SEQCROW.tools.per_frame_plot import NavigationToolbar
@@ -101,14 +117,15 @@ def _build_ui(self):
101117
self.scale.setRange(1., 1.5)
102118
settings_layout.addRow("VDW scale:", self.scale)
103119

120+
calc_layout.addRow("1.", QLabel("select ligand"))
104121
set_ligand_atoms = QPushButton("set ligands to current selection")
105122
set_ligand_atoms.clicked.connect(self.set_ligand_atoms)
106123
set_ligand_atoms.setToolTip(
107124
"specify atoms to use in calculation\n" +
108125
"by default, all atoms will be used unless a single center is specified\n" +
109126
"in the case of a single center, all atoms except the center is used"
110127
)
111-
calc_layout.addRow(set_ligand_atoms)
128+
calc_layout.addRow("2.", set_ligand_atoms)
112129
self.set_ligand_atoms = set_ligand_atoms
113130

114131
self.radius = QDoubleSpinBox()
@@ -197,13 +214,13 @@ def _build_ui(self):
197214
lambda text, widget=mc_widget: widget.setVisible(text == "Monte-Carlo")
198215
)
199216

200-
self.use_centroid = QCheckBox()
217+
calc_layout.addRow("3.", QLabel("change selection to reaction center"))
218+
self.use_centroid = QCheckBox("use centroid of centers")
201219
self.use_centroid.setChecked(self.settings.use_centroid)
202220
self.use_centroid.setToolTip(
203-
"place the center between selected atoms\n" +
204-
"might be useful for polydentate ligands"
221+
"place the center between selected atoms"
205222
)
206-
calc_layout.addRow("use centroid of centers:", self.use_centroid)
223+
calc_layout.addRow(self.use_centroid)
207224

208225

209226
self.steric_map = QCheckBox()
@@ -342,7 +359,7 @@ def _build_ui(self):
342359

343360
calc_vbur_button = QPushButton("calculate % buried volume for selected centers")
344361
calc_vbur_button.clicked.connect(self.calc_vbur)
345-
calc_layout.addRow(calc_vbur_button)
362+
calc_layout.addRow("4.", calc_vbur_button)
346363
self.calc_vbur_button = calc_vbur_button
347364

348365
remove_vbur_button = QPushButton("remove % buried volume visualizations")
@@ -720,7 +737,6 @@ def calc_vbur(self):
720737
self.table.resizeColumnToContents(1)
721738
self.table.resizeColumnToContents(2)
722739

723-
724740
def header_check(self, state):
725741
"""user has [un]checked the 'include header' option on the menu"""
726742
if state:

0 commit comments

Comments
 (0)