MoleditPy 2.2.0a1__py3-none-any.whl → 2.2.0a3__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.
Files changed (28) hide show
  1. moleditpy/modules/constants.py +1 -1
  2. moleditpy/modules/main_window_main_init.py +31 -13
  3. moleditpy/modules/main_window_ui_manager.py +21 -2
  4. moleditpy/modules/plugin_interface.py +1 -10
  5. moleditpy/modules/plugin_manager.py +0 -3
  6. {moleditpy-2.2.0a1.dist-info → moleditpy-2.2.0a3.dist-info}/METADATA +1 -1
  7. {moleditpy-2.2.0a1.dist-info → moleditpy-2.2.0a3.dist-info}/RECORD +11 -28
  8. moleditpy/plugins/Analysis/ms_spectrum_neo.py +0 -919
  9. moleditpy/plugins/File/animated_xyz_giffer.py +0 -583
  10. moleditpy/plugins/File/cube_viewer.py +0 -689
  11. moleditpy/plugins/File/gaussian_fchk_freq_analyzer.py +0 -1148
  12. moleditpy/plugins/File/mapped_cube_viewer.py +0 -552
  13. moleditpy/plugins/File/orca_out_freq_analyzer.py +0 -1226
  14. moleditpy/plugins/File/paste_xyz.py +0 -336
  15. moleditpy/plugins/Input Generator/gaussian_input_generator_neo.py +0 -930
  16. moleditpy/plugins/Input Generator/orca_input_generator_neo.py +0 -1028
  17. moleditpy/plugins/Input Generator/orca_xyz2inp_gui.py +0 -286
  18. moleditpy/plugins/Optimization/all-trans_optimizer.py +0 -65
  19. moleditpy/plugins/Optimization/complex_molecule_untangler.py +0 -268
  20. moleditpy/plugins/Optimization/conf_search.py +0 -224
  21. moleditpy/plugins/Utility/atom_colorizer.py +0 -547
  22. moleditpy/plugins/Utility/console.py +0 -163
  23. moleditpy/plugins/Utility/pubchem_ressolver.py +0 -244
  24. moleditpy/plugins/Utility/vdw_radii_overlay.py +0 -303
  25. {moleditpy-2.2.0a1.dist-info → moleditpy-2.2.0a3.dist-info}/WHEEL +0 -0
  26. {moleditpy-2.2.0a1.dist-info → moleditpy-2.2.0a3.dist-info}/entry_points.txt +0 -0
  27. {moleditpy-2.2.0a1.dist-info → moleditpy-2.2.0a3.dist-info}/licenses/LICENSE +0 -0
  28. {moleditpy-2.2.0a1.dist-info → moleditpy-2.2.0a3.dist-info}/top_level.txt +0 -0
