MoleditPy-linux 4.1.0__tar.gz → 4.1.2__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.
- {moleditpy_linux-4.1.0 → moleditpy_linux-4.1.2}/PKG-INFO +5 -5
- {moleditpy_linux-4.1.0 → moleditpy_linux-4.1.2}/README.md +4 -4
- {moleditpy_linux-4.1.0 → moleditpy_linux-4.1.2}/pyproject.toml +1 -1
- {moleditpy_linux-4.1.0 → moleditpy_linux-4.1.2}/src/MoleditPy_linux.egg-info/PKG-INFO +5 -5
- {moleditpy_linux-4.1.0 → moleditpy_linux-4.1.2}/src/moleditpy_linux/plugins/plugin_interface.py +11 -0
- {moleditpy_linux-4.1.0 → moleditpy_linux-4.1.2}/src/moleditpy_linux/ui/calculation_worker.py +60 -12
- {moleditpy_linux-4.1.0 → moleditpy_linux-4.1.2}/src/moleditpy_linux/ui/compute_logic.py +3 -3
- {moleditpy_linux-4.1.0 → moleditpy_linux-4.1.2}/src/moleditpy_linux/ui/io_logic.py +184 -111
- {moleditpy_linux-4.1.0 → moleditpy_linux-4.1.2}/src/moleditpy_linux/utils/constants.py +5 -0
- {moleditpy_linux-4.1.0 → moleditpy_linux-4.1.2}/LICENSE +0 -0
- {moleditpy_linux-4.1.0 → moleditpy_linux-4.1.2}/setup.cfg +0 -0
- {moleditpy_linux-4.1.0 → moleditpy_linux-4.1.2}/src/MoleditPy_linux.egg-info/SOURCES.txt +0 -0
- {moleditpy_linux-4.1.0 → moleditpy_linux-4.1.2}/src/MoleditPy_linux.egg-info/dependency_links.txt +0 -0
- {moleditpy_linux-4.1.0 → moleditpy_linux-4.1.2}/src/MoleditPy_linux.egg-info/entry_points.txt +0 -0
- {moleditpy_linux-4.1.0 → moleditpy_linux-4.1.2}/src/MoleditPy_linux.egg-info/requires.txt +0 -0
- {moleditpy_linux-4.1.0 → moleditpy_linux-4.1.2}/src/MoleditPy_linux.egg-info/top_level.txt +0 -0
- {moleditpy_linux-4.1.0 → moleditpy_linux-4.1.2}/src/moleditpy_linux/__init__.py +0 -0
- {moleditpy_linux-4.1.0 → moleditpy_linux-4.1.2}/src/moleditpy_linux/__main__.py +0 -0
- {moleditpy_linux-4.1.0 → moleditpy_linux-4.1.2}/src/moleditpy_linux/assets/file_icon.ico +0 -0
- {moleditpy_linux-4.1.0 → moleditpy_linux-4.1.2}/src/moleditpy_linux/assets/icon.icns +0 -0
- {moleditpy_linux-4.1.0 → moleditpy_linux-4.1.2}/src/moleditpy_linux/assets/icon.ico +0 -0
- {moleditpy_linux-4.1.0 → moleditpy_linux-4.1.2}/src/moleditpy_linux/assets/icon.png +0 -0
- {moleditpy_linux-4.1.0 → moleditpy_linux-4.1.2}/src/moleditpy_linux/core/__init__.py +0 -0
- {moleditpy_linux-4.1.0 → moleditpy_linux-4.1.2}/src/moleditpy_linux/core/mol_geometry.py +0 -0
- {moleditpy_linux-4.1.0 → moleditpy_linux-4.1.2}/src/moleditpy_linux/core/molecular_data.py +0 -0
- {moleditpy_linux-4.1.0 → moleditpy_linux-4.1.2}/src/moleditpy_linux/main.py +0 -0
- {moleditpy_linux-4.1.0 → moleditpy_linux-4.1.2}/src/moleditpy_linux/plugins/__init__.py +0 -0
- {moleditpy_linux-4.1.0 → moleditpy_linux-4.1.2}/src/moleditpy_linux/plugins/plugin_manager.py +0 -0
- {moleditpy_linux-4.1.0 → moleditpy_linux-4.1.2}/src/moleditpy_linux/plugins/plugin_manager_window.py +0 -0
- {moleditpy_linux-4.1.0 → moleditpy_linux-4.1.2}/src/moleditpy_linux/ui/__init__.py +0 -0
- {moleditpy_linux-4.1.0 → moleditpy_linux-4.1.2}/src/moleditpy_linux/ui/about_dialog.py +0 -0
- {moleditpy_linux-4.1.0 → moleditpy_linux-4.1.2}/src/moleditpy_linux/ui/align_plane_dialog.py +0 -0
- {moleditpy_linux-4.1.0 → moleditpy_linux-4.1.2}/src/moleditpy_linux/ui/alignment_dialog.py +0 -0
- {moleditpy_linux-4.1.0 → moleditpy_linux-4.1.2}/src/moleditpy_linux/ui/analysis_window.py +0 -0
- {moleditpy_linux-4.1.0 → moleditpy_linux-4.1.2}/src/moleditpy_linux/ui/angle_dialog.py +0 -0
- {moleditpy_linux-4.1.0 → moleditpy_linux-4.1.2}/src/moleditpy_linux/ui/app_state.py +0 -0
- {moleditpy_linux-4.1.0 → moleditpy_linux-4.1.2}/src/moleditpy_linux/ui/atom_item.py +0 -0
- {moleditpy_linux-4.1.0 → moleditpy_linux-4.1.2}/src/moleditpy_linux/ui/atom_picking.py +0 -0
- {moleditpy_linux-4.1.0 → moleditpy_linux-4.1.2}/src/moleditpy_linux/ui/base_picking_dialog.py +0 -0
- {moleditpy_linux-4.1.0 → moleditpy_linux-4.1.2}/src/moleditpy_linux/ui/bond_item.py +0 -0
- {moleditpy_linux-4.1.0 → moleditpy_linux-4.1.2}/src/moleditpy_linux/ui/bond_length_dialog.py +0 -0
- {moleditpy_linux-4.1.0 → moleditpy_linux-4.1.2}/src/moleditpy_linux/ui/color_settings_dialog.py +0 -0
- {moleditpy_linux-4.1.0 → moleditpy_linux-4.1.2}/src/moleditpy_linux/ui/constrained_optimization_dialog.py +0 -0
- {moleditpy_linux-4.1.0 → moleditpy_linux-4.1.2}/src/moleditpy_linux/ui/custom_interactor_style.py +0 -0
- {moleditpy_linux-4.1.0 → moleditpy_linux-4.1.2}/src/moleditpy_linux/ui/custom_qt_interactor.py +0 -0
- {moleditpy_linux-4.1.0 → moleditpy_linux-4.1.2}/src/moleditpy_linux/ui/dialog_3d_picking_mixin.py +0 -0
- {moleditpy_linux-4.1.0 → moleditpy_linux-4.1.2}/src/moleditpy_linux/ui/dialog_logic.py +0 -0
- {moleditpy_linux-4.1.0 → moleditpy_linux-4.1.2}/src/moleditpy_linux/ui/dihedral_dialog.py +0 -0
- {moleditpy_linux-4.1.0 → moleditpy_linux-4.1.2}/src/moleditpy_linux/ui/edit_3d_logic.py +0 -0
- {moleditpy_linux-4.1.0 → moleditpy_linux-4.1.2}/src/moleditpy_linux/ui/edit_actions_logic.py +0 -0
- {moleditpy_linux-4.1.0 → moleditpy_linux-4.1.2}/src/moleditpy_linux/ui/export_logic.py +0 -0
- {moleditpy_linux-4.1.0 → moleditpy_linux-4.1.2}/src/moleditpy_linux/ui/geometry_base_dialog.py +0 -0
- {moleditpy_linux-4.1.0 → moleditpy_linux-4.1.2}/src/moleditpy_linux/ui/main_window.py +0 -0
- {moleditpy_linux-4.1.0 → moleditpy_linux-4.1.2}/src/moleditpy_linux/ui/main_window_init.py +0 -0
- {moleditpy_linux-4.1.0 → moleditpy_linux-4.1.2}/src/moleditpy_linux/ui/mirror_dialog.py +0 -0
- {moleditpy_linux-4.1.0 → moleditpy_linux-4.1.2}/src/moleditpy_linux/ui/molecular_scene_handler.py +0 -0
- {moleditpy_linux-4.1.0 → moleditpy_linux-4.1.2}/src/moleditpy_linux/ui/molecule_scene.py +0 -0
- {moleditpy_linux-4.1.0 → moleditpy_linux-4.1.2}/src/moleditpy_linux/ui/move_group_dialog.py +0 -0
- {moleditpy_linux-4.1.0 → moleditpy_linux-4.1.2}/src/moleditpy_linux/ui/move_selected_atoms_dialog.py +0 -0
- {moleditpy_linux-4.1.0 → moleditpy_linux-4.1.2}/src/moleditpy_linux/ui/periodic_table_dialog.py +0 -0
- {moleditpy_linux-4.1.0 → moleditpy_linux-4.1.2}/src/moleditpy_linux/ui/planarize_dialog.py +0 -0
- {moleditpy_linux-4.1.0 → moleditpy_linux-4.1.2}/src/moleditpy_linux/ui/plugin_menu_manager.py +0 -0
- {moleditpy_linux-4.1.0 → moleditpy_linux-4.1.2}/src/moleditpy_linux/ui/settings_dialog.py +0 -0
- {moleditpy_linux-4.1.0 → moleditpy_linux-4.1.2}/src/moleditpy_linux/ui/settings_tabs/__init__.py +0 -0
- {moleditpy_linux-4.1.0 → moleditpy_linux-4.1.2}/src/moleditpy_linux/ui/settings_tabs/settings_2d_tab.py +0 -0
- {moleditpy_linux-4.1.0 → moleditpy_linux-4.1.2}/src/moleditpy_linux/ui/settings_tabs/settings_3d_tabs.py +0 -0
- {moleditpy_linux-4.1.0 → moleditpy_linux-4.1.2}/src/moleditpy_linux/ui/settings_tabs/settings_other_tab.py +0 -0
- {moleditpy_linux-4.1.0 → moleditpy_linux-4.1.2}/src/moleditpy_linux/ui/settings_tabs/settings_tab_base.py +0 -0
- {moleditpy_linux-4.1.0 → moleditpy_linux-4.1.2}/src/moleditpy_linux/ui/string_importers.py +0 -0
- {moleditpy_linux-4.1.0 → moleditpy_linux-4.1.2}/src/moleditpy_linux/ui/template_preview_item.py +0 -0
- {moleditpy_linux-4.1.0 → moleditpy_linux-4.1.2}/src/moleditpy_linux/ui/template_preview_view.py +0 -0
- {moleditpy_linux-4.1.0 → moleditpy_linux-4.1.2}/src/moleditpy_linux/ui/translation_dialog.py +0 -0
- {moleditpy_linux-4.1.0 → moleditpy_linux-4.1.2}/src/moleditpy_linux/ui/ui_manager.py +0 -0
- {moleditpy_linux-4.1.0 → moleditpy_linux-4.1.2}/src/moleditpy_linux/ui/user_template_dialog.py +0 -0
- {moleditpy_linux-4.1.0 → moleditpy_linux-4.1.2}/src/moleditpy_linux/ui/view_3d_logic.py +0 -0
- {moleditpy_linux-4.1.0 → moleditpy_linux-4.1.2}/src/moleditpy_linux/ui/zoomable_view.py +0 -0
- {moleditpy_linux-4.1.0 → moleditpy_linux-4.1.2}/src/moleditpy_linux/utils/__init__.py +0 -0
- {moleditpy_linux-4.1.0 → moleditpy_linux-4.1.2}/src/moleditpy_linux/utils/default_settings.py +0 -0
- {moleditpy_linux-4.1.0 → moleditpy_linux-4.1.2}/src/moleditpy_linux/utils/sip_isdeleted_safe.py +0 -0
- {moleditpy_linux-4.1.0 → moleditpy_linux-4.1.2}/src/moleditpy_linux/utils/system_utils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: MoleditPy-linux
|
|
3
|
-
Version: 4.1.
|
|
3
|
+
Version: 4.1.2
|
|
4
4
|
Summary: A cross-platform, simple, and intuitive molecular structure editor built in Python. It allows 2D molecular drawing and 3D structure visualization. It supports exporting structure files for input to DFT calculation software.
|
|
5
5
|
Author-email: HiroYokoyama <titech.yoko.hiro@gmail.com>
|
|
6
6
|
License: GNU GENERAL PUBLIC LICENSE
|
|
@@ -837,9 +837,9 @@ moleditpy
|
|
|
837
837
|
* **3D Visualization (PyVista / pyvistaqt):** 3D rendering is achieved by generating PyVista meshes (spheres and cylinders) from RDKit conformer coordinates. A custom `vtkInteractorStyle` enables direct drag-and-drop editing of atoms in the 3D view.
|
|
838
838
|
* **Modular Architecture:** The codebase is organized into dedicated packages for `core` logic, `ui` components, and `utils`. The main application logic is decomposed into reusable mixins, ensuring long-term maintainability and easier verification.
|
|
839
839
|
|
|
840
|
-
## License
|
|
840
|
+
## License & Disclaimer
|
|
841
841
|
|
|
842
|
-
This project is licensed under the
|
|
842
|
+
This project is licensed under the GNU General Public License v3.0 (GPLv3) - see the [LICENSE](LICENSE) file for details. As open-source software, it is provided 'as is' without warranty of any kind, and the author assumes no responsibility or liability for the results. Although outputs have been carefully verified, users are strongly encouraged to independently check and validate them for critical applications (such as publications). If you encounter any bugs, please open an issue.
|
|
843
843
|
|
|
844
844
|
## Citation
|
|
845
845
|
|
|
@@ -971,9 +971,9 @@ moleditpy
|
|
|
971
971
|
* **化学計算 (RDKit / Open Babel):** 2DデータからRDKit分子オブジェクトを生成し、3D座標生成や分子特性計算を実行します。RDKitでの3D座標生成が失敗した際は、Open Babelにフォールバックします。重い計算処理は別スレッド (`QThread`) で実行し、GUIの応答性を維持しています。
|
|
972
972
|
* **3D可視化 (PyVista / pyvistaqt):** RDKitのコンフォーマ座標からPyVistaのメッシュ(球や円柱)を生成して描画します。カスタムの`vtkInteractorStyle`を実装し、3Dビュー内での原子の直接的なドラッグ&ドロップ編集を可能にしています。
|
|
973
973
|
|
|
974
|
-
## ライセンス
|
|
974
|
+
## ライセンス & 免責事項
|
|
975
975
|
|
|
976
|
-
このプロジェクトは
|
|
976
|
+
このプロジェクトは GNU General Public License v3.0 (GPLv3) のもとでライセンスされています。詳細は [LICENSE](LICENSE) ファイルを参照してください。オープンソースソフトウェアとして、本ソフトウェアは「現状のまま」提供され、いかなる明示または黙示の保証も行いません。また、本ソフトウェアを使用した結果について、作者は一切の責任や義務を負いません。出力結果は慎重に検証されていますが、学術論文の作成など重要な用途においては、ユーザーご自身で結果を独立して確認および検証することを強くお勧めします。バグに遭遇した場合は、Issueを作成してください。
|
|
977
977
|
|
|
978
978
|
## 引用
|
|
979
979
|
|
|
@@ -134,9 +134,9 @@ moleditpy
|
|
|
134
134
|
* **3D Visualization (PyVista / pyvistaqt):** 3D rendering is achieved by generating PyVista meshes (spheres and cylinders) from RDKit conformer coordinates. A custom `vtkInteractorStyle` enables direct drag-and-drop editing of atoms in the 3D view.
|
|
135
135
|
* **Modular Architecture:** The codebase is organized into dedicated packages for `core` logic, `ui` components, and `utils`. The main application logic is decomposed into reusable mixins, ensuring long-term maintainability and easier verification.
|
|
136
136
|
|
|
137
|
-
## License
|
|
137
|
+
## License & Disclaimer
|
|
138
138
|
|
|
139
|
-
This project is licensed under the
|
|
139
|
+
This project is licensed under the GNU General Public License v3.0 (GPLv3) - see the [LICENSE](LICENSE) file for details. As open-source software, it is provided 'as is' without warranty of any kind, and the author assumes no responsibility or liability for the results. Although outputs have been carefully verified, users are strongly encouraged to independently check and validate them for critical applications (such as publications). If you encounter any bugs, please open an issue.
|
|
140
140
|
|
|
141
141
|
## Citation
|
|
142
142
|
|
|
@@ -268,9 +268,9 @@ moleditpy
|
|
|
268
268
|
* **化学計算 (RDKit / Open Babel):** 2DデータからRDKit分子オブジェクトを生成し、3D座標生成や分子特性計算を実行します。RDKitでの3D座標生成が失敗した際は、Open Babelにフォールバックします。重い計算処理は別スレッド (`QThread`) で実行し、GUIの応答性を維持しています。
|
|
269
269
|
* **3D可視化 (PyVista / pyvistaqt):** RDKitのコンフォーマ座標からPyVistaのメッシュ(球や円柱)を生成して描画します。カスタムの`vtkInteractorStyle`を実装し、3Dビュー内での原子の直接的なドラッグ&ドロップ編集を可能にしています。
|
|
270
270
|
|
|
271
|
-
## ライセンス
|
|
271
|
+
## ライセンス & 免責事項
|
|
272
272
|
|
|
273
|
-
このプロジェクトは
|
|
273
|
+
このプロジェクトは GNU General Public License v3.0 (GPLv3) のもとでライセンスされています。詳細は [LICENSE](LICENSE) ファイルを参照してください。オープンソースソフトウェアとして、本ソフトウェアは「現状のまま」提供され、いかなる明示または黙示の保証も行いません。また、本ソフトウェアを使用した結果について、作者は一切の責任や義務を負いません。出力結果は慎重に検証されていますが、学術論文の作成など重要な用途においては、ユーザーご自身で結果を独立して確認および検証することを強くお勧めします。バグに遭遇した場合は、Issueを作成してください。
|
|
274
274
|
|
|
275
275
|
## 引用
|
|
276
276
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: MoleditPy-linux
|
|
3
|
-
Version: 4.1.
|
|
3
|
+
Version: 4.1.2
|
|
4
4
|
Summary: A cross-platform, simple, and intuitive molecular structure editor built in Python. It allows 2D molecular drawing and 3D structure visualization. It supports exporting structure files for input to DFT calculation software.
|
|
5
5
|
Author-email: HiroYokoyama <titech.yoko.hiro@gmail.com>
|
|
6
6
|
License: GNU GENERAL PUBLIC LICENSE
|
|
@@ -837,9 +837,9 @@ moleditpy
|
|
|
837
837
|
* **3D Visualization (PyVista / pyvistaqt):** 3D rendering is achieved by generating PyVista meshes (spheres and cylinders) from RDKit conformer coordinates. A custom `vtkInteractorStyle` enables direct drag-and-drop editing of atoms in the 3D view.
|
|
838
838
|
* **Modular Architecture:** The codebase is organized into dedicated packages for `core` logic, `ui` components, and `utils`. The main application logic is decomposed into reusable mixins, ensuring long-term maintainability and easier verification.
|
|
839
839
|
|
|
840
|
-
## License
|
|
840
|
+
## License & Disclaimer
|
|
841
841
|
|
|
842
|
-
This project is licensed under the
|
|
842
|
+
This project is licensed under the GNU General Public License v3.0 (GPLv3) - see the [LICENSE](LICENSE) file for details. As open-source software, it is provided 'as is' without warranty of any kind, and the author assumes no responsibility or liability for the results. Although outputs have been carefully verified, users are strongly encouraged to independently check and validate them for critical applications (such as publications). If you encounter any bugs, please open an issue.
|
|
843
843
|
|
|
844
844
|
## Citation
|
|
845
845
|
|
|
@@ -971,9 +971,9 @@ moleditpy
|
|
|
971
971
|
* **化学計算 (RDKit / Open Babel):** 2DデータからRDKit分子オブジェクトを生成し、3D座標生成や分子特性計算を実行します。RDKitでの3D座標生成が失敗した際は、Open Babelにフォールバックします。重い計算処理は別スレッド (`QThread`) で実行し、GUIの応答性を維持しています。
|
|
972
972
|
* **3D可視化 (PyVista / pyvistaqt):** RDKitのコンフォーマ座標からPyVistaのメッシュ(球や円柱)を生成して描画します。カスタムの`vtkInteractorStyle`を実装し、3Dビュー内での原子の直接的なドラッグ&ドロップ編集を可能にしています。
|
|
973
973
|
|
|
974
|
-
## ライセンス
|
|
974
|
+
## ライセンス & 免責事項
|
|
975
975
|
|
|
976
|
-
このプロジェクトは
|
|
976
|
+
このプロジェクトは GNU General Public License v3.0 (GPLv3) のもとでライセンスされています。詳細は [LICENSE](LICENSE) ファイルを参照してください。オープンソースソフトウェアとして、本ソフトウェアは「現状のまま」提供され、いかなる明示または黙示の保証も行いません。また、本ソフトウェアを使用した結果について、作者は一切の責任や義務を負いません。出力結果は慎重に検証されていますが、学術論文の作成など重要な用途においては、ユーザーご自身で結果を独立して確認および検証することを強くお勧めします。バグに遭遇した場合は、Issueを作成してください。
|
|
977
977
|
|
|
978
978
|
## 引用
|
|
979
979
|
|
{moleditpy_linux-4.1.0 → moleditpy_linux-4.1.2}/src/moleditpy_linux/plugins/plugin_interface.py
RENAMED
|
@@ -499,6 +499,17 @@ class PluginContext:
|
|
|
499
499
|
if mw and hasattr(mw, "string_importer_manager"):
|
|
500
500
|
mw.string_importer_manager.load_from_smiles(smiles)
|
|
501
501
|
|
|
502
|
+
def show_xyz_data(
|
|
503
|
+
self, xyz_text: str, source_name: str = "XYZ data"
|
|
504
|
+
) -> Optional[Any]:
|
|
505
|
+
"""Display XYZ text in the 3D viewer and return the loaded RDKit Mol."""
|
|
506
|
+
mw = self.get_main_window()
|
|
507
|
+
if mw and hasattr(mw, "io_manager"):
|
|
508
|
+
show = getattr(mw.io_manager, "show_xyz_data", None)
|
|
509
|
+
if show is not None:
|
|
510
|
+
return show(xyz_text, source_name=source_name)
|
|
511
|
+
return None
|
|
512
|
+
|
|
502
513
|
def to_xyz_block(self) -> Optional[str]:
|
|
503
514
|
"""Return the current 3D structure as an XYZ block (only element x y z lines)."""
|
|
504
515
|
mol = self.current_mol
|
{moleditpy_linux-4.1.0 → moleditpy_linux-4.1.2}/src/moleditpy_linux/ui/calculation_worker.py
RENAMED
|
@@ -548,7 +548,22 @@ def _perform_direct_conversion(
|
|
|
548
548
|
_safe_status,
|
|
549
549
|
options=options if backend == "RDKIT" else None,
|
|
550
550
|
):
|
|
551
|
-
|
|
551
|
+
fallback_success = False
|
|
552
|
+
if backend == "RDKIT" and "MMFF" in method_key:
|
|
553
|
+
_safe_status("MMFF optimization failed. Auto-falling back to UFF...")
|
|
554
|
+
fallback_success = opt_func(
|
|
555
|
+
mol, "UFF", _check_halted, _safe_status, options=options
|
|
556
|
+
)
|
|
557
|
+
if fallback_success:
|
|
558
|
+
with contextlib.suppress(Exception):
|
|
559
|
+
mol.SetProp("_pme_optimization_method", "UFF_RDKIT")
|
|
560
|
+
|
|
561
|
+
if not fallback_success:
|
|
562
|
+
_safe_status(
|
|
563
|
+
"Warning: Optimization failed. Using unoptimized structure."
|
|
564
|
+
)
|
|
565
|
+
with contextlib.suppress(Exception):
|
|
566
|
+
mol.ClearProp("_pme_optimization_method")
|
|
552
567
|
|
|
553
568
|
if _check_halted():
|
|
554
569
|
raise WorkerHaltError("Halted")
|
|
@@ -664,15 +679,30 @@ print(ob_mol.write("mol"))
|
|
|
664
679
|
_safe_status,
|
|
665
680
|
options=options if backend == "RDKIT" else None,
|
|
666
681
|
):
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
682
|
+
fallback_success = False
|
|
683
|
+
if backend == "RDKIT" and "MMFF" in method_key:
|
|
684
|
+
_safe_status("MMFF optimization failed. Auto-falling back to UFF...")
|
|
685
|
+
fallback_success = opt_func(
|
|
686
|
+
rd_mol, "UFF", _check_halted, _safe_status, options=options
|
|
687
|
+
)
|
|
688
|
+
if fallback_success:
|
|
689
|
+
with contextlib.suppress(Exception):
|
|
690
|
+
rd_mol.SetProp("_pme_optimization_method", "UFF_RDKIT")
|
|
691
|
+
|
|
692
|
+
if not fallback_success:
|
|
693
|
+
_safe_status(
|
|
694
|
+
"Warning: Optimization failed. Using unoptimized structure."
|
|
695
|
+
)
|
|
696
|
+
with contextlib.suppress(Exception):
|
|
697
|
+
rd_mol.ClearProp("_pme_optimization_method")
|
|
671
698
|
|
|
672
699
|
if _check_halted():
|
|
673
700
|
raise WorkerHaltError("Halted")
|
|
674
701
|
# Final status message before finishing (to ensure it doesn't overwrite error/halt messages)
|
|
675
|
-
|
|
702
|
+
final_opt = "Unoptimized"
|
|
703
|
+
if rd_mol.HasProp("_pme_optimization_method"):
|
|
704
|
+
final_opt = rd_mol.GetProp("_pme_optimization_method")
|
|
705
|
+
opt_label = _OPT_METHOD_LABELS.get(final_opt, final_opt)
|
|
676
706
|
_safe_status(f"Process completed (Open Babel Conversion / {opt_label}).")
|
|
677
707
|
_safe_finished((worker_id, rd_mol))
|
|
678
708
|
return True
|
|
@@ -925,9 +955,22 @@ class CalculationWorker(QObject):
|
|
|
925
955
|
_safe_status,
|
|
926
956
|
options=options if backend == "RDKIT" else None,
|
|
927
957
|
):
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
958
|
+
fallback_success = False
|
|
959
|
+
if backend == "RDKIT" and "MMFF" in method_key:
|
|
960
|
+
_safe_status("MMFF optimization failed. Auto-falling back to UFF...")
|
|
961
|
+
fallback_success = opt_func(
|
|
962
|
+
mol, "UFF", _check_halted, _safe_status, options=options
|
|
963
|
+
)
|
|
964
|
+
if fallback_success:
|
|
965
|
+
with contextlib.suppress(Exception):
|
|
966
|
+
mol.SetProp("_pme_optimization_method", "UFF_RDKIT")
|
|
967
|
+
|
|
968
|
+
if not fallback_success:
|
|
969
|
+
_safe_status(
|
|
970
|
+
"Warning: Optimization failed. Using unoptimized structure."
|
|
971
|
+
)
|
|
972
|
+
with contextlib.suppress(Exception):
|
|
973
|
+
mol.ClearProp("_pme_optimization_method")
|
|
931
974
|
|
|
932
975
|
# Final stereo restoration check
|
|
933
976
|
for b_idx, s, satoms in orig_stereo:
|
|
@@ -939,7 +982,10 @@ class CalculationWorker(QObject):
|
|
|
939
982
|
if _check_halted():
|
|
940
983
|
raise WorkerHaltError("Halted")
|
|
941
984
|
# Final status message before finishing (to ensure it doesn't overwrite error/halt messages)
|
|
942
|
-
|
|
985
|
+
final_opt = "Unoptimized"
|
|
986
|
+
if mol.HasProp("_pme_optimization_method"):
|
|
987
|
+
final_opt = mol.GetProp("_pme_optimization_method")
|
|
988
|
+
opt_label = _OPT_METHOD_LABELS.get(final_opt, final_opt)
|
|
943
989
|
_safe_status(f"Process completed (RDKit Conversion / {opt_label}).")
|
|
944
990
|
_safe_finished((w_id, mol))
|
|
945
991
|
return True
|
|
@@ -972,9 +1018,11 @@ class CalculationWorker(QObject):
|
|
|
972
1018
|
)
|
|
973
1019
|
# Final status message before finishing (to ensure it doesn't overwrite error/halt messages)
|
|
974
1020
|
_safe_status = helpers["status"]
|
|
975
|
-
opt_method = (options or {}).get("optimization_method") or "MMFF94s_RDKIT"
|
|
976
1021
|
if (options or {}).get("do_optimize", True):
|
|
977
|
-
|
|
1022
|
+
final_opt = "Unoptimized"
|
|
1023
|
+
if mol.HasProp("_pme_optimization_method"):
|
|
1024
|
+
final_opt = mol.GetProp("_pme_optimization_method")
|
|
1025
|
+
opt_label = _OPT_METHOD_LABELS.get(final_opt, final_opt)
|
|
978
1026
|
_safe_status(f"Process completed (Direct 2D->3D Conversion / {opt_label}).")
|
|
979
1027
|
else:
|
|
980
1028
|
_safe_status("Process completed (Direct 2D->3D Conversion).")
|
|
@@ -484,13 +484,13 @@ class ComputeManager:
|
|
|
484
484
|
method_key = None
|
|
485
485
|
if mol and mol.HasProp("_pme_optimization_method"):
|
|
486
486
|
method_key = mol.GetProp("_pme_optimization_method")
|
|
487
|
-
if not method_key:
|
|
488
|
-
method_key = self.host.init_manager.optimization_method
|
|
489
487
|
if method_key:
|
|
490
488
|
labels = self.host.init_manager.opt3d_method_labels or {}
|
|
491
489
|
self.last_successful_optimization_method = labels.get(
|
|
492
490
|
method_key, method_key
|
|
493
491
|
)
|
|
492
|
+
else:
|
|
493
|
+
self.last_successful_optimization_method = "Unoptimized"
|
|
494
494
|
except (AttributeError, TypeError):
|
|
495
495
|
# Safe defensive fallback catching AttributeError, TypeError
|
|
496
496
|
pass
|
|
@@ -539,7 +539,7 @@ class ComputeManager:
|
|
|
539
539
|
"Retry with UFF?",
|
|
540
540
|
f"{msg}\n\nWould you like to retry using UFF (RDKit) instead?",
|
|
541
541
|
QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No,
|
|
542
|
-
QMessageBox.StandardButton.
|
|
542
|
+
QMessageBox.StandardButton.Yes,
|
|
543
543
|
)
|
|
544
544
|
if reply == QMessageBox.StandardButton.Yes:
|
|
545
545
|
self.optimize_3d_structure("UFF_RDKIT")
|
|
@@ -34,7 +34,7 @@ from PyQt6.QtWidgets import (
|
|
|
34
34
|
from rdkit import Chem
|
|
35
35
|
from rdkit.Chem import AllChem, rdGeometry, rdMolTransforms, Descriptors
|
|
36
36
|
|
|
37
|
-
from ..utils.constants import COVALENT_RADII, VERSION
|
|
37
|
+
from ..utils.constants import COVALENT_RADII, DUMMY_XYZ_SYMBOLS, VERSION
|
|
38
38
|
|
|
39
39
|
|
|
40
40
|
class IOManager:
|
|
@@ -84,139 +84,210 @@ class IOManager:
|
|
|
84
84
|
lines[3] = self.fix_mol_counts_line(lines[3])
|
|
85
85
|
return "\n".join(lines)
|
|
86
86
|
|
|
87
|
-
def
|
|
88
|
-
"""
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
87
|
+
def _normalize_xyz_symbol(self, raw_symbol: str) -> Tuple[str, bool]:
|
|
88
|
+
"""Return the RDKit symbol for an XYZ atom and whether it is a dummy."""
|
|
89
|
+
stripped = raw_symbol.strip()
|
|
90
|
+
if ":" in stripped:
|
|
91
|
+
return "*", True
|
|
92
|
+
if stripped.upper() in DUMMY_XYZ_SYMBOLS:
|
|
93
|
+
return "*", True
|
|
94
|
+
symbol = stripped.capitalize()
|
|
95
|
+
try:
|
|
96
|
+
atomic_num = Chem.GetPeriodicTable().GetAtomicNumber(symbol)
|
|
97
|
+
except (RuntimeError, ValueError, TypeError):
|
|
98
|
+
return "*", True
|
|
99
|
+
if atomic_num <= 0:
|
|
100
|
+
return "*", True
|
|
101
|
+
return symbol, False
|
|
102
|
+
|
|
103
|
+
def _mol_from_xyz_lines(self, raw_lines: list[str]) -> Any:
|
|
104
|
+
"""Create an RDKit molecule from XYZ text lines."""
|
|
105
|
+
lines = [ln.strip() for ln in raw_lines if not ln.strip().startswith("#")]
|
|
106
|
+
while lines and not lines[0]:
|
|
107
|
+
lines.pop(0)
|
|
108
|
+
|
|
109
|
+
if not lines:
|
|
110
|
+
raise ValueError("XYZ file format error: too few lines")
|
|
111
|
+
|
|
112
|
+
atom_start = 2
|
|
92
113
|
try:
|
|
93
|
-
with open(file_path, "r", encoding="utf-8") as f:
|
|
94
|
-
raw_lines = f.readlines()
|
|
95
|
-
|
|
96
|
-
lines = [ln.strip() for ln in raw_lines if not ln.strip().startswith("#")]
|
|
97
|
-
while lines and not lines[0]:
|
|
98
|
-
lines.pop(0)
|
|
99
|
-
|
|
100
114
|
if len(lines) < 2:
|
|
101
115
|
raise ValueError("XYZ file format error: too few lines")
|
|
102
|
-
|
|
103
116
|
num_atoms = int(lines[0])
|
|
104
117
|
if num_atoms == 0:
|
|
105
118
|
raise ValueError("XYZ file has zero atoms")
|
|
119
|
+
except ValueError as exc:
|
|
120
|
+
# Not a standard headed XYZ — treat all lines as atom rows
|
|
121
|
+
if "zero atoms" in str(exc) or "too few" in str(exc):
|
|
122
|
+
raise
|
|
123
|
+
num_atoms = len(lines)
|
|
124
|
+
atom_start = 0
|
|
125
|
+
|
|
126
|
+
atoms_data = []
|
|
127
|
+
has_dummy_atoms = False
|
|
128
|
+
atom_lines = lines[atom_start : atom_start + num_atoms]
|
|
129
|
+
if len(atom_lines) < num_atoms:
|
|
130
|
+
raise ValueError("XYZ file format error: fewer atom rows than expected")
|
|
131
|
+
|
|
132
|
+
for i, line in enumerate(atom_lines):
|
|
133
|
+
parts = line.split()
|
|
134
|
+
if len(parts) < 4:
|
|
135
|
+
raise ValueError(f"Invalid atom data at line {atom_start + i + 1}")
|
|
136
|
+
raw_symbol = parts[0]
|
|
137
|
+
symbol, is_dummy = self._normalize_xyz_symbol(raw_symbol)
|
|
138
|
+
has_dummy_atoms = has_dummy_atoms or is_dummy
|
|
139
|
+
atoms_data.append(
|
|
140
|
+
(symbol, float(parts[1]), float(parts[2]), float(parts[3]))
|
|
141
|
+
)
|
|
106
142
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
parts = line.split()
|
|
110
|
-
if len(parts) < 4:
|
|
111
|
-
raise ValueError(f"Invalid atom data at line {i + 3}")
|
|
112
|
-
symbol = parts[0].capitalize()
|
|
113
|
-
try:
|
|
114
|
-
Chem.Atom(symbol)
|
|
115
|
-
except (RuntimeError, ValueError):
|
|
116
|
-
settings = self.host.init_manager.settings
|
|
117
|
-
if settings.get("skip_chemistry_checks", False):
|
|
118
|
-
symbol = "C"
|
|
119
|
-
else:
|
|
120
|
-
raise ValueError(f"Unrecognized element symbol: {parts[0]}")
|
|
121
|
-
atoms_data.append(
|
|
122
|
-
(symbol, float(parts[1]), float(parts[2]), float(parts[3]))
|
|
123
|
-
)
|
|
124
|
-
|
|
125
|
-
if not atoms_data:
|
|
126
|
-
raise ValueError("No valid atoms found in XYZ file")
|
|
143
|
+
if not atoms_data:
|
|
144
|
+
raise ValueError("No valid atoms found in XYZ file")
|
|
127
145
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
mol.
|
|
146
|
+
mol = Chem.RWMol()
|
|
147
|
+
conf = Chem.Conformer(len(atoms_data))
|
|
148
|
+
for i, (symbol, x, y, z) in enumerate(atoms_data):
|
|
149
|
+
atom = Chem.Atom(symbol)
|
|
150
|
+
atom.SetIntProp("xyz_unique_id", i)
|
|
151
|
+
if atom.GetAtomicNum() == 0:
|
|
152
|
+
atom.SetProp("xyz_original_symbol", atom_lines[i].split()[0])
|
|
153
|
+
mol.AddAtom(atom)
|
|
154
|
+
conf.SetAtomPosition(i, rdGeometry.Point3D(x, y, z))
|
|
155
|
+
mol.AddConformer(conf)
|
|
136
156
|
|
|
137
|
-
|
|
138
|
-
|
|
157
|
+
settings = self.host.init_manager.settings
|
|
158
|
+
skip_checks = bool(settings.get("skip_chemistry_checks", False))
|
|
139
159
|
|
|
140
|
-
|
|
160
|
+
def _set_prop(m: Chem.Mol, key: str, val: Any) -> None:
|
|
161
|
+
try:
|
|
162
|
+
if isinstance(val, int):
|
|
163
|
+
m.SetIntProp(key, val)
|
|
164
|
+
elif isinstance(val, float):
|
|
165
|
+
m.SetDoubleProp(key, val)
|
|
166
|
+
except (RuntimeError, TypeError, ValueError):
|
|
167
|
+
# Safe defensive fallback catching RuntimeError, TypeError, ValueError
|
|
168
|
+
pass
|
|
169
|
+
|
|
170
|
+
def _process(charge_val: int, use_rd_determine: bool = True) -> Any:
|
|
171
|
+
if use_rd_determine:
|
|
141
172
|
try:
|
|
142
|
-
|
|
143
|
-
m.SetIntProp(key, val)
|
|
144
|
-
elif isinstance(val, float):
|
|
145
|
-
m.SetDoubleProp(key, val)
|
|
146
|
-
except (RuntimeError, TypeError, ValueError):
|
|
147
|
-
# Safe defensive fallback catching RuntimeError, TypeError, ValueError
|
|
148
|
-
pass
|
|
149
|
-
|
|
150
|
-
def _process(charge_val: int, use_rd_determine: bool = True) -> Any:
|
|
151
|
-
if use_rd_determine:
|
|
152
|
-
try:
|
|
153
|
-
from rdkit.Chem import rdDetermineBonds
|
|
173
|
+
from rdkit.Chem import rdDetermineBonds
|
|
154
174
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
_set_prop(candidate, "_xyz_charge", charge_val)
|
|
159
|
-
return candidate
|
|
160
|
-
except (RuntimeError, ValueError, TypeError) as e:
|
|
161
|
-
raise e
|
|
162
|
-
else:
|
|
163
|
-
self.estimate_bonds_from_distances(mol)
|
|
164
|
-
candidate = mol.GetMol()
|
|
175
|
+
mol_copy = Chem.RWMol(mol)
|
|
176
|
+
rdDetermineBonds.DetermineBonds(mol_copy, charge=charge_val)
|
|
177
|
+
candidate = mol_copy.GetMol()
|
|
165
178
|
_set_prop(candidate, "_xyz_charge", charge_val)
|
|
166
179
|
return candidate
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
final_mol = _process(0, use_rd_determine=False)
|
|
170
|
-
_set_prop(final_mol, "_xyz_skip_checks", 1)
|
|
180
|
+
except (RuntimeError, ValueError, TypeError):
|
|
181
|
+
raise
|
|
171
182
|
else:
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
183
|
+
self.estimate_bonds_from_distances(mol)
|
|
184
|
+
candidate = mol.GetMol()
|
|
185
|
+
_set_prop(candidate, "_xyz_charge", charge_val)
|
|
186
|
+
return candidate
|
|
187
|
+
|
|
188
|
+
if skip_checks or has_dummy_atoms:
|
|
189
|
+
final_mol = _process(0, use_rd_determine=False)
|
|
190
|
+
_set_prop(final_mol, "_xyz_skip_checks", 1)
|
|
191
|
+
else:
|
|
192
|
+
final_mol = None
|
|
193
|
+
# First try with charge 0 (per user's 'first try with 0 then ask' requirement)
|
|
194
|
+
# but only if "Always ask" is not explicitly enabled in settings.
|
|
195
|
+
if not settings.get("always_ask_charge", False):
|
|
196
|
+
try:
|
|
197
|
+
final_mol = _process(0, use_rd_determine=True)
|
|
198
|
+
except (RuntimeError, ValueError, TypeError):
|
|
199
|
+
final_mol = None
|
|
200
|
+
|
|
201
|
+
# If still no final_mol (because always_ask is True, or charge 0 failed)
|
|
202
|
+
if final_mol is None:
|
|
203
|
+
while True:
|
|
204
|
+
prompt_fn = getattr(self, "prompt_for_charge", None)
|
|
205
|
+
if callable(prompt_fn):
|
|
206
|
+
result = prompt_fn()
|
|
207
|
+
if isinstance(result, tuple) and len(result) == 3:
|
|
208
|
+
charge_val, ok, skip_flag = result
|
|
192
209
|
else:
|
|
193
210
|
charge_val, ok, skip_flag = 0, True, False
|
|
211
|
+
else:
|
|
212
|
+
charge_val, ok, skip_flag = 0, True, False
|
|
213
|
+
|
|
214
|
+
if not ok:
|
|
215
|
+
return None
|
|
216
|
+
if skip_flag:
|
|
217
|
+
final_mol = _process(0, use_rd_determine=False)
|
|
218
|
+
_set_prop(final_mol, "_xyz_skip_checks", 1)
|
|
219
|
+
break
|
|
220
|
+
try:
|
|
221
|
+
final_mol = _process(charge_val, use_rd_determine=True)
|
|
222
|
+
break
|
|
223
|
+
except (RuntimeError, ValueError, TypeError) as e:
|
|
224
|
+
if self.host.statusBar():
|
|
225
|
+
self.host.statusBar().showMessage(
|
|
226
|
+
f"Chemistry failed for charge {charge_val}: {e}. Try a different charge or skip."
|
|
227
|
+
)
|
|
228
|
+
if not callable(prompt_fn):
|
|
229
|
+
raise e
|
|
194
230
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
break
|
|
204
|
-
except (RuntimeError, ValueError, TypeError) as e:
|
|
205
|
-
if self.host.statusBar():
|
|
206
|
-
self.host.statusBar().showMessage(
|
|
207
|
-
f"Chemistry failed for charge {charge_val}: {e}. Try a different charge or skip."
|
|
208
|
-
)
|
|
209
|
-
if not callable(prompt_fn):
|
|
210
|
-
raise e
|
|
211
|
-
|
|
212
|
-
if final_mol:
|
|
213
|
-
final_mol.xyz_atom_data = atoms_data
|
|
214
|
-
return final_mol
|
|
231
|
+
if final_mol:
|
|
232
|
+
final_mol.xyz_atom_data = atoms_data
|
|
233
|
+
return final_mol
|
|
234
|
+
|
|
235
|
+
def load_xyz_file(self, file_path: str) -> Optional[Any]:
|
|
236
|
+
"""Load XYZ file and create RDKit Mol with charge prompt and bond determination."""
|
|
237
|
+
if not self.host.state_manager.check_unsaved_changes():
|
|
238
|
+
return None
|
|
215
239
|
|
|
240
|
+
try:
|
|
241
|
+
with open(file_path, "r", encoding="utf-8") as f:
|
|
242
|
+
return self._mol_from_xyz_lines(f.readlines())
|
|
216
243
|
except (RuntimeError, TypeError, ValueError, UnicodeDecodeError) as e:
|
|
217
244
|
self.host.statusBar().showMessage(f"Error parsing XYZ file: {e}")
|
|
218
245
|
return None
|
|
219
246
|
|
|
247
|
+
def load_xyz_block(self, xyz_text: str) -> Optional[Any]:
|
|
248
|
+
"""Load XYZ text and create an RDKit Mol without opening a file dialog."""
|
|
249
|
+
try:
|
|
250
|
+
return self._mol_from_xyz_lines(xyz_text.splitlines())
|
|
251
|
+
except (RuntimeError, TypeError, ValueError, UnicodeDecodeError) as e:
|
|
252
|
+
self.host.statusBar().showMessage(f"Error parsing XYZ data: {e}")
|
|
253
|
+
return None
|
|
254
|
+
|
|
255
|
+
def show_xyz_data(
|
|
256
|
+
self, xyz_text: str, source_name: str = "XYZ data"
|
|
257
|
+
) -> Optional[Any]:
|
|
258
|
+
"""Load XYZ text, set it as the current molecule, and draw it in 3D."""
|
|
259
|
+
try:
|
|
260
|
+
mol = self.load_xyz_block(xyz_text)
|
|
261
|
+
if mol is None:
|
|
262
|
+
return None
|
|
263
|
+
|
|
264
|
+
self.host.edit_actions_manager.clear_all(skip_check=True)
|
|
265
|
+
self.host.set_current_molecule(mol)
|
|
266
|
+
self.host.set_atom_id_to_rdkit_idx_map({})
|
|
267
|
+
|
|
268
|
+
skip_flag = False
|
|
269
|
+
if mol.HasProp("_xyz_skip_checks"):
|
|
270
|
+
skip_flag = bool(mol.GetIntProp("_xyz_skip_checks"))
|
|
271
|
+
self.host.is_xyz_derived = skip_flag or (mol.GetNumBonds() == 0)
|
|
272
|
+
|
|
273
|
+
self.host.view_3d_manager.draw_molecule_3d(mol)
|
|
274
|
+
self.host.ui_manager.enter_3d_viewer_mode()
|
|
275
|
+
self.host.ui_manager.enable_3d_features(True)
|
|
276
|
+
self.host.view_3d_manager.update_atom_id_menu_text()
|
|
277
|
+
self.host.view_3d_manager.update_atom_id_menu_state()
|
|
278
|
+
|
|
279
|
+
if self.host.statusBar():
|
|
280
|
+
self.host.statusBar().showMessage(
|
|
281
|
+
f"3D Viewer Mode: Loaded {source_name}"
|
|
282
|
+
)
|
|
283
|
+
self.host.set_has_unsaved_changes(False)
|
|
284
|
+
self.host.state_manager.update_window_title()
|
|
285
|
+
return mol
|
|
286
|
+
except (RuntimeError, TypeError, ValueError, AttributeError) as e:
|
|
287
|
+
if self.host.statusBar():
|
|
288
|
+
self.host.statusBar().showMessage(f"XYZ display failed: {e}")
|
|
289
|
+
return None
|
|
290
|
+
|
|
220
291
|
def prompt_for_charge(self) -> Tuple[Optional[int], bool, bool]:
|
|
221
292
|
"""Show dialog to prompt user for molecular charge when loading XYZ files."""
|
|
222
293
|
dialog = QDialog(self.host)
|
|
@@ -261,6 +332,8 @@ class IOManager:
|
|
|
261
332
|
for j in range(i + 1, num_atoms):
|
|
262
333
|
atom_i = mol.GetAtomWithIdx(i)
|
|
263
334
|
atom_j = mol.GetAtomWithIdx(j)
|
|
335
|
+
if atom_i.GetAtomicNum() == 0 or atom_j.GetAtomicNum() == 0:
|
|
336
|
+
continue
|
|
264
337
|
distance = rdMolTransforms.GetBondLength(conf, i, j)
|
|
265
338
|
symbol_i = atom_i.GetSymbol()
|
|
266
339
|
symbol_j = atom_j.GetSymbol()
|
|
@@ -55,6 +55,11 @@ BOND_OFFSET = 3.5
|
|
|
55
55
|
DEFAULT_BOND_LENGTH = 75 # Standard bond length used in templates
|
|
56
56
|
CLIPBOARD_MIME_TYPE = "application/x-moleditpy-fragment"
|
|
57
57
|
|
|
58
|
+
# XYZ dummy/pseudo-atom labels that map to RDKit wildcard atom (*)
|
|
59
|
+
DUMMY_XYZ_SYMBOLS: frozenset[str] = frozenset(
|
|
60
|
+
{"*", "-", "X", "DA", "DU", "DUM", "DUMMY", "Q", "BQ", "LP"}
|
|
61
|
+
)
|
|
62
|
+
|
|
58
63
|
# Physical bond length (approximate) used to convert scene pixels to angstroms.
|
|
59
64
|
# DEFAULT_BOND_LENGTH is the length in pixels used in the editor UI for a typical bond.
|
|
60
65
|
# Many molecular file formats expect coordinates in angstroms; use ~1.5 Å as a typical single-bond length.
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{moleditpy_linux-4.1.0 → moleditpy_linux-4.1.2}/src/MoleditPy_linux.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
{moleditpy_linux-4.1.0 → moleditpy_linux-4.1.2}/src/MoleditPy_linux.egg-info/entry_points.txt
RENAMED
|
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
|
{moleditpy_linux-4.1.0 → moleditpy_linux-4.1.2}/src/moleditpy_linux/plugins/plugin_manager.py
RENAMED
|
File without changes
|
{moleditpy_linux-4.1.0 → moleditpy_linux-4.1.2}/src/moleditpy_linux/plugins/plugin_manager_window.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{moleditpy_linux-4.1.0 → moleditpy_linux-4.1.2}/src/moleditpy_linux/ui/align_plane_dialog.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{moleditpy_linux-4.1.0 → moleditpy_linux-4.1.2}/src/moleditpy_linux/ui/base_picking_dialog.py
RENAMED
|
File without changes
|
|
File without changes
|
{moleditpy_linux-4.1.0 → moleditpy_linux-4.1.2}/src/moleditpy_linux/ui/bond_length_dialog.py
RENAMED
|
File without changes
|
{moleditpy_linux-4.1.0 → moleditpy_linux-4.1.2}/src/moleditpy_linux/ui/color_settings_dialog.py
RENAMED
|
File without changes
|
|
File without changes
|
{moleditpy_linux-4.1.0 → moleditpy_linux-4.1.2}/src/moleditpy_linux/ui/custom_interactor_style.py
RENAMED
|
File without changes
|
{moleditpy_linux-4.1.0 → moleditpy_linux-4.1.2}/src/moleditpy_linux/ui/custom_qt_interactor.py
RENAMED
|
File without changes
|
{moleditpy_linux-4.1.0 → moleditpy_linux-4.1.2}/src/moleditpy_linux/ui/dialog_3d_picking_mixin.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{moleditpy_linux-4.1.0 → moleditpy_linux-4.1.2}/src/moleditpy_linux/ui/edit_actions_logic.py
RENAMED
|
File without changes
|
|
File without changes
|
{moleditpy_linux-4.1.0 → moleditpy_linux-4.1.2}/src/moleditpy_linux/ui/geometry_base_dialog.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{moleditpy_linux-4.1.0 → moleditpy_linux-4.1.2}/src/moleditpy_linux/ui/molecular_scene_handler.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{moleditpy_linux-4.1.0 → moleditpy_linux-4.1.2}/src/moleditpy_linux/ui/move_selected_atoms_dialog.py
RENAMED
|
File without changes
|
{moleditpy_linux-4.1.0 → moleditpy_linux-4.1.2}/src/moleditpy_linux/ui/periodic_table_dialog.py
RENAMED
|
File without changes
|
|
File without changes
|
{moleditpy_linux-4.1.0 → moleditpy_linux-4.1.2}/src/moleditpy_linux/ui/plugin_menu_manager.py
RENAMED
|
File without changes
|
|
File without changes
|
{moleditpy_linux-4.1.0 → moleditpy_linux-4.1.2}/src/moleditpy_linux/ui/settings_tabs/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{moleditpy_linux-4.1.0 → moleditpy_linux-4.1.2}/src/moleditpy_linux/ui/template_preview_item.py
RENAMED
|
File without changes
|
{moleditpy_linux-4.1.0 → moleditpy_linux-4.1.2}/src/moleditpy_linux/ui/template_preview_view.py
RENAMED
|
File without changes
|
{moleditpy_linux-4.1.0 → moleditpy_linux-4.1.2}/src/moleditpy_linux/ui/translation_dialog.py
RENAMED
|
File without changes
|
|
File without changes
|
{moleditpy_linux-4.1.0 → moleditpy_linux-4.1.2}/src/moleditpy_linux/ui/user_template_dialog.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{moleditpy_linux-4.1.0 → moleditpy_linux-4.1.2}/src/moleditpy_linux/utils/default_settings.py
RENAMED
|
File without changes
|
{moleditpy_linux-4.1.0 → moleditpy_linux-4.1.2}/src/moleditpy_linux/utils/sip_isdeleted_safe.py
RENAMED
|
File without changes
|
|
File without changes
|