diff --git a/pixi.lock b/pixi.lock index 1154a358..828854e2 100644 --- a/pixi.lock +++ b/pixi.lock @@ -6,8 +6,6 @@ environments: - url: https://conda.anaconda.org/Auto-Mech/ indexes: - https://pypi.org/simple - options: - pypi-prerelease-mode: if-necessary-or-explicit packages: linux-64: - conda: https://conda.anaconda.org/conda-forge/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2 @@ -19,9 +17,9 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/astor-0.8.1-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/asttokens-3.0.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/attrs-25.4.0-pyh71513ae_0.conda - - conda: https://conda.anaconda.org/Auto-Mech/noarch/autochem-0.2026.2-pyh4616a5c_0.conda + - conda: https://conda.anaconda.org/Auto-Mech/noarch/autochem-0.2025.0-pyh4616a5c_0.conda - conda: https://conda.anaconda.org/Auto-Mech/noarch/autofile-0.2025.0-pyh4616a5c_0.conda - - conda: https://conda.anaconda.org/Auto-Mech/noarch/autoio-0.2026.0-pyh4616a5c_0.conda + - conda: https://conda.anaconda.org/Auto-Mech/noarch/autoio-0.2025.0-pyh4616a5c_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/brotli-1.2.0-h41a2e66_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/brotli-bin-1.2.0-hf2c8021_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/bumpver-2025.1131-pyhd8ed1ab_0.conda @@ -133,8 +131,8 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/matplotlib-3.10.8-py312h7900ff3_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/matplotlib-base-3.10.8-py312he3d6523_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/matplotlib-inline-0.2.1-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/Auto-Mech/noarch/mechanalyzer-0.2026.0-pyh4616a5c_0.conda - - conda: https://conda.anaconda.org/Auto-Mech/noarch/mess-static-2026.2.4-h4616a5c_0.conda + - conda: https://conda.anaconda.org/Auto-Mech/noarch/mechanalyzer-0.2025.0-pyh4616a5c_0.conda + - conda: https://conda.anaconda.org/Auto-Mech/noarch/mess-static-2025.9.0-h4616a5c_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/more-itertools-10.8.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/munkres-1.1.4-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/narwhals-2.12.0-pyhcf101f3_0.conda @@ -235,15 +233,13 @@ environments: - pypi: https://files.pythonhosted.org/packages/15/80/44286939ca215e88fa827b2aeb6fa3fd2b4a7af322485c7170d6f9fd96e0/cloudpickle-2.2.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/dd/91/da846638ddffa10b2321df6b4d2874dd89cb933007f93e9d04ff60737150/hyperqueue-0.20.0-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - pypi: https://files.pythonhosted.org/packages/d0/30/dc54f88dd4a2b5dc8a0279bdd7270e735851848b762aeb1c1184ed1f6b14/tqdm-4.67.1-py3-none-any.whl - - pypi: ./ + - pypi: . default: channels: - url: https://conda.anaconda.org/conda-forge/ - url: https://conda.anaconda.org/Auto-Mech/ indexes: - https://pypi.org/simple - options: - pypi-prerelease-mode: if-necessary-or-explicit packages: linux-64: - conda: https://conda.anaconda.org/conda-forge/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2 @@ -254,9 +250,9 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/arpack-3.9.1-nompi_hf03ea27_102.conda - conda: https://conda.anaconda.org/conda-forge/noarch/asttokens-3.0.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/attrs-25.4.0-pyh71513ae_0.conda - - conda: https://conda.anaconda.org/Auto-Mech/noarch/autochem-0.2026.2-pyh4616a5c_0.conda + - conda: https://conda.anaconda.org/Auto-Mech/noarch/autochem-0.2025.0-pyh4616a5c_0.conda - conda: https://conda.anaconda.org/Auto-Mech/noarch/autofile-0.2025.0-pyh4616a5c_0.conda - - conda: https://conda.anaconda.org/Auto-Mech/noarch/autoio-0.2026.0-pyh4616a5c_0.conda + - conda: https://conda.anaconda.org/Auto-Mech/noarch/autoio-0.2025.0-pyh4616a5c_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/brotli-1.2.0-h41a2e66_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/brotli-bin-1.2.0-hf2c8021_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-hda65f42_8.conda @@ -363,8 +359,8 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/matplotlib-3.10.8-py313h78bf25f_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/matplotlib-base-3.10.8-py313h683a580_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/matplotlib-inline-0.2.1-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/Auto-Mech/noarch/mechanalyzer-0.2026.0-pyh4616a5c_0.conda - - conda: https://conda.anaconda.org/Auto-Mech/noarch/mess-static-2026.2.4-h4616a5c_0.conda + - conda: https://conda.anaconda.org/Auto-Mech/noarch/mechanalyzer-0.2025.0-pyh4616a5c_0.conda + - conda: https://conda.anaconda.org/Auto-Mech/noarch/mess-static-2025.9.0-h4616a5c_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/more-itertools-10.8.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/munkres-1.1.4-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/narwhals-2.12.0-pyhcf101f3_0.conda @@ -457,15 +453,13 @@ environments: - pypi: https://files.pythonhosted.org/packages/15/80/44286939ca215e88fa827b2aeb6fa3fd2b4a7af322485c7170d6f9fd96e0/cloudpickle-2.2.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/dd/91/da846638ddffa10b2321df6b4d2874dd89cb933007f93e9d04ff60737150/hyperqueue-0.20.0-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - pypi: https://files.pythonhosted.org/packages/d0/30/dc54f88dd4a2b5dc8a0279bdd7270e735851848b762aeb1c1184ed1f6b14/tqdm-4.67.1-py3-none-any.whl - - pypi: ./ + - pypi: . dev: channels: - url: https://conda.anaconda.org/conda-forge/ - url: https://conda.anaconda.org/Auto-Mech/ indexes: - https://pypi.org/simple - options: - pypi-prerelease-mode: if-necessary-or-explicit packages: linux-64: - conda: https://conda.anaconda.org/conda-forge/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2 @@ -477,9 +471,9 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/arpack-3.9.1-nompi_hf03ea27_102.conda - conda: https://conda.anaconda.org/conda-forge/noarch/asttokens-3.0.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/attrs-25.4.0-pyh71513ae_0.conda - - conda: https://conda.anaconda.org/Auto-Mech/noarch/autochem-0.2026.2-pyh4616a5c_0.conda + - conda: https://conda.anaconda.org/Auto-Mech/noarch/autochem-0.2025.0-pyh4616a5c_0.conda - conda: https://conda.anaconda.org/Auto-Mech/noarch/autofile-0.2025.0-pyh4616a5c_0.conda - - conda: https://conda.anaconda.org/Auto-Mech/noarch/autoio-0.2026.0-pyh4616a5c_0.conda + - conda: https://conda.anaconda.org/Auto-Mech/noarch/autoio-0.2025.0-pyh4616a5c_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/brotli-1.2.0-h41a2e66_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/brotli-bin-1.2.0-hf2c8021_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-hda65f42_8.conda @@ -597,8 +591,8 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/matplotlib-inline-0.2.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/mdit-py-plugins-0.5.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/mdurl-0.1.2-pyhd8ed1ab_1.conda - - conda: https://conda.anaconda.org/Auto-Mech/noarch/mechanalyzer-0.2026.0-pyh4616a5c_0.conda - - conda: https://conda.anaconda.org/Auto-Mech/noarch/mess-static-2026.2.4-h4616a5c_0.conda + - conda: https://conda.anaconda.org/Auto-Mech/noarch/mechanalyzer-0.2025.0-pyh4616a5c_0.conda + - conda: https://conda.anaconda.org/Auto-Mech/noarch/mess-static-2025.9.0-h4616a5c_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/more-itertools-10.8.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/munkres-1.1.4-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/narwhals-2.12.0-pyhcf101f3_0.conda @@ -699,19 +693,17 @@ environments: - pypi: https://files.pythonhosted.org/packages/15/80/44286939ca215e88fa827b2aeb6fa3fd2b4a7af322485c7170d6f9fd96e0/cloudpickle-2.2.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/dd/91/da846638ddffa10b2321df6b4d2874dd89cb933007f93e9d04ff60737150/hyperqueue-0.20.0-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - pypi: https://files.pythonhosted.org/packages/d0/30/dc54f88dd4a2b5dc8a0279bdd7270e735851848b762aeb1c1184ed1f6b14/tqdm-4.67.1-py3-none-any.whl + - pypi: . - pypi: ../autochem - pypi: ../autofile - pypi: ../autoio - pypi: ../mechanalyzer - - pypi: ./ dev2: channels: - url: https://conda.anaconda.org/conda-forge/ - url: https://conda.anaconda.org/Auto-Mech/ indexes: - https://pypi.org/simple - options: - pypi-prerelease-mode: if-necessary-or-explicit packages: linux-64: - conda: https://conda.anaconda.org/conda-forge/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2 @@ -723,9 +715,9 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/arpack-3.9.1-nompi_hf03ea27_102.conda - conda: https://conda.anaconda.org/conda-forge/noarch/asttokens-3.0.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/attrs-25.4.0-pyh71513ae_0.conda - - conda: https://conda.anaconda.org/Auto-Mech/noarch/autochem-0.2026.2-pyh4616a5c_0.conda + - conda: https://conda.anaconda.org/Auto-Mech/noarch/autochem-0.2025.0-pyh4616a5c_0.conda - conda: https://conda.anaconda.org/Auto-Mech/noarch/autofile-0.2025.0-pyh4616a5c_0.conda - - conda: https://conda.anaconda.org/Auto-Mech/noarch/autoio-0.2026.0-pyh4616a5c_0.conda + - conda: https://conda.anaconda.org/Auto-Mech/noarch/autoio-0.2025.0-pyh4616a5c_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/brotli-1.2.0-h41a2e66_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/brotli-bin-1.2.0-hf2c8021_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-hda65f42_8.conda @@ -843,8 +835,8 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/matplotlib-inline-0.2.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/mdit-py-plugins-0.5.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/mdurl-0.1.2-pyhd8ed1ab_1.conda - - conda: https://conda.anaconda.org/Auto-Mech/noarch/mechanalyzer-0.2026.0-pyh4616a5c_0.conda - - conda: https://conda.anaconda.org/Auto-Mech/noarch/mess-static-2026.2.4-h4616a5c_0.conda + - conda: https://conda.anaconda.org/Auto-Mech/noarch/mechanalyzer-0.2025.0-pyh4616a5c_0.conda + - conda: https://conda.anaconda.org/Auto-Mech/noarch/mess-static-2025.9.0-h4616a5c_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/more-itertools-10.8.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/munkres-1.1.4-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/narwhals-2.12.0-pyhcf101f3_0.conda @@ -945,19 +937,17 @@ environments: - pypi: https://files.pythonhosted.org/packages/88/39/799be3f2f0f38cc727ee3b4f1445fe6d5e4133064ec2e4115069418a5bb6/cloudpickle-3.1.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/ab/5f/6bea67b88a17ae297b165de471bb88ca37ecaa4c8a25e3bcb09c9b5b1313/hyperqueue-0.24.0-cp39-abi3-manylinux_2_28_x86_64.whl - pypi: https://files.pythonhosted.org/packages/d0/30/dc54f88dd4a2b5dc8a0279bdd7270e735851848b762aeb1c1184ed1f6b14/tqdm-4.67.1-py3-none-any.whl + - pypi: . - pypi: ../autochem - pypi: ../autofile - pypi: ../autoio - pypi: ../mechanalyzer - - pypi: ./ test: channels: - url: https://conda.anaconda.org/conda-forge/ - url: https://conda.anaconda.org/Auto-Mech/ indexes: - https://pypi.org/simple - options: - pypi-prerelease-mode: if-necessary-or-explicit packages: linux-64: - conda: https://conda.anaconda.org/conda-forge/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2 @@ -968,9 +958,9 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/arpack-3.9.1-nompi_hf03ea27_102.conda - conda: https://conda.anaconda.org/conda-forge/noarch/asttokens-3.0.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/attrs-25.4.0-pyh71513ae_0.conda - - conda: https://conda.anaconda.org/Auto-Mech/noarch/autochem-0.2026.2-pyh4616a5c_0.conda + - conda: https://conda.anaconda.org/Auto-Mech/noarch/autochem-0.2025.0-pyh4616a5c_0.conda - conda: https://conda.anaconda.org/Auto-Mech/noarch/autofile-0.2025.0-pyh4616a5c_0.conda - - conda: https://conda.anaconda.org/Auto-Mech/noarch/autoio-0.2026.0-pyh4616a5c_0.conda + - conda: https://conda.anaconda.org/Auto-Mech/noarch/autoio-0.2025.0-pyh4616a5c_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/brotli-1.2.0-h41a2e66_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/brotli-bin-1.2.0-hf2c8021_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-hda65f42_8.conda @@ -1080,8 +1070,8 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/matplotlib-3.10.8-py313h78bf25f_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/matplotlib-base-3.10.8-py313h683a580_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/matplotlib-inline-0.2.1-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/Auto-Mech/noarch/mechanalyzer-0.2026.0-pyh4616a5c_0.conda - - conda: https://conda.anaconda.org/Auto-Mech/noarch/mess-static-2026.2.4-h4616a5c_0.conda + - conda: https://conda.anaconda.org/Auto-Mech/noarch/mechanalyzer-0.2025.0-pyh4616a5c_0.conda + - conda: https://conda.anaconda.org/Auto-Mech/noarch/mess-static-2025.9.0-h4616a5c_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/more-itertools-10.8.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/munkres-1.1.4-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/narwhals-2.12.0-pyhcf101f3_0.conda @@ -1177,7 +1167,7 @@ environments: - pypi: https://files.pythonhosted.org/packages/15/80/44286939ca215e88fa827b2aeb6fa3fd2b4a7af322485c7170d6f9fd96e0/cloudpickle-2.2.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/dd/91/da846638ddffa10b2321df6b4d2874dd89cb933007f93e9d04ff60737150/hyperqueue-0.20.0-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - pypi: https://files.pythonhosted.org/packages/d0/30/dc54f88dd4a2b5dc8a0279bdd7270e735851848b762aeb1c1184ed1f6b14/tqdm-4.67.1-py3-none-any.whl - - pypi: ./ + - pypi: . packages: - conda: https://conda.anaconda.org/conda-forge/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2 sha256: fe51de6107f9edc7aa4f786a70f4a883943bc9d39b3bb7307c04c41410990726 @@ -1304,12 +1294,13 @@ packages: timestamp: 1759762331492 - pypi: ../autochem name: autochem - version: 0.2026.2 - sha256: 9501bbbefb1adb15bcc4cec731548c452e7643e31510a2d7c2d0d5f453819ade + version: 0.2026.0 + sha256: a61f39f927a5f2ef9c295d619d567b1666286f5f7b95aef31a272d536523443b requires_python: '>=3.11' -- conda: https://conda.anaconda.org/Auto-Mech/noarch/autochem-0.2026.2-pyh4616a5c_0.conda - sha256: ac66a659c2b1da738582acc23bd4c3831da5db572d6e5032d35fb689c507766c - md5: 51d360511a3d07803176ad44f5401beb + editable: true +- conda: https://conda.anaconda.org/Auto-Mech/noarch/autochem-0.2025.0-pyh4616a5c_0.conda + sha256: 56535f3e7f30ed02b2b65d65f49ee60b00f558757dd07e51d7d9339aff0066ca + md5: c1905a59367f1750ebf58384c3ad2015 depends: - altair >=5.5.0 - ipython >=8.15 @@ -1326,13 +1317,14 @@ packages: - xarray >=2023.8 - python >=3.11 - python * - size: 610491 - timestamp: 1772739572046 + size: 610723 + timestamp: 1763746042074 - pypi: ../autofile name: autofile version: 0.2025.0 sha256: 1158420897d789f9aa7bc3d2053412f840d1f377d567c78ca1c1fbc98ed8faf0 requires_python: '>=3.11' + editable: true - conda: https://conda.anaconda.org/Auto-Mech/noarch/autofile-0.2025.0-pyh4616a5c_0.conda sha256: 027fed4c146c65bb3d55a237c331ff4a4534964e9771c09e7220bce99a208a3d md5: b7bfb6a4fcf15eb0d4ec20dc69dc9f58 @@ -1347,12 +1339,13 @@ packages: timestamp: 1763748110716 - pypi: ../autoio name: autoio - version: 0.2026.0 - sha256: b554f06265eb5e8204bc87e109b9dba5df8b8a42163ad747fe0213439cb4c49c + version: 0.2025.0 + sha256: 9720401e7f430caa3b97ef6d736d056eed1eeb9fc08ab5e04d3b132882a216af requires_python: '>=3.11' -- conda: https://conda.anaconda.org/Auto-Mech/noarch/autoio-0.2026.0-pyh4616a5c_0.conda - sha256: 0dd0d28a368b55cf775b231e7710e1309491b1db79bcad5b334056afe636f6a6 - md5: 8f97347f404687644c579ac99bae3f7d + editable: true +- conda: https://conda.anaconda.org/Auto-Mech/noarch/autoio-0.2025.0-pyh4616a5c_0.conda + sha256: 38f151908a4e4595df7a90bc16d41f71549220ceb3ecd2a1fd7afe121266dbf5 + md5: e8117f81ed6caf696bdc033fed6e9d93 depends: - mako >=1.3.10 - more-itertools >=10.8.0 @@ -1364,8 +1357,8 @@ packages: - autochem >=0.2025.0,<2.0.0 - python >=3.11 - python * - size: 5284910 - timestamp: 1772762271687 + size: 5285348 + timestamp: 1763747126180 - conda: https://conda.anaconda.org/conda-forge/linux-64/brotli-1.2.0-h41a2e66_0.conda sha256: 33239a07f7685917cac25646dd33798ee93e61f83504a0c938d86c507e05d7c9 md5: 4ddfd44e473c676cb8e80548ba4aa704 @@ -3196,12 +3189,13 @@ packages: timestamp: 1733255681319 - pypi: ../mechanalyzer name: mechanalyzer - version: 0.2026.0 - sha256: 363ca1cad51d90753262a652999083d551e70f20286cea794df088877ee219da + version: 0.2025.0 + sha256: ae648c05f2a528eeda61f591dee818e43aad5e046148c2b7a9bb070da1b801a8 requires_python: '>=3.11' -- conda: https://conda.anaconda.org/Auto-Mech/noarch/mechanalyzer-0.2026.0-pyh4616a5c_0.conda - sha256: 19a62baba6c137f47e7538511ce00682e9102be412ddd548e4750837f93eedb6 - md5: 0670a4dc8844b832866fc5e4a3dac4e2 + editable: true +- conda: https://conda.anaconda.org/Auto-Mech/noarch/mechanalyzer-0.2025.0-pyh4616a5c_0.conda + sha256: dddf3523678cbc77b69c03521e04698ad543fd2077d587b4d1f1c66bb054d57c + md5: 10d551318ec5f7adb4ac58d347bcc9e9 depends: - click >=8.2.1 - mako >=1.3.10 @@ -3217,20 +3211,21 @@ packages: - autofile >=0.2025.0,<2.0.0 - python >=3.11 - python * - size: 2731032 - timestamp: 1772765088653 -- pypi: ./ + size: 2729114 + timestamp: 1763750488901 +- pypi: . name: mechdriver - version: 0.2026.0 - sha256: 6465daa62798154ea96b63386a443487dc2fa16f2da184281659a7430b02bb87 + version: 0.2025.0 + sha256: f422c33102fca7daa75628e4454feed87b8c8809e44e42e5408bdb799df10f4f requires_dist: - hyperqueue requires_python: '>=3.11,<3.14' -- conda: https://conda.anaconda.org/Auto-Mech/noarch/mess-static-2026.2.4-h4616a5c_0.conda - sha256: 73cf524ed5a9f5a34f5c68e0309de084c9dcad833bdfcb3c7f288b48f45ac22d - md5: 962375844fd512acf2d0305a46fcd8f3 - size: 42835440 - timestamp: 1770225035248 + editable: true +- conda: https://conda.anaconda.org/Auto-Mech/noarch/mess-static-2025.9.0-h4616a5c_0.conda + sha256: bf49bc57d60cbcda20f57e6a6e63edbb6204396946703224f9ecd9e49c78e50f + md5: d7dee2b3a30813504691abd00da40943 + size: 42798128 + timestamp: 1758816360707 - conda: https://conda.anaconda.org/conda-forge/noarch/more-itertools-10.8.0-pyhd8ed1ab_0.conda sha256: fabe81c8f8f3e1d0ef227fc1306526c76189b3f1175f12302c707e0972dd707c md5: d7620a15dc400b448e1c88a981b23ddd diff --git a/pyproject.toml b/pyproject.toml index c21d89cc..163ce8f4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -105,11 +105,11 @@ autoio = { path = "../autoio", editable = true } autofile = { path = "../autofile", editable = true } mechanalyzer = { path = "../mechanalyzer", editable = true } -[tool.pixi.feature.dev.pypi-options.dependency-overrides] -autochem = { path = "../autochem", editable = true } -autoio = { path = "../autoio", editable = true } -autofile = { path = "../autofile", editable = true } -mechanalyzer = { path = "../mechanalyzer", editable = true } +# [tool.pixi.feature.dev.pypi-options.dependency-overrides] +# autochem = { path = "../autochem", editable = true } +# autoio = { path = "../autoio", editable = true } +# autofile = { path = "../autofile", editable = true } +# mechanalyzer = { path = "../mechanalyzer", editable = true } [tool.pixi.system-requirements] linux = "3.10" diff --git a/src/mechdriver/drivers/ktpdriver.py b/src/mechdriver/drivers/ktpdriver.py index 420425ca..6d814fb4 100644 --- a/src/mechdriver/drivers/ktpdriver.py +++ b/src/mechdriver/drivers/ktpdriver.py @@ -55,7 +55,11 @@ def run(pes_rlst, pes_grp_dct, run_fit_tsk = parser.run.extract_task('run_fits', ktp_tsk_lst) # Group the PESs into lists - pes_grps_rlst = parser.rlst.pes_groups(pes_rlst, pes_grp_dct) + if pes_rlst is None: + print('No channels requested by user, check input.') + pes_grps_rlst = [] + else: + pes_grps_rlst = parser.rlst.pes_groups(pes_rlst, pes_grp_dct) # --------------------------------------- # # LOOP OVER ALL OF THE SUBPES in PES_RLST # diff --git a/src/mechlib/amech_io/parser/models.py b/src/mechlib/amech_io/parser/models.py index a2499584..18aff25c 100644 --- a/src/mechlib/amech_io/parser/models.py +++ b/src/mechlib/amech_io/parser/models.py @@ -161,12 +161,11 @@ def _format_lvl(lvl_val): """ format weird energy calls """ if isinstance(lvl_val, str): - lvl_val = lvl_val.replace(',','*').split('*') + lvl_val = lvl_val.replace(',','*').replace(' ','').split('*') if len(lvl_val) > 1: val_inf = (float(lvl_val[0]), tinfo.from_dct(thy_dct.get(lvl_val[1]))) else: val_inf = (1.00, tinfo.from_dct(thy_dct.get(lvl_val[0]))) - return val_inf new_dct2 = {} @@ -180,7 +179,6 @@ def _format_lvl(lvl_val): _new_dct[key2] = val2 new_dct2[key1] = _new_dct - return new_dct2 diff --git a/src/mechlib/filesys/mincnf.py b/src/mechlib/filesys/mincnf.py index 65454c09..647efb46 100644 --- a/src/mechlib/filesys/mincnf.py +++ b/src/mechlib/filesys/mincnf.py @@ -19,7 +19,8 @@ def min_energy_conformer_locators( - cnf_save_fs, mod_thy_info, hbond_cutoffs=None, nprocs=1): + cnf_save_fs, mod_thy_info, hbond_cutoffs=None, nprocs=1, + print_level=1): """ Obtain the (ring-id, tors-id) filesystem locator pair and path for the conformer of a species with the lowest energy for the specified electronic structure method that currently @@ -37,7 +38,8 @@ def min_energy_conformer_locators( locs, paths = conformer_locators( cnf_save_fs, mod_thy_info, - cnf_range='min', hbond_cutoffs=hbond_cutoffs, nprocs=nprocs) + cnf_range='min', hbond_cutoffs=hbond_cutoffs, nprocs=nprocs, + print_level=print_level) if locs and paths: ret = locs[0], paths[0] else: @@ -48,7 +50,7 @@ def min_energy_conformer_locators( def conformer_locators( cnf_save_fs, mod_thy_info, - cnf_range='min', sort_info_lst=None, print_enes=False, + cnf_range='min', sort_info_lst=None, print_level=1, hbond_cutoffs=None, nprocs=1): """ Obtain the (ring-id, tors-id) filesystem locator pair and path for all conformers meeting @@ -79,7 +81,7 @@ def _conformer_locators( cnf_save_fs, mod_thy_info, cnf_range='min', only_hbnds=True, only_nonhbnds=True, freq_info=None, sp_info=None, sort_prop_dct=None, - print_enes=False, already_counted_locs_lst=(), hbond_cutoffs=None, + print_level=1, already_counted_locs_lst=(), hbond_cutoffs=None, nprocs=1): fin_locs_lst, fin_paths_lst = (), () @@ -117,7 +119,7 @@ def _conformer_locators( for idx, locs in enumerate(fin_locs_lst): fin_paths_lst += (cnf_save_fs[-1].path(locs),) - if print_enes: + if print_level == 2: header = '\nConformer Ordering' if only_hbnds: header += ' for only hydrogen bonded conformers' @@ -136,7 +138,7 @@ def _conformer_locators( mark = '' print(f'{locs[0]:<16}{locs[1]:<16}{_ene:<6.2f}{mark:<3}') print() - else: + elif print_level > 0: print(f'No conformers located in {cnf_save_fs[0].path()}') return fin_locs_lst, fin_paths_lst @@ -154,7 +156,7 @@ def _conformer_locators( only_hbnds=True, only_nonhbnds=False, freq_info=freq_info, sp_info=sp_info, sort_prop_dct=sort_prop_dct, - print_enes=print_enes, + print_level=print_level, already_counted_locs_lst=union_locs_lst, hbond_cutoffs=hbond_cutoffs, nprocs=nprocs) @@ -166,7 +168,7 @@ def _conformer_locators( only_hbnds=False, only_nonhbnds=True, freq_info=freq_info, sp_info=sp_info, sort_prop_dct=sort_prop_dct, - print_enes=print_enes, + print_level=print_level, already_counted_locs_lst=union_locs_lst, hbond_cutoffs=hbond_cutoffs, nprocs=nprocs) @@ -179,7 +181,7 @@ def _conformer_locators( only_hbnds=False, only_nonhbnds=False, freq_info=freq_info, sp_info=sp_info, sort_prop_dct=sort_prop_dct, - print_enes=print_enes, + print_level=print_level, already_counted_locs_lst=union_locs_lst, hbond_cutoffs=hbond_cutoffs, nprocs=nprocs) @@ -455,7 +457,8 @@ def traj_sort(save_fs, mod_thy_info, rid=None): locs_lst = save_fs[-1].existing() if locs_lst: - # Update the trajectory file in the CONFS/rid level for rings + # Update the trajectory file in the CONFS/conf.t.xyz level for + # lowest torsional configurations of all puckering configurations enes = [] for locs in locs_lst: cnf_path = save_fs[-1].path(locs) @@ -464,10 +467,15 @@ def traj_sort(save_fs, mod_thy_info, rid=None): sp_fs[-1].file.energy.read(mod_thy_info[1:4])) geos = [save_fs[-1].file.geometry.read(locs) for locs in locs_lst] - traj = [] traj_sort_data = sorted(zip(enes, geos, locs_lst), key=lambda x: x[0]) + traj = [] + used_rids = [] for ene, geo, locs in traj_sort_data: - comment = f'energy: {ene:<15.10f} \t {locs[0]}' + trid, _ = locs + if trid in used_rids: + continue + used_rids.append(trid) + comment = f'energy: {ene:<15.10f} \t {trid}' traj.append((geo, comment)) traj_path = save_fs[0].file.trajectory.path() @@ -475,6 +483,8 @@ def traj_sort(save_fs, mod_thy_info, rid=None): save_fs[0].file.trajectory.write(traj) if rid is not None: + # Update the trajectory file in the CONFS/rid/conf.t.xyz for the + # torsional configurations of a puckering configuration locs_lst = save_fs[-1].existing() if locs_lst: enes, geos = [], [] @@ -899,10 +909,10 @@ def fs_confs_dict(cnf_save_fs, cnf_save_locs_lst, if saddle: dist_tol = 0.25 for ini_locs in ini_cnf_save_locs_lst: - match_dct[tuple(ini_locs)] = None # Loop over structs in cnf_save, see if they match the current struct - # inigeo = ini_cnf_save_fs[-1].file.geometry.read(ini_locs) + ## + inigeos = [ini_cnf_save_fs[-1].file.geometry.read(ini_locs)] # inizma = automol.geom.zmatrix(inigeo) # inizma = ini_cnf_save_fs[-1].file.zmatrix.read(ini_locs) ini_cnf_save_path = ini_cnf_save_fs[-1].path(ini_locs) @@ -913,14 +923,18 @@ def fs_confs_dict(cnf_save_fs, cnf_save_locs_lst, dtt = automol.zmat.conversion_info(inizmas[0]) for sym_locs in ini_sym_fs[-1].existing(): geo = ini_sym_fs[-1].file.geometry.read(sym_locs) + ## + inigeos.append(geo) geo_wdummy = automol.geom.apply_zmatrix_conversion(geo, dtt) try: inizmas.append(automol.zmat.from_geometry(inizmas[0], geo_wdummy)) except: print('some structures have a different zmatrix') - for inizma in inizmas: + for idx, inizma in enumerate(inizmas): for locs in cnf_save_locs_lst: - # geo = cnf_save_fs[-1].file.geometry.read(locs) + print('checking against run', cnf_save_fs[-1].path(locs)) + ## + geo = cnf_save_fs[-1].file.geometry.read(locs) # zma = automol.geom.zmatrix(geo) zma_save_fs = autofile.fs.zmatrix(cnf_save_fs[-1].path(locs)) zma = zma_save_fs[-1].file.zmatrix.read((0,)) @@ -932,6 +946,12 @@ def fs_confs_dict(cnf_save_fs, cnf_save_locs_lst, # f'- Similar structure found at {cnf_save_path}') match_dct[tuple(ini_locs)] = tuple(locs) break + _, sym_idx = automol.geom.is_unique( + geo, [inigeos[idx]], check_dct={'coulomb': 1e-2}) + if sym_idx is not None: + print(' - Structure is not symmetrically unique.') + match_dct[tuple(ini_locs)] = tuple(locs) + else: sym_fs = autofile.fs.symmetry(cnf_save_fs[-1].path(locs)) dtt = automol.zmat.conversion_info(zma) diff --git a/src/mechlib/filesys/models.py b/src/mechlib/filesys/models.py index 9b1e8c58..5d0e2594 100644 --- a/src/mechlib/filesys/models.py +++ b/src/mechlib/filesys/models.py @@ -250,7 +250,7 @@ def get_spc_locs_lst( hbond_cutoffs = spc_dct_i['hbond_cutoffs'] min_locs_lst, _ = conformer_locators( cnf_save_fs, levelp, cnf_range=cnf_range, - sort_info_lst=mod_info_lst, print_enes=True, + sort_info_lst=mod_info_lst, print_level=2, hbond_cutoffs=hbond_cutoffs, nprocs=nprocs) for min_locs in min_locs_lst: cnf_run_fs[-1].create(min_locs) diff --git a/src/mechlib/filesys/read.py b/src/mechlib/filesys/read.py index c81554eb..9e30c7a5 100644 --- a/src/mechlib/filesys/read.py +++ b/src/mechlib/filesys/read.py @@ -362,16 +362,14 @@ def instability_transformation(spc_dct, spc_name, thy_info, save_prefix, # Check if any locs exist first? # hbond_cutoffs = spc_dct[spc_name]['hbond_cutoffs'] - #ini_loc_info = min_energy_conformer_locators( + # ini_loc_info = min_energy_conformer_locators( # cnf_save_fs, mod_thy_info, hbond_cutoffs=hbond_cutoffs, nprocs=nprocs) ini_loc_lst = cnf_save_fs[-1].existing() - if len(ini_loc_lst) > 0: - min_cnf_path = cnf_save_fs[-1].path(ini_loc_lst[0]) - - else: - min_cnf_path = None + if len(ini_loc_lst) < 1: + return None, None + + min_cnf_path = cnf_save_fs[-1].path(ini_loc_lst[0]) zma_save_fs = autofile.fs.zmatrix(min_cnf_path) - # Check if the instability files exist if zma_save_fs[-1].file.instability.exists(zma_locs): instab_trans = zma_save_fs[-1].file.instability.read(zma_locs) diff --git a/src/mechlib/filesys/save.py b/src/mechlib/filesys/save.py index 506b645b..6883bb68 100644 --- a/src/mechlib/filesys/save.py +++ b/src/mechlib/filesys/save.py @@ -291,7 +291,6 @@ def read_zma_from_geo(init_zma, geo): """ zma = None if init_zma is not None: - print('Resetting ZMA coords using opt geoms...') zma = rebuild_zma_from_opt_geo(init_zma, geo) return zma @@ -405,7 +404,6 @@ def _save_zmatrix(ret, zma_fs, zma_locs, init_zma=None): inf_obj, inp_str, out_str, prog, _ = _unpack_ret(ret) zma = None if init_zma is not None: - print('using opt geo fro zma') geo = elstruct.reader.opt_geometry(prog, out_str) zma = read_zma_from_geo(init_zma, geo) if zma is None: diff --git a/src/mechroutines/es/_routines/conformer.py b/src/mechroutines/es/_routines/conformer.py index 117e2462..4d0fadf0 100644 --- a/src/mechroutines/es/_routines/conformer.py +++ b/src/mechroutines/es/_routines/conformer.py @@ -3,7 +3,6 @@ import shutil import time -import random import subprocess import os import numpy @@ -25,104 +24,103 @@ from phydat import phycon # Initial conformer -def initial_conformer(spc_dct_i, spc_info, ini_method_dct, method_dct, - ini_cnf_save_fs, cnf_run_fs, cnf_save_fs, - es_keyword_dct): - """ Assess if a conformer layer with a geometry exists in the save - filesys for the given species. - If not, attempt to generate some guess structure using InChI strings - or input geom from user. - and optimize - it with input method. Then assess if the optimized structure - corresponds to genuine minimum on the PES via a frequency calculation. - If a minimum is found, save the conformer geometry, zmatrix, energy, +def initial_conformer( + spc_dct_i: dict, + spc_info: tuple, + ini_method_dct: dict, + method_dct: dict, + ini_cnf_save_fs: object, + cnf_run_fs: object, + cnf_save_fs: object, + es_keyword_dct: dict): + """ Create and optimize the first conformer for a species and method (init_geom). + - Ensure no conformer exists in the save filesys for the given species + at the run-LoT. + - Generate a guess structure with priority on input geometry from user + (inp/geomA.xyz) and then using RDKit geometries from InChI strings + - Optimize guess structure with the run-LoT + - Ensure optimized geometry is a minimum on the PES via a frequency calculation + (if imaginary frequencies are found, loop through kickoff/reoptimization procedure). + - If a minimum is found, save the conformer geometry, zmatrix, energy, and torsions to the save filesys. - Also, the function assessess if the species is unstable and will + - Also, the function assessess if the species is unstable and will save the appropriate information. + :param spc_dct_i: Species dictionary for species i + :type spc_dct_i: dict + :param spc_info: Species info (InChI, charge, multiplicity) + :type spc_info: tuple + :param ini_method_dct: Initial method dictionary + :type ini_method_dct: dict + :param method_dct: Run Method dictionary + :type method_dct: dict + :param ini_cnf_save_fs: Initial conformer save filesystem + :type ini_cnf_save_fs: autofile.fs.conformer + :param cnf_run_fs: Conformer run filesystem + :type cnf_run_fs: autofile.fs.conformer + :param cnf_save_fs: Conformer save filesystem + :type cnf_save_fs: autofile.fs.conformer + :param es_keyword_dct: Electronic structure keyword dictionary + :type es_keyword_dct: dict + :returns: bool indicating if conformer was found """ - ini_thy_info = tinfo.from_dct(ini_method_dct) - thy_info = tinfo.from_dct(method_dct) - mod_thy_info = tinfo.modify_orb_label( - thy_info, spc_info) - mod_ini_thy_info = tinfo.modify_orb_label( - ini_thy_info, spc_info) - [kickoff_size, kickoff_backward] = spc_dct_i['kickoff'] - - _, cnf_path = filesys.mincnf.min_energy_conformer_locators( - cnf_save_fs, mod_thy_info) + # check run and save filesystems for existing jobs + mod_thy_info = tinfo.modify_orb_label(tinfo.from_dct(method_dct), spc_info) overwrite = es_keyword_dct['overwrite'] - if not cnf_path: - info_message( - 'No conformer found in save filesys. Checking for running jobs...') - if _init_geom_is_running(cnf_run_fs) and not overwrite: - _run = False - else: - info_message( - 'No conformers are running in run filesys.' + - 'Proceeding with optimization...') - _run = True - elif overwrite: - info_message( - 'User specified to overwrite energy with new run...') - _run = True - else: - _run = False - - if _run: - info_message('Obtaining some initial guess geometry.') - geo_init = _obtain_ini_geom(spc_dct_i, ini_cnf_save_fs, - mod_ini_thy_info, - overwrite) - - if geo_init is not None: - info_message( - 'Assessing if there are any functional groups', - 'that cause instability') + if not _init_geom_is_needed( + cnf_save_fs, cnf_run_fs, mod_thy_info, overwrite): + return True - zma_init = automol.geom.zmatrix(geo_init) - - rid = autofile.schema.generate_new_ring_id() - cid = autofile.schema.generate_new_conformer_id() + # obtain initial guess structure from user input or InChI + # info_message('Obtaining initial guess geometry.') + mod_ini_thy_info = tinfo.modify_orb_label( + tinfo.from_dct(ini_method_dct), spc_info) + geo_init = _obtain_ini_geom( + spc_dct_i, ini_cnf_save_fs, mod_ini_thy_info, overwrite) + if geo_init is None: + warning_message( + 'Unable to obtain an initial guess geometry') + return False - # Determine if there is an instability, if so return prods - instab_zmas = automol.reac.instability_product_zmas(zma_init) - if not instab_zmas: - - # Build a cid and a run fs - cnf_run_fs[-1].create((rid, cid)) - run_fs = autofile.fs.run(cnf_run_fs[-1].path((rid, cid))) - - if not automol.geom.is_atom(geo_init): - geo_found = _optimize_molecule( - spc_info, zma_init, - method_dct, - cnf_save_fs, (rid, cid), - run_fs, - overwrite, - kickoff_size=kickoff_size, - kickoff_backward=kickoff_backward) - else: - geo_found = _optimize_atom( - spc_info, zma_init, - method_dct, - cnf_save_fs, (rid, cid), - run_fs, - overwrite) - else: - info_message( - 'Found functional groups that cause instabilities') - filesys.save.instability( - zma_init, instab_zmas, cnf_save_fs, - rng_locs=(rid,), tors_locs=(cid,), zma_locs=(0,)) - geo_found = True - else: - geo_found = False - warning_message( - 'Unable to obtain an initial guess geometry') + # Assign random ring and conformer IDs + rid = autofile.schema.generate_new_ring_id() + cid = autofile.schema.generate_new_conformer_id() + + # Check for common functional groups that cause instabilities + # info_message( + # 'Assessing if there are any functional groups', + # 'that cause instability') + zma_init = automol.geom.zmatrix(geo_init) + instab_zmas = automol.reac.instability_product_zmas(zma_init) + if instab_zmas: + info_message( + 'Found functional groups that cause instabilities') + filesys.save.instability( + zma_init, instab_zmas, cnf_save_fs, + rng_locs=(rid,), tors_locs=(cid,), zma_locs=(0,)) + return True + + # Optimize the initial geometry, including a loop through kickoffs + # until no imaginary frequencies remain or max attempts reached + cnf_run_fs[-1].create((rid, cid)) + run_fs = autofile.fs.run(cnf_run_fs[-1].path((rid, cid))) + if not automol.geom.is_atom(geo_init): + [kickoff_size, kickoff_backward] = spc_dct_i['kickoff'] + geo_found = _optimize_molecule( + spc_info, zma_init, + method_dct, + cnf_save_fs, (rid, cid), + run_fs, + overwrite, + kickoff_size=kickoff_size, + kickoff_backward=kickoff_backward) else: - existing_path('Initial geometry', cnf_path) - geo_found = True - + geo_found = _optimize_atom( + spc_info, zma_init, + method_dct, + cnf_save_fs, (rid, cid), + run_fs, + overwrite) + return geo_found @@ -130,21 +128,31 @@ def _obtain_ini_geom(spc_dct_i, ini_cnf_save_fs, mod_ini_thy_info, overwrite): """ Obtain an initial geometry to be optimized. Checks a hieratchy of places to obtain the initial geom. - (1) Geom dict which is the input from the user - (2) Geom from inchi + (1) Geom dict which is the input from the user (the geom dict is + populated during input parsing from inp/.xyz if it exists) + (2) Geom from inchi """ geo_init = None # Obtain geom from thy fs or remove the conformer filesystem if needed if not overwrite: ini_min_locs, ini_path = filesys.mincnf.min_energy_conformer_locators( - ini_cnf_save_fs, mod_ini_thy_info) + ini_cnf_save_fs, mod_ini_thy_info, print_level=0) if ini_path: geo_init = ini_cnf_save_fs[-1].file.geometry.read(ini_min_locs) path = ini_cnf_save_fs[-1].path(ini_min_locs) info_message( f'Getting inital geometry from inplvl at path {path}') else: + # Note: I think this print message makes no sense for what the code does + # I think the rmtree is fine? It's deleting anything saved in the + # ini save filesystem if overwrite is True. I guess wiping the whole system + # would be a reasonable meaning of overwriting init_geom, but at the same + # time, this could wipe more than a user would expect. + # This was added in 2020 in a hard to track push because it was + # originally added to a no-longer existing geom.py file. + # https://github.com/Auto-Mech/mechdriver/commit/e4c2d52c5185d940f6e8cc242430b34eeffc3879 + # - Sarah 01/14/2026 debug_message( 'Removing original conformer save data for instability') for locs in ini_cnf_save_fs[-1].existing(): @@ -153,14 +161,13 @@ def _obtain_ini_geom(spc_dct_i, ini_cnf_save_fs, shutil.rmtree(cnf_save_path) if geo_init is None: - if 'geo' in spc_dct_i: - geo_init = spc_dct_i['geo'] + geo_init = spc_dct_i.get('init_geo', None) + if geo_init is not None: info_message( 'Getting initial geometry from geom dictionary') - - if geo_init is None: - geo_init = automol.chi.geometry(spc_dct_i['canon_enant_ich']) - info_message('Getting initial geometry from inchi') + else: + geo_init = automol.chi.geometry(spc_dct_i['canon_enant_ich']) + info_message('Getting initial geometry from inchi') # Check if the init geometry is connected if geo_init is not None: @@ -264,10 +271,9 @@ def _optimize_molecule(spc_info, zma_init, if conn and proper_stereo: info_message( 'Saving structure as the first conformer...', newline=1) - filesys.save.conformer( - ret, None, cnf_save_fs, mod_thy_info[1:], - rng_locs=(locs[0],), tors_locs=(locs[1],), - init_zma=zma) + save_conformer( + ret, run_fs, cnf_save_fs, locs, mod_thy_info, + orig_ich=spc_info[0], rid_traj=True, init_zma=zma) else: if not conn: info_message('Saving disconnected species...') @@ -288,14 +294,27 @@ def _optimize_molecule(spc_info, zma_init, return conf_found -def single_conformer(zma, spc_info, mod_thy_info, - cnf_run_fs, cnf_save_fs, - script_str, overwrite, - retryfail=True, zrxn=None, - use_locs=None, resave=False, +def single_conformer(zma, spc_info: tuple, mod_thy_info: tuple, + cnf_run_fs: tuple, cnf_save_fs: tuple, + script_str: str, overwrite: bool, + retryfail: bool=True, zrxn: object=None, + use_locs: tuple=None, resave: bool=False, **kwargs): - """ generate single optimized geometry to be saved into a - filesystem + """ generate single optimized geometry to be saved into a filesystem + from an input zmatrix + :param zma: tuple(zip(symbs, key_mat, name_mat, val_mat)), + automol-type Z-matrix to be optimized + :param spc_info: tuple, Species info (InChI, charge, multiplicity) + :param mod_thy_info: tuple, (program, method, basis, orb_label) to run + :param cnf_run_fs: autofile.fs.conformer, Conformer run filesystem + :param cnf_save_fs: autofile.fs.conformer, Conformer save filesystem + :param script_str: str, Script string for electronic structure package + :param overwrite: bool, Whether to overwrite existing files + :param retryfail: bool, Whether to retry failed jobs + :param zrxn: automol.reac.Reaction, automol reaction if TS optimization + :param use_locs: tuple, (rid, cid) to use for running + :param resave: bool, Whether to resave all conformers from run fs + :returns: None """ skip_job = False @@ -303,13 +322,6 @@ def single_conformer(zma, spc_info, mod_thy_info, _presamp_save( spc_info, cnf_run_fs, cnf_save_fs, mod_thy_info, zrxn=zrxn, rid=None, ref_zma=zma) - if use_locs is None: - print('getting rid') - rid = rng_loc_for_geo( - automol.zmat.geometry(zma), cnf_save_fs) - if rid is not None: - cid = autofile.schema.generate_new_conformer_id() - locs = (rid, cid) if this_conformer_is_running(zma, cnf_run_fs): skip_job = True @@ -322,15 +334,22 @@ def single_conformer(zma, spc_info, mod_thy_info, skip_job = True if not skip_job: - # Build the filesystem - if use_locs is None: - rid = autofile.schema.generate_new_ring_id() - cid = autofile.schema.generate_new_conformer_id() - locs = (rid, cid) + # Build the run filesystem + existing_rid = rng_loc_for_geo( + automol.zmat.geometry(zma), cnf_save_fs) + if use_locs is not None: + rid, cid = use_locs + if existing_rid is not None: + rid = existing_rid + elif [rid] in cnf_save_fs[-2].existing(): + rid = autofile.schema.generate_new_ring_id() else: - locs = use_locs - rid = locs[0] - + cid = autofile.schema.generate_new_conformer_id() + if existing_rid is not None: + rid = existing_rid + else: + rid = autofile.schema.generate_new_ring_id() + locs = (rid, cid) cnf_run_fs[-1].create(locs) cnf_run_path = cnf_run_fs[-1].path(locs) run_fs = autofile.fs.run(cnf_run_path) @@ -353,111 +372,84 @@ def single_conformer(zma, spc_info, mod_thy_info, ) if success: - inf_obj, _, out_str = ret - prog = inf_obj.prog - method = inf_obj.method - ene = elstruct.reader.energy(prog, method, out_str) - geo = elstruct.reader.opt_geometry(prog, out_str) - # zma = elstruct.reader.opt_zmatrix(prog, out_str) - saved_locs, saved_geos, saved_enes = _saved_cnf_info( - cnf_save_fs, mod_thy_info) - - opt_zma = None - if zma is not None: - opt_zma = filesys.save.read_zma_from_geo(zma, geo) - if zma is None: - opt_zma = filesys.save.read_job_zma(ret, init_zma=zma) - viable = _geo_connected(geo, zrxn) - if viable: - if zrxn: - viable = _ts_geo_viable( - opt_zma, zrxn, cnf_save_fs, mod_thy_info, ref_zma=zma) - else: - viable = _inchi_are_same(spc_info[0], geo) - - if viable: - if _geo_unique(geo, ene, saved_geos, saved_enes, zrxn=zrxn): - sym_id = _sym_unique( - geo, ene, saved_geos, saved_enes) - if sym_id is None: - if cnf_save_fs[0].file.info.exists(): - debug_message( - 'inf_obj path', cnf_save_fs[0].path()) - rinf_obj = cnf_save_fs[0].file.info.read() - rinf = rinf_obj - debug_message( - 'inf_obj for r', rinf) - rnsampd = rinf_obj.nsamp - rnsampd += 1 - rinf.nsamp = rnsampd - else: - rinf = autofile.schema.info_objects.conformer_trunk(0) - rinf.nsamp = 1 - if cnf_save_fs[1].file.info.exists([locs[0]]): - cinf_obj_s = cnf_save_fs[1].file.info.read([locs[0]]) - cinf = cinf_obj_s - cnsampd = cinf_obj_s.nsamp - cnsampd += 1 - cinf.nsamp = cnsampd - else: - cinf = autofile.schema.info_objects.conformer_branch(0) - cinf.nsamp = 1 - cnf_save_fs[1].create([locs[0]]) - cnf_save_fs[0].file.info.write(rinf) - cnf_save_fs[1].file.info.write(cinf, [locs[0]]) - filesys.save.conformer( - ret, None, cnf_save_fs, mod_thy_info[1:], - zrxn=zrxn, init_zma=zma, - rng_locs=(locs[0],), tors_locs=(locs[1],)) - saved_geos.append(geo) - saved_enes.append(ene) - saved_locs.append(locs) - - # Update the conformer trajectory file - obj('vspace') - filesys.mincnf.traj_sort( - cnf_save_fs, mod_thy_info) - filesys.mincnf.traj_sort( - cnf_save_fs, mod_thy_info, locs[0]) - else: - sym_locs = saved_locs[sym_id] - filesys.save.sym_indistinct_conformer( - geo, cnf_save_fs, locs, sym_locs) - if cnf_save_fs[-1].exists(locs): - cnf_save_path = cnf_save_fs[-1].path(locs) - if cnf_run_fs[-1].exists(locs): - cnf_run_path = cnf_run_fs[-1].path(locs) - - -def conformer_sampling(zma, spc_info, thy_info, - cnf_run_fs, cnf_save_fs, rid, - script_str, overwrite, - nsamp_par=(False, 3, 3, 1, 50, 50), - tors_names=(), - zrxn=None, two_stage=False, - retryfail=False, resave=False, - repulsion_thresh=40.0, print_debug=True, + # Determine if the optimized ring puckering state already exists + inf_obj_temp, _, out_str = ret + prog = inf_obj_temp.prog + opt_geo = elstruct.reader.opt_geometry(prog, out_str) + existing_rid = rng_loc_for_geo(opt_geo, cnf_save_fs) + # increment sample count for rings and conformers, + # if csamp.yaml and rsamp.yaml exist + # save_conformer will set these to 1 if + # csamp.yaml and rsamp.yaml don't currently exist + if existing_rid is None: + if cnf_save_fs[0].file.info.exists(): + rinf_obj = cnf_save_fs[0].file.info.read() + rsampd = util.calc_nsampd(cnf_save_fs, cnf_run_fs) + rsampd += 1 + rinf_obj.nsamp = rsampd + cnf_save_fs[0].file.info.write(rinf_obj) + cnf_run_fs[0].file.info.write(rinf_obj) + if cnf_save_fs[1].file.info.exists([locs[0]]): + cinf_obj = cnf_save_fs[1].file.info.read([locs[0]]) + csampd = util.calc_nsampd(cnf_save_fs, cnf_run_fs, locs[0]) + csampd += 1 + cinf_obj.nsamp = csampd + cnf_save_fs[1].file.info.write(cinf_obj, [locs[0]]) + cnf_run_fs[1].file.info.write(cinf_obj, [locs[0]]) + # use save_conformer to save the conformer if it passes + # viability and uniqueness checks + if existing_rid is not None: + rid = existing_rid + locs = [rid, cid] + save_conformer( + ret, cnf_run_fs, cnf_save_fs, locs, mod_thy_info, + zrxn=zrxn, orig_ich=spc_info[0], rid_traj=True, init_zma=zma, ref_zma=zma) + + +def conformer_sampling(zma, spc_info: tuple, mod_thy_info: tuple, + cnf_run_fs: object, cnf_save_fs: object, rid: str, + script_str: str, overwrite: bool, + nsamp_par: tuple=(False, 3, 3, 1, 50, 50), + tors_names: tuple=(), + zrxn: object=None, two_stage: bool=False, + retryfail: bool=False, resave: bool=False, + repulsion_thresh: float=40.0, print_debug: bool=True, **kwargs): - """ run sampling algorithm to find conformers + """ Sample the torsional configurations of a specific ring-puckering state + :param zma: tuple(zip(symbs, key_mat, name_mat, val_mat)), + automol-type Z-matrix to be optimized + :param spc_info: tuple, Species info (InChI, charge, multiplicity) + :param mod_thy_info: tuple, (program, method, basis, orb_label) to run + :param cnf_run_fs: autofile.fs.conformer, Conformer run filesystem + :param cnf_save_fs: autofile.fs.conformer, Conformer save filesystem + :param rid: str, Ring ID for the puckering state + :param script_str: str, Script string for electronic structure package + :param overwrite: bool, Whether to overwrite existing files + :param nsamp_par: tuple, Parameters to determine the number of samples + :param tors_names: tuple, Names of torsions to sample + :param zrxn: automol.reac.Reaction, automol reaction if TS + :param two_stage: bool, Whether to use two-stage optimization + :param retryfail: bool, Whether to retry failed jobs + :param resave: bool, Whether to resave all conformers from run fs + :param repulsion_thresh: float, Threshold for relative repulsion energy + :param print_debug: bool, Whether to print debug messages + :returns: None """ - # Check if any saving needs to be done before hand ref_rid = rid cnf_run_fs[1].create([rid]) + cnf_save_fs[1].create([rid]) if resave: _presamp_save( - spc_info, cnf_run_fs, cnf_save_fs, thy_info, zrxn=zrxn, rid=rid, ref_zma=zma) + spc_info, cnf_run_fs, cnf_save_fs, mod_thy_info, + zrxn=zrxn, rid=rid, ref_zma=zma) - # Build filesys - cnf_save_fs[1].create([rid]) - inf_obj = autofile.schema.info_objects.conformer_branch(0) # Set the samples nsamp, tors_range_dct = util.calc_nsamp( tors_names, nsamp_par, zma, zrxn=zrxn) nsamp0 = nsamp nsampd = util.calc_nsampd(cnf_save_fs, cnf_run_fs, rid) - tot_samp = nsamp - nsampd brk_tot_samp = nsamp * 5 @@ -486,22 +478,23 @@ def conformer_sampling(zma, spc_info, thy_info, f'Max sample num: 5*{nsamp} attempted, ending search', 'Run again if more samples desired.') break - print(f"Debug: new iteration, nsampd - {nsampd}") # Run the conformer sampling if nsampd > 0: samp_zma, = automol.zmat.samples(zma, 1, tors_range_dct) else: samp_zma = zma - info_message( - 'Generating sample Z-Matrix that does not have', - 'high intramolecular repulsion...') + info_message(f"Run {samp_idx}/{tot_samp}, Total {nsampd}/{nsamp0}") + info_message(' - Generating sample Z-Matrix') bad_geo_cnt = 0 - while not automol.zmat.has_low_relative_repulsion_energy(samp_zma, zma) and bad_geo_cnt < 1000: + # the repulsion_thresh argument is not being used, it seems like this would + # be the place to apply it -Sarah 01/15/2026 + while not ( + automol.zmat.has_low_relative_repulsion_energy(samp_zma, zma) + and bad_geo_cnt < 1000): if print_debug: warning_message('Structure has high repulsion.') - warning_message( - 'Generating new sample Z-Matrix') + warning_message('Generating new sample Z-Matrix') samp_zma, = automol.zmat.samples(zma, 1, tors_range_dct) bad_geo_cnt += 1 @@ -512,9 +505,7 @@ def conformer_sampling(zma, spc_info, thy_info, cnf_run_path = cnf_run_fs[-1].path(locs) run_fs = autofile.fs.run(cnf_run_path) - info_message(f"Run {samp_idx}/{tot_samp}") - tors_names = tuple(tors_range_dct.keys()) - print('two_stage test:', two_stage, tors_names) + tors_names = tuple(tors_range_dct.keys()) if tors_range_dct else () if two_stage and tors_names: frozen_coords_lst = (tors_names, ()) success, ret = es_runner.multi_stage_optimization( @@ -522,7 +513,7 @@ def conformer_sampling(zma, spc_info, thy_info, run_fs=run_fs, geo=samp_zma, spc_info=spc_info, - thy_info=thy_info, + thy_info=mod_thy_info, frozen_coords_lst=frozen_coords_lst, zrxn=zrxn, overwrite=overwrite, @@ -537,7 +528,7 @@ def conformer_sampling(zma, spc_info, thy_info, run_fs=run_fs, geo=samp_zma, spc_info=spc_info, - thy_info=thy_info, + thy_info=mod_thy_info, zrxn=zrxn, overwrite=overwrite, saddle=bool(zrxn is not None), @@ -556,15 +547,19 @@ def conformer_sampling(zma, spc_info, thy_info, rid = autofile.schema.generate_new_ring_id() locs = [rid, cid] save_conformer( - ret, cnf_run_fs, cnf_save_fs, locs, thy_info, + ret, cnf_run_fs, cnf_save_fs, locs, mod_thy_info, zrxn=zrxn, orig_ich=spc_info[0], rid_traj=True, init_zma=samp_zma, ref_zma=samp_zma) + if cnf_save_fs[1].file.info.exists([ref_rid]): + cinf_obj = cnf_save_fs[1].file.info.read([ref_rid]) + else: + cinf_obj = autofile.schema.info_objects.conformer_branch(0) nsampd = util.calc_nsampd(cnf_save_fs, cnf_run_fs, ref_rid) nsampd += 1 samp_idx += 1 - inf_obj.nsamp = nsampd - cnf_save_fs[1].file.info.write(inf_obj, [ref_rid]) - cnf_run_fs[1].file.info.write(inf_obj, [ref_rid]) + cinf_obj.nsamp = nsampd + cnf_save_fs[1].file.info.write(cinf_obj, [ref_rid]) + cnf_run_fs[1].file.info.write(cinf_obj, [ref_rid]) # Increment attempt counter samp_attempt_idx += 1 @@ -1348,51 +1343,73 @@ def _presamp_save(spc_info, cnf_run_fs, cnf_save_fs, filesys.mincnf.traj_sort(cnf_save_fs, thy_info, rid=rloc[0]) -def save_conformer(ret, cnf_run_fs, cnf_save_fs, locs, thy_info, zrxn=None, - orig_ich='', rid_traj=False, init_zma=None, ref_zma=None): - """ save the conformers that have been found so far - # Only go through save procedure if conf not in save - # may need to get geo, ene, etc; maybe make function +def save_conformer( + ret: tuple, cnf_run_fs: object, cnf_save_fs: object, locs: tuple, + mod_thy_info: tuple, zrxn: object=None, orig_ich: str='', + rid_traj: bool=False, init_zma: object=None, ref_zma: object=None): + """ Save a conformer into the correct location if unique and viable + 1) Check if geometry is properly connected + 2) Check if geometry is totally or symmetrically unique (compared to saved) + 3) Save conformer accordingly + :param ret: tuple, (inf_obj, err_msg, out_str) from es_runner.read_job + :param cnf_run_fs: tuple(autofile.fs), conformer run filesystem + :param cnf_save_fs: tuple(autofile.fs), conformer save filesystem + :param locs: tuple(str), (ring_id, conf_id) location of conformer + :param thy_info: tuple, (program, method, basis, program, orb_res) theory information + :param zrxn: automol.reac.Reaction, reaction object if a TS else None + :param orig_ich: str, InChI string of original species + :param rid_traj: bool, whether to update traj for ring id + :param init_zma: automol.zmat.ZMatrix, initial zmatrix used in optimization + :param ref_zma: automol.zmat.ZMatrix, reference zmatrix for TS viability check + (this differs from init_zma, which is the starting point of the optimization, + which is a perturbed structure along reactant coordinates for a TS whereas + the ref_zma is zma built by automol from the reactant geometries) + :return: None """ - - saved_locs, saved_geos, saved_enes = _saved_cnf_info( - cnf_save_fs, thy_info, locs) - + # Read the electronic structure optimization job output inf_obj, _, out_str = ret prog = inf_obj.prog method = inf_obj.method ene = elstruct.reader.energy(prog, method, out_str) geo = elstruct.reader.opt_geometry(prog, out_str) - zma = None - if init_zma is not None: - zma = filesys.save.read_zma_from_geo(init_zma, geo) + zma = filesys.save.read_zma_from_geo(init_zma, geo) if zma is None: zma = filesys.save.read_job_zma(ret, init_zma=init_zma) + # Gather saved conformer information to ensure uniqueness of current output + saved_locs, saved_geos, saved_enes = _saved_cnf_info( + cnf_save_fs, mod_thy_info, locs) # Assess if geometry is properly connected viable = _geo_connected(geo, zrxn) if viable: if zrxn: viable = _ts_geo_viable( - zma, zrxn, cnf_save_fs, thy_info, ref_zma=ref_zma) + zma, zrxn, cnf_save_fs, mod_thy_info, ref_zma=ref_zma) else: viable = _inchi_are_same(orig_ich, geo) # Determine uniqueness of conformer, save if needed if viable: if _geo_unique(geo, ene, saved_geos, saved_enes, zrxn): + # Determine correct ring location + existing_rid = rng_loc_for_geo(geo, cnf_save_fs) + rid, cid = locs + if existing_rid is None: + if [rid] in cnf_save_fs[-2].existing(): + rid = autofile.schema.generate_new_ring_id() + print("Generating new ring state folder RID") + else: + rid = existing_rid + locs = (rid, cid) + + # if symmetrical to saved conformer, + # save under SYM/ of corresponding saved conformer + # otherwise save it under its own CONF/rid/cid sym_id = _sym_unique( geo, ene, saved_geos, saved_enes) - # Determine correct ring location - rid = rng_loc_for_geo(geo, cnf_save_fs) - if rid is None: - rid = autofile.schema.generate_new_ring_id() - print("Generating new ring state folder RID") - _,cid = locs - locs = (rid,cid) if sym_id is None: filesys.save.conformer( - ret, None, cnf_save_fs, thy_info[1:], + ret, None, cnf_save_fs, mod_thy_info[1:], init_zma=init_zma, zrxn=zrxn, rng_locs=(locs[0],), tors_locs=(locs[1],)) else: @@ -1411,18 +1428,31 @@ def save_conformer(ret, cnf_run_fs, cnf_save_fs, locs, thy_info, zrxn=None, check_dct = {'dist': 0.3, 'tors': None} else: check_dct = {'dist': 0.3} - unique, match_idx = automol.geom.is_unique(geo, sym_geos, check_dct=check_dct) + unique, match_idx = automol.geom.is_unique( + geo, sym_geos, check_dct=check_dct) if unique: filesys.save.sym_indistinct_conformer( geo, cnf_save_fs, locs, sym_locs, inf_obj=ret[0]) - - # if cnf_save_fs[-1].exists(locs): - # cnf_save_path = cnf_save_fs[-1].path(locs) - # shutil.rmtree(cnf_save_path) - # if cnf_run_fs[-1].exists(locs): - # cnf_run_path = cnf_run_fs[-1].path(locs) - # shutil.rmtree(cnf_run_path) - else: + + # Update the conformer trajectory files rid/conf.t.xyz and potentially also + # rid/cid/conf.t.xyz + obj('vspace') + if rid_traj and [rid] in cnf_save_fs[-2].existing(): + filesys.mincnf.traj_sort(cnf_save_fs, mod_thy_info, rid=rid) + else: + filesys.mincnf.traj_sort(cnf_save_fs, mod_thy_info, rid=None) + + else: + # Note: this is clearing both the run and save filesystems + # if not unique. The save removal should always do nothing + # because it should not exist there if not unique. + # perhaps an old cleanup attempt: + # https://github.com/Auto-Mech/mechdriver/commit/f5f6bab75df92ba91230ee80469f86e50306767a + # I think removing the run is bad, because we have checks to see if + # a new conformer we want to optimize has already been run + # but optimized into something non-unique. If we remove it here, + # we lose that record. + # - Sarah 01/15/2026 if cnf_save_fs[-1].exists(locs): cnf_save_path = cnf_save_fs[-1].path(locs) shutil.rmtree(cnf_save_path) @@ -1430,19 +1460,11 @@ def save_conformer(ret, cnf_run_fs, cnf_save_fs, locs, thy_info, zrxn=None, cnf_run_path = cnf_run_fs[-1].path(locs) shutil.rmtree(cnf_run_path) - # Update the conformer trajectory file - obj('vspace') - rid = None - if rid_traj: - if rid in cnf_save_fs[-1].existing(): - rid = locs[0] - filesys.mincnf.traj_sort(cnf_save_fs, thy_info, rid=rid) - -def _saved_cnf_info(cnf_save_fs, mod_thy_info, orig_locs=None): +def _saved_cnf_info( + cnf_save_fs: object, mod_thy_info: tuple, orig_locs: tuple=None): """ get the locs, geos and enes for saved conformers """ - saved_locs = list(cnf_save_fs[-1].existing()) saved_locs = [locs for locs in saved_locs if not locs == orig_locs] saved_geos = [cnf_save_fs[-1].file.geometry.read(locs) @@ -1486,45 +1508,86 @@ def _saved_cnf_info(cnf_save_fs, mod_thy_info, orig_locs=None): return found_saved_locs, found_saved_geos, found_saved_enes -def _init_geom_is_running(cnf_run_fs): +def _init_geom_is_needed( + cnf_save_fs: object, cnf_run_fs: object, + mod_thy_info: tuple, overwrite: bool=False): + """ Determine if initial geometry optimization is needed + """ + # Check to see if conformer already exists in the save filesys + _, cnf_path = filesys.mincnf.min_energy_conformer_locators( + cnf_save_fs, mod_thy_info) + if cnf_path: + if overwrite: + info_message( + f'Overwrite will search for new conformer' + f'despite existing conformer at {cnf_path}') + return True + existing_path('Initial geometry', cnf_path) + return False + + # Check to see if it exists or is running in the run filesystem + info_message('Checking for running jobs...') + if _init_geom_is_running(cnf_run_fs) and not overwrite: + info_message( + 'No conformers are running in run filesys.' + 'Proceeding with optimization...') + return False + return True + + +def _init_geom_is_running(cnf_run_fs: object): """ Check the RUN filesystem for currently running initial geometry submissions """ - running = False jobs = [elstruct.Job.OPTIMIZATION, elstruct.Job.HESSIAN] locs = cnf_run_fs[-1].existing() if not locs: - wait_time = random.randint(10, 60) - print('lets wait a bit', wait_time) + # this gives us a random chance to desynchronize jobs that were launched + # at the exact same time (which means they might both check the run.yaml + # for existing jobs at the same time, see none, and both launch) + # it is not the ideal solution, but it is simple and should work most of the time + # Get the unique PID and current time + rng = numpy.random.default_rng(os.getpid()) + wait_time = rng.uniform(2, 40) + print(f'Starting job in {wait_time:3.2f}s if no other submissions launch it') time.sleep(wait_time) locs = cnf_run_fs[-1].existing() - print('im going to check locs', cnf_run_fs[-1].existing()) + + # Check all of the conformer locations for this species/LoT in the run filesystem + # to make sure the desired job is not already running/just succeeded for locs in cnf_run_fs[-1].existing(): - cnf_run_path = cnf_run_fs[-1].path(locs) - run_fs = autofile.fs.run(cnf_run_path) - print('im going to check here', cnf_run_path) + run_fs = autofile.fs.run(cnf_run_fs[-1].path(locs)) for job in jobs: if not run_fs[-1].file.info.exists([job]): continue - print('im going to check it job', job) inf_obj = run_fs[-1].file.info.read([job]) status = inf_obj.status - print('its job status is', status) + start_time = inf_obj.utc_start_time + current_time = autofile.schema.utc_time() + elapsed_time = (current_time - start_time).total_seconds() if status == autofile.schema.RunStatus.RUNNING: - start_time = inf_obj.utc_start_time - current_time = autofile.schema.utc_time() - _time = (current_time - start_time).total_seconds() - print('its jtime is', _time) - if _time < 3000000: + # a month is probably long enough for any initial geometry optimization + # but maybe someone decides to do an init geom with CCSDTQP + if elapsed_time < 3000000: path = cnf_run_fs[-1].path(locs) info_message( - 'init_geom was started in the last ' - f'{_time/3600:3.4f} hours in {path}.') - running = True - break - return running + f'An init_geom task was started by another submission ' + f'in the last {elapsed_time/3600:3.4f} hours in {path}.') + return True + elif status == autofile.schema.RunStatus.SUCCESS: + # this time should be stricter, its should only pass if a running job + # finished in the middle of the running check, otherwise finished + # jobs that didn't make it to save mean something was wrong with the + # final optimized structure + if elapsed_time < 500: + path = cnf_run_fs[-1].path(locs) + info_message( + f'An init_geom was successfully completed by another submission ' + f'in the last {elapsed_time/3600:3.4f} hours in {path}.') + return True + return False -def this_conformer_was_run_in_save(zma, cnf_fs): +def this_conformer_was_run_in_save(zma, cnf_fs: object): """ Assess if a conformer was run in save """ running = False @@ -1564,7 +1627,7 @@ def this_conformer_was_run_in_save(zma, cnf_fs): return running -def this_conformer_is_running(zma, cnf_run_fs): +def this_conformer_is_running(zma, cnf_run_fs: object): """ Check the RUN filesystem for similar geometry submissions that are currently running """ @@ -1603,11 +1666,9 @@ def this_conformer_is_running(zma, cnf_run_fs): return running -def _geo_connected(geo, rxn): - """ Assess if geometry is connected. Right now only works for - minima +def _geo_connected(geo: object, rxn: object=None): + """ Assess if geometry is connected. Right now only works for minima """ - # Determine connectivity (only for minima) if rxn is None: gra = automol.geom.graph(geo) @@ -1626,7 +1687,9 @@ def _geo_connected(geo, rxn): return connected -def _geo_unique(geo, ene, seen_geos, seen_enes, zrxn=None): +def _geo_unique( + geo: object, ene: float, + seen_geos: list, seen_enes: list, zrxn: object=None): """ Assess if a geometry is unique to saved geos Need to pass the torsions """ @@ -1653,7 +1716,7 @@ def _geo_unique(geo, ene, seen_geos, seen_enes, zrxn=None): return unique -def _inchi_are_same(orig_ich, geo): +def _inchi_are_same(orig_ich: str, geo: object): """ Assess if a geometry has the same connectivity to saved geos evaluated in temrs of inchi """ @@ -1670,21 +1733,12 @@ def _inchi_are_same(orig_ich, geo): return same -def _check_old_inchi(orig_ich, seen_geos, saved_locs, cnf_save_fs): - """ - This assumes you already have bad geos in your save - """ - for i, geoi in enumerate(seen_geos): - if not orig_ich == automol.geom.chi(geoi): - smi = automol.geom.smiles(geoi) - path = cnf_save_fs[-1].path(saved_locs[i]) - error_message( - f'inchi do not match for {smi} at {path}') - - -def _sym_unique(geo, ene, saved_geos, saved_enes, ethresh=1.0e-5): +def _sym_unique( + geo: object, ene: float, saved_geos: list, + saved_enes: list, ethresh: float=1.0e-5): """ Check if a conformer is symmetrically distinct from the - existing conformers in the filesystem + existing conformers in the filesystem, returns index of + the matching conformer if not symmetrically unique """ sym_idx = None @@ -1851,36 +1905,35 @@ def unique_fs_confs(cnf_save_fs, cnf_save_locs_lst, return uni_ini_cnf_save_locs -def rng_loc_for_geo(geo, cnf_save_fs): +def rng_loc_for_geo(geo, cnf_save_fs, ang_tol=.2): """ Find the ring-conf locators for a given geometry in the conformer save filesystem """ rid = None + checked_rids = [] + frag_geo = automol.geom.ring_fragments_geometry(geo) if frag_geo is not None: frag_zma = automol.geom.zmatrix(frag_geo) - checked_rids = [] + for locs in cnf_save_fs[-1].existing(): - print("Debug: locs", locs) current_rid, _ = locs + if frag_geo is None: + rid = current_rid + break if current_rid in checked_rids: continue checked_rids.append(current_rid) locs_geo = cnf_save_fs[-1].file.geometry.read(locs) frag_locs_geo = automol.geom.ring_fragments_geometry(locs_geo) - if frag_geo is None: - rid = locs[0] - break - else: - if frag_locs_geo is None: - continue + if frag_locs_geo is None: + continue frag_locs_zma = automol.geom.zmatrix(frag_locs_geo) if automol.zmat.almost_equal(frag_locs_zma, frag_zma, - dist_rtol=0.018, ang_atol=.1): - rid = locs[0] - print("Debug: Zmat similar - locs: ", locs) + dist_rtol=0.018, ang_atol=ang_tol): + rid = current_rid break return rid diff --git a/src/mechroutines/es/runner/scan.py b/src/mechroutines/es/runner/scan.py index fbe8c291..03e00e3f 100644 --- a/src/mechroutines/es/runner/scan.py +++ b/src/mechroutines/es/runner/scan.py @@ -35,8 +35,8 @@ def execute_scan(zma, spc_info, mod_thy_info, # Need a resave option _fin = scan_finished( - coord_names, coord_grids, scn_save_fs, - constraint_dct=constraint_dct, overwrite=overwrite) + coord_names, coord_grids, scn_save_fs, scn_run_fs, + scn_typ, constraint_dct=constraint_dct, overwrite=overwrite) if not _fin: run_scan( @@ -524,8 +524,8 @@ def scan_locs(scn_save_fs, coord_names, constraint_dct=None): return coord_locs, scn_locs -def scan_finished(coord_names, coord_grids, scn_save_fs, - constraint_dct=None, overwrite=False): +def scan_finished(coord_names, coord_grids, scn_save_fs, scn_run_fs, + scn_typ, job=None, constraint_dct=None, overwrite=False): """ Assesses if the scan calculations requested by the user have been completed by assessing if Z-Matrices exist in the filesystem for all grid values of the scan coordinates. @@ -536,6 +536,10 @@ def scan_finished(coord_names, coord_grids, scn_save_fs, :type coord_grids: tuple(tuple(float)) :param scn_save_fs: SCAN/CSCAN object with save filesys prefix :type scn_save_fs: autofile.fs.scan or autofile.fs.cscan object + :param scn_run_fs: SCAN/CSCAN object with run filesys prefix + :type scn_run_fs: autofile.fs.scan or autofile.fs.cscan object + :param scn_typ: label for scan type ('relaxed' or 'rigid') + :type scn_typ: str :param constraint_dct: values of coordinates to constrain during scan :type constraint_dct: dict[str: float] :param overwrite: @@ -544,7 +548,7 @@ def scan_finished(coord_names, coord_grids, scn_save_fs, """ run_finished = True - + job = _set_job(scn_typ) if not overwrite: grid_vals = tuple(itertools.product(*coord_grids)) for vals in grid_vals: @@ -555,17 +559,34 @@ def scan_finished(coord_names, coord_grids, scn_save_fs, locs = [constraint_dct] + locs # Check if ZMA (other info?) exists - if not scn_save_fs[-1].file.zmatrix.exists(locs): - run_finished = False - break + if scn_save_fs[-1].file.zmatrix.exists(locs): + continue + + # If no zma, check if the scan is suceeded or failed + if scn_run_fs[-1].exists(locs): + run_fs = autofile.fs.run(scn_run_fs[-1].path(locs)) + if run_fs[-1].file.info.exists([job]): + inf_obj = run_fs[-1].file.info.read([job]) + if inf_obj.status == autofile.schema.RunStatus.FAILURE: + ioprinter.info_message( + 'Scan point dropped at ', locs) + continue + if inf_obj.status == autofile.schema.RunStatus.RUNNING: + ioprinter.info_message( + 'Scan job is currently running at ', + coord_names, locs) + run_finished = False + break + ioprinter.info_message( + 'Waiting for scan point to be started at ', locs) + run_finished = False + break else: run_finished = False ioprinter.message('User elected to overwrite scan') if run_finished: ioprinter.message(f'Scan saved previously at {scn_save_fs[0].path()}') - else: - ioprinter.message('Need to run scans') return run_finished diff --git a/src/mechroutines/es/ts/_rpath.py b/src/mechroutines/es/ts/_rpath.py index 954823ea..6ca3a950 100644 --- a/src/mechroutines/es/ts/_rpath.py +++ b/src/mechroutines/es/ts/_rpath.py @@ -75,6 +75,8 @@ def internal_coordinates_scan(ts_zma, zrxn, coord_names=coord_names, coord_grids=coord_grids, scn_save_fs=_scn_save_fs, + scn_run_fs=_scn_run_fs, + scn_typ='relaxed', constraint_dct=constraint_dct, ) if scan_finished_ and find_max: diff --git a/src/mechroutines/es/tsk.py b/src/mechroutines/es/tsk.py index 53f3efcc..fd0db37d 100644 --- a/src/mechroutines/es/tsk.py +++ b/src/mechroutines/es/tsk.py @@ -166,20 +166,18 @@ def conformer_tsk(job, spc_dct, spc_name, :type save_prefix: str """ - saddle = bool('ts_' in spc_name) + overwrite = es_keyword_dct['overwrite'] + retryfail = es_keyword_dct['retryfail'] + # Get species information out of dictionaries spc_dct_i = spc_dct[spc_name] - - # Set the spc_info - if not saddle: + zrxn = spc_dct_i.get('zrxn', None) + if zrxn is None: spc_info = sinfo.from_dct(spc_dct_i, canonical=True) else: spc_info = rinfo.ts_info(spc_dct_i['canon_rxn_info']) - zrxn = spc_dct_i.get('zrxn', None) - overwrite = es_keyword_dct['overwrite'] - retryfail = es_keyword_dct['retryfail'] - # Modify the theory + # Get method information out of dictionaries method_dct = thy_dct.get(es_keyword_dct['runlvl']) ini_method_dct = thy_dct.get(es_keyword_dct['inplvl']) thy_info = tinfo.from_dct(method_dct) @@ -188,8 +186,12 @@ def conformer_tsk(job, spc_dct, spc_name, mod_ini_thy_info = tinfo.modify_orb_label( ini_thy_info, spc_info) nprocs = method_dct['nprocs'] - # New filesystem objects - _root = root_locs(spc_dct_i, saddle=saddle, name=spc_name) + + # Create/locate filesystem for running/saving + _root = root_locs( + spc_dct_i, + saddle=(zrxn is not None), + name=spc_name) ini_cnf_run_fs, ini_cnf_save_fs = build_fs( run_prefix, save_prefix, 'CONFORMER', thy_locs=mod_ini_thy_info[1:], @@ -201,47 +203,52 @@ def conformer_tsk(job, spc_dct, spc_name, if job == 'samp': - # Build the ini zma filesys + # Determine the initial conformers to sample from user_conf_ids = spc_dct_i.get('conf_id') + all_locs, all_paths = filesys.mincnf.conformer_locators( + ini_cnf_save_fs, mod_ini_thy_info, cnf_range='all', nprocs=nprocs) + ini_confs = [] + ### TODO give option to only sample minimum ring state + ### (currently done on individual case by user specifying conf_id) if user_conf_ids is None: - ini_loc_info = filesys.mincnf.min_energy_conformer_locators( - ini_cnf_save_fs, mod_ini_thy_info, nprocs=nprocs) - ini_locs, ini_min_cnf_path = ini_loc_info - - all_locs,all_paths = filesys.mincnf.conformer_locators( - cnf_save_fs, mod_thy_info, cnf_range='all', nprocs=nprocs) + # Collect the minimum energy conformer of each ring state unique_rids = set() - ini_confs = [] - for loc,loc_path in zip(all_locs,all_paths): + for loc, loc_path in zip(all_locs, all_paths): if loc[0] not in unique_rids: - ini_confs.append((loc,loc_path)) + ini_confs.append((loc, loc_path)) unique_rids.add(loc[0]) - visited_rids = set() - else: + # Use only user specified conformer print(f'Using user specified conformer IDs: {user_conf_ids}') - ini_locs = user_conf_ids + for loc, loc_path in zip(all_locs, all_paths): + if loc == user_conf_ids: + ini_confs.append((loc, loc_path)) - if any(ini_locs): - ini_zma_save_fs = autofile.fs.zmatrix(ini_min_cnf_path) + if not any(ini_confs): + ioprinter.info_message( + 'Missing conformers. Skipping task...') - # Set up the run scripts - script_str, kwargs = qchem_params( - method_dct, elstruct.Job.OPTIMIZATION) + # Set up the run scripts + script_str, kwargs = qchem_params( + method_dct, elstruct.Job.OPTIMIZATION) - # Set variables if it is a saddle - two_stage = saddle - mc_nsamp = spc_dct_i['mc_nsamp'] - resave = es_keyword_dct['resave'] + # Set variables if it is a saddle + two_stage = zrxn is not None + mc_nsamp = spc_dct_i['mc_nsamp'] + resave = es_keyword_dct['resave'] - # Read the geometry and zma from the ini file system + # Loop over all the initial conformers to sample from + for ini_locs, ini_path in ini_confs: + + # Read the geometry and zma from the initial file system + ini_zma_save_fs = autofile.fs.zmatrix(ini_path) geo = ini_cnf_save_fs[-1].file.geometry.read(ini_locs) zma_locs = (0,) - if saddle: + if zrxn is not None: zma_locs = ts_zma_locs(spc_dct, spc_name, ini_zma_save_fs) zma = ini_zma_save_fs[-1].file.zmatrix.read(zma_locs) - # Read the torsions from the ini file sys + # Read the torsions from the initial file sys if ini_zma_save_fs[-1].file.torsions.exists(zma_locs): tors_lst = ini_zma_save_fs[-1].file.torsions.read(zma_locs) rotors = automol.data.rotor.rotors_from_data(zma, tors_lst) @@ -249,27 +256,19 @@ def conformer_tsk(job, spc_dct, spc_name, else: tors_names = () - geo_path = ini_cnf_save_fs[-1].path(ini_locs) - ioprinter.initial_geom_path('Sampling started', geo_path) - - # Check runsystem for equal ring CONF make conf_fs - # Else make new ring conf directory - # Why should RID be None? I am taking stuff from filesys so it will already have a RID! - rid = ini_locs[0] - # rid = conformer.rng_loc_for_geo(geo, cnf_save_fs) - # print("Debug: back to tsk - rid", rid) - - # if rid is None: - # conformer.single_conformer( - # zma, spc_info, mod_thy_info, - # cnf_run_fs, cnf_save_fs, - # script_str, overwrite, - # retryfail=retryfail, zrxn=zrxn, - # **kwargs) + ioprinter.initial_geom_path( + 'Sampling started', + ini_cnf_save_fs[-1].path(ini_locs)) - # rid = conformer.rng_loc_for_geo( - # geo, cnf_save_fs) + rid = conformer.rng_loc_for_geo(geo, cnf_save_fs) + if rid is None: + rid = conformer.rng_loc_for_geo(geo, ini_cnf_save_fs) + # use the rid for the initial LoT unless it corresponds + # to a different puckering state at the run LoT + if rid is None or [rid] in cnf_save_fs[-2].existing(): + rid = autofile.schema.generate_new_ring_id() + # Run the sampling conformer.conformer_sampling( zma, spc_info, mod_thy_info, @@ -278,58 +277,10 @@ def conformer_tsk(job, spc_dct, spc_name, nsamp_par=mc_nsamp, tors_names=tors_names, zrxn=zrxn, two_stage=two_stage, - retryfail=retryfail, resave=resave, + retryfail=retryfail, resave=False, repulsion_thresh=40.0, print_debug=print_debug, **kwargs) - visited_rids.add(rid) - if True: - for ini_locs,ini_path in ini_confs: - if ini_locs[0] not in visited_rids: - ini_zma_save_fs = autofile.fs.zmatrix(ini_path) - # Set up the run scripts - # script_str, kwargs = qchem_params( - # method_dct, elstruct.Job.OPTIMIZATION) - # Set variables if it is a saddle - # two_stage = saddle - # mc_nsamp = spc_dct_i['mc_nsamp'] - # resave = resave - - # Read the geometry and zma from the ini file system - geo = ini_cnf_save_fs[-1].file.geometry.read(ini_locs) - zma_locs = (0,) - if saddle: - zma_locs = ts_zma_locs(spc_dct, spc_name, ini_zma_save_fs) - zma = ini_zma_save_fs[-1].file.zmatrix.read(zma_locs) - - # Read the torsions from the ini file sys - if ini_zma_save_fs[-1].file.torsions.exists(zma_locs): - tors_lst = ini_zma_save_fs[-1].file.torsions.read(zma_locs) - rotors = automol.data.rotor.rotors_from_data(zma, tors_lst) - tors_names = automol.data.rotor.rotors_torsion_names(rotors, flat=True) - else: - tors_names = () - - geo_path = ini_cnf_save_fs[-1].path(ini_locs) - ioprinter.initial_geom_path('Sampling started', geo_path) - rid = ini_locs[0] - # Run the sampling - conformer.conformer_sampling( - zma, spc_info, mod_thy_info, - cnf_run_fs, cnf_save_fs, rid, - script_str, overwrite, - nsamp_par=mc_nsamp, - tors_names=tors_names, - zrxn=zrxn, two_stage=two_stage, - retryfail=retryfail, resave=False, - repulsion_thresh=40.0, print_debug=print_debug, - **kwargs) - - - - else: - ioprinter.info_message( - 'Missing conformers. Skipping task...') elif job == 'pucker': algo = es_keyword_dct['algorithm'] @@ -341,54 +292,59 @@ def conformer_tsk(job, spc_dct, spc_name, ini_loc_info = filesys.mincnf.min_energy_conformer_locators( ini_cnf_save_fs, mod_ini_thy_info, nprocs=nprocs) ini_min_locs, ini_min_cnf_path = ini_loc_info - ini_zma_save_fs = autofile.fs.zmatrix(ini_min_cnf_path) + + if not ini_min_cnf_path: + ioprinter.info_message( + 'No conformer found for starting point. Skipping task...') + else: + ini_zma_save_fs = autofile.fs.zmatrix(ini_min_cnf_path) - # Set up the run scripts - script_str, kwargs = qchem_params( - method_dct, elstruct.Job.OPTIMIZATION) - # Always run two stage optimization - two_stage = True - mc_nsamp = spc_dct_i['mc_nsamp'] + # Set up the run scripts + script_str, kwargs = qchem_params( + method_dct, elstruct.Job.OPTIMIZATION) + # Always run two stage optimization + two_stage = True + mc_nsamp = spc_dct_i['mc_nsamp'] - # Read the geometry and zma from the ini file system - geo = ini_cnf_save_fs[-1].file.geometry.read(ini_min_locs) - zma_locs = (0,) - if saddle: - zma_locs = ts_zma_locs(spc_dct, spc_name, ini_zma_save_fs) - zma = ini_zma_save_fs[-1].file.zmatrix.read(zma_locs) + # Read the geometry and zma from the ini file system + geo = ini_cnf_save_fs[-1].file.geometry.read(ini_min_locs) + zma_locs = (0,) + if zrxn is not None: + zma_locs = ts_zma_locs(spc_dct, spc_name, ini_zma_save_fs) + zma = ini_zma_save_fs[-1].file.zmatrix.read(zma_locs) - # Read the ring torsions from the ini file sys - if ini_zma_save_fs[-1].file.ring_torsions.exists(zma_locs): - ring_tors_dct = ini_zma_save_fs[-1].file.ring_torsions.read(zma_locs) - else: - ring_tors_dct = {} + # Read the ring torsions from the ini file sys + if ini_zma_save_fs[-1].file.ring_torsions.exists(zma_locs): + ring_tors_dct = ini_zma_save_fs[-1].file.ring_torsions.read(zma_locs) + else: + ring_tors_dct = {} - # Read the torsions from the ini file sys - if ini_zma_save_fs[-1].file.torsions.exists(zma_locs): - tors_lst = ini_zma_save_fs[-1].file.torsions.read(zma_locs) - rotors = automol.data.rotor.rotors_from_data(zma, tors_lst) - tors_names = automol.data.rotor.rotors_torsion_names(rotors, flat=True) - else: - tors_names = () - - geo_path = ini_cnf_save_fs[-1].path(ini_min_locs) - ioprinter.initial_geom_path('Sampling started', geo_path) - - # Run the sampling - conformer.ring_conformer_sampling( - zma, spc_info, mod_thy_info, - cnf_run_fs, cnf_save_fs, - script_str, overwrite, - tors_names, - algorithm=algo, - thresholds=thresh_pucker, - eps=eps, - checks=checks, - rand_tors=rand_tors, - nsamp_par=mc_nsamp, - ring_tors_dct=ring_tors_dct, zrxn=zrxn, - two_stage=two_stage, retryfail=retryfail, - **kwargs) + # Read the torsions from the ini file sys + if ini_zma_save_fs[-1].file.torsions.exists(zma_locs): + tors_lst = ini_zma_save_fs[-1].file.torsions.read(zma_locs) + rotors = automol.data.rotor.rotors_from_data(zma, tors_lst) + tors_names = automol.data.rotor.rotors_torsion_names(rotors, flat=True) + else: + tors_names = () + + geo_path = ini_cnf_save_fs[-1].path(ini_min_locs) + ioprinter.initial_geom_path('Sampling started', geo_path) + + # Run the sampling + conformer.ring_conformer_sampling( + zma, spc_info, mod_thy_info, + cnf_run_fs, cnf_save_fs, + script_str, overwrite, + tors_names, + algorithm=algo, + thresholds=thresh_pucker, + eps=eps, + checks=checks, + rand_tors=rand_tors, + nsamp_par=mc_nsamp, + ring_tors_dct=ring_tors_dct, zrxn=zrxn, + two_stage=two_stage, retryfail=retryfail, + **kwargs) elif job == 'opt': @@ -402,24 +358,32 @@ def conformer_tsk(job, spc_dct, spc_name, script_str, kwargs = qchem_params( method_dct, elstruct.Job.OPTIMIZATION) + # collect the conformers saved at the run LoT rng_cnf_locs_lst, _ = filesys.mincnf.conformer_locators( cnf_save_fs, mod_thy_info, - cnf_range='all', nprocs=nprocs) - + cnf_range='all', nprocs=nprocs, print_level=0) + + # choose conformers from the ini LoT to optimize at run LoT ini_rng_cnf_locs_lst, _ = filesys.mincnf.conformer_locators( ini_cnf_save_fs, mod_ini_thy_info, cnf_range=cnf_range, sort_info_lst=cnf_sort_info_lst, hbond_cutoffs=hbond_cutoffs, - print_enes=True, nprocs=nprocs) + print_level=2, nprocs=nprocs) - # Truncate the list of the ini confs + if not ini_rng_cnf_locs_lst: + ioprinter.warning_message( + f'No min-energy conformer found at {ini_cnf_save_fs[0].path()}') + if ini_cnf_save_fs[-1].existing(): + ioprinter.warning_message( + ' likely due to missing sorting criteria.' + ) + print(cnf_sort_info_lst) + + # Determine which of the requested conformers are unique to the ini + # LoT save, and are not in the run LoT save uni_rng_locs_lst, uni_cnf_locs_lst = conformer.unique_fs_ring_confs( cnf_save_fs, rng_cnf_locs_lst, ini_cnf_save_fs, ini_rng_cnf_locs_lst) - # ioprinter.debug_message( - # 'uni lst that has no similar ring', uni_rng_locs_lst) - # ioprinter.debug_message( - # 'uni lst that has similar ring', uni_cnf_locs_lst) for locs in uni_rng_locs_lst + uni_cnf_locs_lst: @@ -431,10 +395,11 @@ def conformer_tsk(job, spc_dct, spc_name, ini_locs, rid = locs cid = autofile.schema.generate_new_conformer_id() + # get the zma for the ini LoT conformer for the current locs ini_cnf_save_path = ini_cnf_save_fs[-1].path(ini_locs) ini_zma_save_fs = autofile.fs.zmatrix(ini_cnf_save_path) zma_locs = (0,) - if saddle: + if zrxn is not None: zma_locs = ts_zma_locs(spc_dct, spc_name, ini_zma_save_fs) zma = ini_zma_save_fs[-1].file.zmatrix.read(zma_locs) @@ -449,7 +414,7 @@ def conformer_tsk(job, spc_dct, spc_name, zma, instab_zmas, cnf_save_fs, rng_locs=(rid,), tors_locs=(cid,), zma_locs=(0,)) else: - # Make the ring filesystem + # Optimize the conformer at the run LoT conformer.single_conformer( zma, spc_info, mod_thy_info, cnf_run_fs, cnf_save_fs, @@ -480,7 +445,7 @@ def conformer_tsk(job, spc_dct, spc_name, ini_cnf_save_fs, mod_ini_thy_info, cnf_range=cnf_range, sort_info_lst=cnf_sort_info_lst, hbond_cutoffs=hbond_cutoffs, - print_enes=True, nprocs=nprocs) + print_level=2, nprocs=nprocs) else: print(f'Using user specified conformer IDs: {user_conf_ids}') ini_rng_cnf_locs_lst = (user_conf_ids,) @@ -517,7 +482,7 @@ def conformer_tsk(job, spc_dct, spc_name, ini_zma_save_fs = autofile.fs.zmatrix(geo_save_path) geo = ini_cnf_save_fs[-1].file.geometry.read(ini_locs) zma_locs = (0,) - if saddle: + if zrxn is not None: zma_locs = ts_zma_locs(spc_dct, spc_name, ini_zma_save_fs) zma = ini_zma_save_fs[-1].file.zmatrix.read(zma_locs) @@ -849,7 +814,7 @@ def hr_tsk(job, spc_dct, spc_name, ini_cnf_save_fs, mod_ini_thy_info, cnf_range=cnf_range, sort_info_lst=cnf_sort_info_lst, hbond_cutoffs=hbond_cutoffs, - print_enes=True, nprocs=nprocs) + print_level=2, nprocs=nprocs) else: ini_min_locs_lst = (user_conf_ids,) ini_path_lst = (ini_cnf_save_fs[-1].path(user_conf_ids),) diff --git a/src/mechroutines/proc/_collect.py b/src/mechroutines/proc/_collect.py index ea6cf903..5a391930 100644 --- a/src/mechroutines/proc/_collect.py +++ b/src/mechroutines/proc/_collect.py @@ -337,8 +337,8 @@ def enthalpy( if cnf_fs[-1].file.hessian.exists(locs): # print(pf_filesystems) ene_abs = ene.read_energy( - spc_dct_i, pf_filesystems, spc_mod_dct_i, - run_prefix, spc_dct, conf=(locs, locs_path, cnf_fs), + spc_dct_i, pf_filesystems, spc_mod_dct_i, spc_dct, + run_prefix, conf=(locs, locs_path, cnf_fs), read_ene=True, read_zpe=True, saddle=saddle) hf0k, _, chn_basis_ene_dct, hbasis = basis.enthalpy_calculation( spc_dct, spc_name, ene_abs, diff --git a/src/mechroutines/proc/_util.py b/src/mechroutines/proc/_util.py index 19986beb..a1238b8b 100644 --- a/src/mechroutines/proc/_util.py +++ b/src/mechroutines/proc/_util.py @@ -142,7 +142,7 @@ def choose_conformers( rng_cnf_locs_lst, rng_cnf_locs_path = filesys.mincnf.conformer_locators( cnf_save_fs, mod_thy_info, cnf_range=cnf_range, sort_info_lst=sort_info_lst, hbond_cutoffs=hbond_cutoffs, - print_enes=True, nprocs=proc_keyword_dct['nprocs']) + print_level=2, nprocs=proc_keyword_dct['nprocs']) if populate_symm: for cnf_locs, cnf_path in zip(rng_cnf_locs_lst, rng_cnf_locs_path): symm_fs = autofile.fs.symmetry(cnf_path) diff --git a/src/mechroutines/trans/_routines/_trans.py b/src/mechroutines/trans/_routines/_trans.py index 4d40d518..b46e4ee1 100644 --- a/src/mechroutines/trans/_routines/_trans.py +++ b/src/mechroutines/trans/_routines/_trans.py @@ -172,7 +172,7 @@ def _etrans_fs(spc_dct, tgt_name, bath_name, cnf_range=etrans_keyword_dct['cnf_range'], sort_info_lst=cnf_sort_info_lst, hbond_cutoffs=spc_dct_i['hbond_cutoffs'], - print_enes=True, + print_level=2, nprocs=1) min_cnf_locs = cnf_rng_info[0][0] diff --git a/tests/archive.tgz b/tests/archive.tgz index 3e579810..198ec1bd 100644 Binary files a/tests/archive.tgz and b/tests/archive.tgz differ