@@ -1,224 +0,0 @@
1
- from PyQt6.QtWidgets import (
2
- QDialog, QVBoxLayout, QHBoxLayout, QTableWidget,
3
- QTableWidgetItem, QPushButton, QMessageBox, QLabel, QHeaderView, QAbstractItemView,
4
- QApplication, QComboBox
5
- )
6
- from PyQt6.QtCore import Qt
7
- from rdkit import Chem
8
- from rdkit.Chem import AllChem
9
- import copy
10
-
11
- PLUGIN_NAME = "Conformational Search"
12
- __version__="2025.12.25"
13
- __author__="HiroYokoyama"
14
-
15
- class ConformerSearchDialog(QDialog):
16
- def __init__(self, main_window, parent=None):
17
- super().__init__(parent)
18
- self.main_window = main_window
19
- self.setWindowTitle("Conformational Search & Preview")
20
- self.resize(400, 500)
21
-
22
- # メインウィンドウの分子への参照
23
- self.target_mol = getattr(main_window, "current_mol", None)
24
-
25
- # 計算用の一時的な分子(オリジナルを汚染しないため)
26
- self.temp_mol = None
27
- # 生成された配座データのリスト [(Energy, ConformerID), ...]
28
- self.conformer_data = []
29
-
30
- self.init_ui()
31
-
32
- def init_ui(self):
33
- layout = QVBoxLayout(self)
34
-
35
- # 説明ラベル
36
- self.lbl_info = QLabel("Click 'Run Search' to generate conformers.\nSelect a row to preview.")
37
- layout.addWidget(self.lbl_info)
38
-
39
- # Force Field Selection
40
- hbox_ff = QHBoxLayout()
41
- hbox_ff.addWidget(QLabel("Force Field:"))
42
- self.combo_ff = QComboBox()
43
- self.combo_ff.addItems(["MMFF94", "UFF"])
44
- hbox_ff.addWidget(self.combo_ff)
45
- hbox_ff.addStretch()
46
- layout.addLayout(hbox_ff)
47
-
48
- # Set default based on main window setting
49
- default_method = getattr(self.main_window, "optimization_method", "MMFF_RDKIT")
50
- if default_method:
51
- default_method = default_method.upper()
52
- if "UFF" in default_method:
53
- self.combo_ff.setCurrentText("UFF")
54
- else:
55
- self.combo_ff.setCurrentText("MMFF94")
56
-
57
- # 結果表示用テーブル
58
- self.table = QTableWidget()
59
- self.table.setColumnCount(2)
60
- self.table.setHorizontalHeaderLabels(["Rank", "Energy (kcal/mol)"])
61
- self.table.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeMode.Stretch)
62
- self.table.setSelectionBehavior(QAbstractItemView.SelectionBehavior.SelectRows)
63
- self.table.setSelectionMode(QAbstractItemView.SelectionMode.SingleSelection)
64
- self.table.itemClicked.connect(self.preview_conformer)
65
- layout.addWidget(self.table)
66
-
67
- # ボタンエリア
68
- btn_layout = QHBoxLayout()
69
- self.btn_run = QPushButton("Run Search")
70
- self.btn_run.clicked.connect(self.run_search)
71
-
72
- self.btn_close = QPushButton("Close")
73
- self.btn_close.clicked.connect(self.accept) # 閉じる(現在のプレビュー状態で確定)
74
-
75
- btn_layout.addWidget(self.btn_run)
76
- btn_layout.addWidget(self.btn_close)
77
- layout.addLayout(btn_layout)
78
-
79
- def accept(self):
80
- # Push undo state when closing the dialog (confirming the selection)
81
- if hasattr(self.main_window, "push_undo_state"):
82
- self.main_window.push_undo_state()
83
- super().accept()
84
-
85
- def run_search(self):
86
- if not self.target_mol:
87
- return
88
-
89
- self.btn_run.setEnabled(False)
90
- self.lbl_info.setText("Running conformational search... please wait.")
91
- QApplication.processEvents()
92
-
93
- try:
94
- # 計算用に分子を複製(水素が付加されていることを推奨)
95
- mol_calc = copy.deepcopy(self.target_mol)
96
-
97
- # 1. 配座生成 (ETKDGv3)
98
- params = AllChem.ETKDGv3()
99
- params.useSmallRingTorsions = True
100
- cids = AllChem.EmbedMultipleConfs(mol_calc, numConfs=30, params=params)
101
-
102
- if not cids:
103
- QMessageBox.warning(self, PLUGIN_NAME, "Failed to generate conformers.")
104
- self.lbl_info.setText("Failed.")
105
- self.btn_run.setEnabled(True)
106
- return
107
-
108
- # 2. 構造最適化とエネルギー計算
109
- results = []
110
- selected_ff = self.combo_ff.currentText()
111
-
112
- for i, cid in enumerate(cids):
113
- energy = None
114
-
115
- if selected_ff == "MMFF94":
116
- # MMFF94 Optimize
117
- if AllChem.MMFFOptimizeMolecule(mol_calc, confId=cid) != -1:
118
- # Calculate Energy
119
- prop = AllChem.MMFFGetMoleculeProperties(mol_calc)
120
- if prop:
121
- ff = AllChem.MMFFGetMoleculeForceField(mol_calc, prop, confId=cid)
122
- if ff:
123
- energy = ff.CalcEnergy()
124
-
125
- elif selected_ff == "UFF":
126
- # UFF Optimize
127
- if AllChem.UFFOptimizeMolecule(mol_calc, confId=cid) != -1:
128
- # Calculate Energy
129
- ff = AllChem.UFFGetMoleculeForceField(mol_calc, confId=cid)
130
- if ff:
131
- energy = ff.CalcEnergy()
132
-
133
- if energy is not None:
134
- results.append((energy, cid))
135
-
136
- # UIの応答性を維持
137
- if i % 5 == 0:
138
- QApplication.processEvents()
139
-
140
- if not results:
141
- QMessageBox.warning(self, PLUGIN_NAME, f"Optimization failed with {selected_ff}.")
142
- self.btn_run.setEnabled(True)
143
- return
144
-
145
- # エネルギーが低い順にソート
146
- results.sort(key=lambda x: x[0])
147
-
148
- # データを保持
149
- self.temp_mol = mol_calc
150
- self.conformer_data = results
151
-
152
- # テーブル更新
153
- self.update_table()
154
- self.lbl_info.setText(f"Found {len(results)} conformers ({selected_ff}).")
155
-
156
- except Exception as e:
157
- QMessageBox.critical(self, PLUGIN_NAME, f"Error during search: {str(e)}")
158
- self.lbl_info.setText("Error occurred.")
159
- finally:
160
- self.btn_run.setEnabled(True)
161
-
162
- def update_table(self):
163
- self.table.setRowCount(0)
164
- # base_energy = self.conformer_data[0][0] if self.conformer_data else 0
165
-
166
- for rank, (energy, cid) in enumerate(self.conformer_data):
167
- row_idx = self.table.rowCount()
168
- self.table.insertRow(row_idx)
169
-
170
- # Rank
171
- self.table.setItem(row_idx, 0, QTableWidgetItem(str(rank + 1)))
172
-
173
- # Energy
174
- energy_str = f"{energy:.4f}"
175
- self.table.setItem(row_idx, 1, QTableWidgetItem(energy_str))
176
-
177
- # 隠しデータとしてConformer IDを持たせる
178
- self.table.item(row_idx, 0).setData(Qt.ItemDataRole.UserRole, cid)
179
-
180
- def preview_conformer(self, item):
181
- """リスト選択時にメインウィンドウの表示を更新"""
182
- if not self.temp_mol or not self.target_mol:
183
- return
184
-
185
- row = item.row()
186
- # Rankカラム(0)にCIDを埋め込んでいるので取得
187
- cid = self.table.item(row, 0).data(Qt.ItemDataRole.UserRole)
188
-
189
- # 選択された配座の座標を取得
190
- source_conf = self.temp_mol.GetConformer(cid)
191
- target_conf = self.target_mol.GetConformer() # 現在の表示用Conformer
192
-
193
- # 座標のコピー
194
- for i in range(self.target_mol.GetNumAtoms()):
195
- pos = source_conf.GetAtomPosition(i)
196
- target_conf.SetAtomPosition(i, pos)
197
-
198
- # ビューの更新(ユーザー提供コードのロジックに従う)
199
- if hasattr(self.main_window, "draw_molecule_3d"):
200
- self.main_window.draw_molecule_3d(self.target_mol)
201
- elif hasattr(self.main_window, "update_view"):
202
- self.main_window.update_view()
203
- elif hasattr(self.main_window, "gl_widget"):
204
- # GLWidgetのリフレッシュ
205
- getattr(self.main_window.gl_widget, "update", lambda: None)()
206
-
207
- def run(mw):
208
- mol = getattr(mw, "current_mol", None)
209
- if not mol:
210
- QMessageBox.warning(mw, PLUGIN_NAME, "No molecule loaded.")
211
- return
212
-
213
- # 既存のダイアログがあればアクティブにする
214
- if hasattr(mw, "_conformer_search_dialog") and mw._conformer_search_dialog.isVisible():
215
- mw._conformer_search_dialog.raise_()
216
- mw._conformer_search_dialog.activateWindow()
217
- return
218
-
219
- dialog = ConformerSearchDialog(mw, parent=mw)
220
- # 参照を保持してGCを防ぐ
221
- mw._conformer_search_dialog = dialog
222
- dialog.show() # モーダルではなくModeless(非ブロック)で表示
223
-
224
- # initialize removed as it only registered the menu action