CodeEntropy 2.0.0__tar.gz → 2.1.0__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.
- {codeentropy-2.0.0 → codeentropy-2.1.0}/.github/workflows/daily.yaml +1 -1
- {codeentropy-2.0.0 → codeentropy-2.1.0}/.github/workflows/pr.yaml +2 -2
- {codeentropy-2.0.0 → codeentropy-2.1.0}/.github/workflows/release.yaml +11 -5
- {codeentropy-2.0.0 → codeentropy-2.1.0}/.github/workflows/weekly-regression.yaml +1 -2
- {codeentropy-2.0.0 → codeentropy-2.1.0}/CITATION.cff +2 -2
- {codeentropy-2.0.0 → codeentropy-2.1.0}/CodeEntropy/__init__.py +1 -1
- {codeentropy-2.0.0 → codeentropy-2.1.0}/CodeEntropy/config/argparse.py +20 -14
- {codeentropy-2.0.0 → codeentropy-2.1.0}/CodeEntropy/config/runtime.py +3 -3
- {codeentropy-2.0.0 → codeentropy-2.1.0}/CodeEntropy/core/logging.py +2 -3
- codeentropy-2.1.0/CodeEntropy/entropy/configurational.py +86 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/CodeEntropy/entropy/graph.py +13 -7
- {codeentropy-2.0.0 → codeentropy-2.1.0}/CodeEntropy/entropy/nodes/aggregate.py +9 -4
- {codeentropy-2.0.0 → codeentropy-2.1.0}/CodeEntropy/entropy/nodes/configurational.py +17 -25
- codeentropy-2.1.0/CodeEntropy/entropy/nodes/orientational.py +84 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/CodeEntropy/entropy/nodes/vibrational.py +31 -14
- codeentropy-2.1.0/CodeEntropy/entropy/orientational.py +117 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/CodeEntropy/entropy/vibrational.py +36 -4
- {codeentropy-2.0.0 → codeentropy-2.1.0}/CodeEntropy/entropy/water.py +9 -8
- {codeentropy-2.0.0 → codeentropy-2.1.0}/CodeEntropy/entropy/workflow.py +42 -18
- {codeentropy-2.0.0 → codeentropy-2.1.0}/CodeEntropy/levels/axes.py +7 -7
- {codeentropy-2.0.0 → codeentropy-2.1.0}/CodeEntropy/levels/dihedrals.py +138 -98
- {codeentropy-2.0.0 → codeentropy-2.1.0}/CodeEntropy/levels/forces.py +18 -13
- {codeentropy-2.0.0 → codeentropy-2.1.0}/CodeEntropy/levels/frame_dag.py +11 -11
- {codeentropy-2.0.0 → codeentropy-2.1.0}/CodeEntropy/levels/hierarchy.py +7 -8
- {codeentropy-2.0.0 → codeentropy-2.1.0}/CodeEntropy/levels/level_dag.py +22 -18
- {codeentropy-2.0.0 → codeentropy-2.1.0}/CodeEntropy/levels/linalg.py +4 -5
- {codeentropy-2.0.0 → codeentropy-2.1.0}/CodeEntropy/levels/mda.py +8 -9
- codeentropy-2.1.0/CodeEntropy/levels/neighbors.py +251 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/CodeEntropy/levels/nodes/accumulators.py +12 -11
- {codeentropy-2.0.0 → codeentropy-2.1.0}/CodeEntropy/levels/nodes/beads.py +12 -11
- {codeentropy-2.0.0 → codeentropy-2.1.0}/CodeEntropy/levels/nodes/conformations.py +28 -13
- {codeentropy-2.0.0 → codeentropy-2.1.0}/CodeEntropy/levels/nodes/covariance.py +45 -45
- {codeentropy-2.0.0 → codeentropy-2.1.0}/CodeEntropy/levels/nodes/detect_levels.py +5 -5
- {codeentropy-2.0.0 → codeentropy-2.1.0}/CodeEntropy/levels/nodes/detect_molecules.py +3 -3
- codeentropy-2.1.0/CodeEntropy/levels/nodes/find_neighbors.py +93 -0
- codeentropy-2.1.0/CodeEntropy/levels/search.py +241 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/CodeEntropy/molecules/grouping.py +7 -7
- {codeentropy-2.0.0 → codeentropy-2.1.0}/CodeEntropy/results/reporter.py +37 -38
- {codeentropy-2.0.0 → codeentropy-2.1.0}/PKG-INFO +6 -4
- {codeentropy-2.0.0 → codeentropy-2.1.0}/README.md +3 -2
- {codeentropy-2.0.0 → codeentropy-2.1.0}/conda-recipe/meta.yaml +11 -6
- {codeentropy-2.0.0 → codeentropy-2.1.0}/docs/conf.py +3 -4
- {codeentropy-2.0.0 → codeentropy-2.1.0}/docs/config.yaml +4 -1
- {codeentropy-2.0.0 → codeentropy-2.1.0}/docs/getting_started.rst +17 -4
- {codeentropy-2.0.0 → codeentropy-2.1.0}/docs/science.rst +33 -6
- {codeentropy-2.0.0 → codeentropy-2.1.0}/pyproject.toml +3 -2
- codeentropy-2.1.0/tests/regression/baselines/benzaldehyde.json +45 -0
- codeentropy-2.0.0/tests/regression/baselines/benzaldehyde.json → codeentropy-2.1.0/tests/regression/baselines/benzaldehyde_rad.json +13 -11
- codeentropy-2.1.0/tests/regression/baselines/benzene.json +45 -0
- codeentropy-2.0.0/tests/regression/baselines/benzene.json → codeentropy-2.1.0/tests/regression/baselines/benzene_rad.json +13 -11
- codeentropy-2.1.0/tests/regression/baselines/cyclohexane.json +45 -0
- codeentropy-2.0.0/tests/regression/baselines/cyclohexane.json → codeentropy-2.1.0/tests/regression/baselines/cylcohexane_rad.json +13 -11
- {codeentropy-2.0.0 → codeentropy-2.1.0}/tests/regression/baselines/dna.json +16 -13
- codeentropy-2.1.0/tests/regression/baselines/ethyl-acetate.json +45 -0
- codeentropy-2.1.0/tests/regression/baselines/ethyl-acetate_rad.json +45 -0
- codeentropy-2.1.0/tests/regression/baselines/methane.json +42 -0
- codeentropy-2.1.0/tests/regression/baselines/methane_rad.json +42 -0
- codeentropy-2.1.0/tests/regression/baselines/methanol.json +45 -0
- codeentropy-2.0.0/tests/regression/baselines/methanol.json → codeentropy-2.1.0/tests/regression/baselines/methanol_rad.json +13 -11
- codeentropy-2.1.0/tests/regression/baselines/octonal_rad.json +45 -0
- codeentropy-2.1.0/tests/regression/baselines/octonol.json +45 -0
- codeentropy-2.1.0/tests/regression/baselines/water.json +42 -0
- codeentropy-2.1.0/tests/regression/baselines/water_rad.json +42 -0
- codeentropy-2.1.0/tests/regression/configs/benzaldehyde/config.yaml +14 -0
- {codeentropy-2.0.0/tests/regression/configs/benzaldehyde → codeentropy-2.1.0/tests/regression/configs/benzaldehyde_rad}/config.yaml +2 -0
- codeentropy-2.1.0/tests/regression/configs/benzene/config.yaml +14 -0
- {codeentropy-2.0.0/tests/regression/configs/benzene → codeentropy-2.1.0/tests/regression/configs/benzene_rad}/config.yaml +2 -0
- codeentropy-2.1.0/tests/regression/configs/cyclohexane/config.yaml +14 -0
- {codeentropy-2.0.0/tests/regression/configs/cyclohexane → codeentropy-2.1.0/tests/regression/configs/cyclohexane_rad}/config.yaml +2 -0
- codeentropy-2.1.0/tests/regression/configs/ethyl-acetate/config.yaml +14 -0
- {codeentropy-2.0.0/tests/regression/configs/ethyl-acetate → codeentropy-2.1.0/tests/regression/configs/ethyl-acetate_rad}/config.yaml +2 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/tests/regression/configs/methane/config.yaml +4 -2
- codeentropy-2.1.0/tests/regression/configs/methane_rad/config.yaml +14 -0
- codeentropy-2.1.0/tests/regression/configs/methanol/config.yaml +14 -0
- {codeentropy-2.0.0/tests/regression/configs/methanol → codeentropy-2.1.0/tests/regression/configs/methanol_rad}/config.yaml +2 -0
- codeentropy-2.1.0/tests/regression/configs/octonol/config.yaml +14 -0
- {codeentropy-2.0.0/tests/regression/configs/octonol → codeentropy-2.1.0/tests/regression/configs/octonol_rad}/config.yaml +2 -0
- codeentropy-2.1.0/tests/regression/configs/water/config.yaml +14 -0
- codeentropy-2.1.0/tests/regression/configs/water_rad/config.yaml +14 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/tests/regression/helpers.py +8 -9
- {codeentropy-2.0.0 → codeentropy-2.1.0}/tests/regression/test_regression.py +9 -8
- {codeentropy-2.0.0 → codeentropy-2.1.0}/tests/unit/CodeEntropy/core/logging/test_export_console.py +1 -1
- codeentropy-2.1.0/tests/unit/CodeEntropy/entropy/nodes/test_orientational_node.py +39 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/tests/unit/CodeEntropy/entropy/nodes/test_vibrational_node.py +16 -7
- codeentropy-2.1.0/tests/unit/CodeEntropy/entropy/test_configurational_edges.py +12 -0
- codeentropy-2.1.0/tests/unit/CodeEntropy/entropy/test_configurational_entropy_math.py +25 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/tests/unit/CodeEntropy/entropy/test_graph.py +2 -0
- codeentropy-2.1.0/tests/unit/CodeEntropy/entropy/test_orientational_entropy.py +34 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/tests/unit/CodeEntropy/entropy/test_vibrational_entropy_math.py +11 -2
- {codeentropy-2.0.0 → codeentropy-2.1.0}/tests/unit/CodeEntropy/entropy/test_workflow.py +23 -11
- {codeentropy-2.0.0 → codeentropy-2.1.0}/tests/unit/CodeEntropy/levels/nodes/test_conformations_node.py +1 -1
- codeentropy-2.1.0/tests/unit/CodeEntropy/levels/nodes/test_find_neighbors.py +33 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/tests/unit/CodeEntropy/levels/test_dihedrals.py +28 -9
- {codeentropy-2.0.0 → codeentropy-2.1.0}/tests/unit/CodeEntropy/levels/test_forces_force_torque_calculator.py +29 -0
- codeentropy-2.1.0/tests/unit/CodeEntropy/levels/test_neighbors.py +489 -0
- codeentropy-2.1.0/tests/unit/CodeEntropy/levels/test_search.py +277 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/tests/unit/CodeEntropy/results/test_reporter.py +1 -2
- codeentropy-2.0.0/CodeEntropy/entropy/configurational.py +0 -266
- codeentropy-2.0.0/CodeEntropy/entropy/orientational.py +0 -158
- codeentropy-2.0.0/tests/regression/baselines/ethyl-acetate.json +0 -43
- codeentropy-2.0.0/tests/regression/baselines/methane.json +0 -40
- codeentropy-2.0.0/tests/regression/baselines/octonol.json +0 -43
- codeentropy-2.0.0/tests/unit/CodeEntropy/entropy/test_configurational_edges.py +0 -90
- codeentropy-2.0.0/tests/unit/CodeEntropy/entropy/test_configurational_entropy_math.py +0 -120
- codeentropy-2.0.0/tests/unit/CodeEntropy/entropy/test_orientational_entropy.py +0 -54
- {codeentropy-2.0.0 → codeentropy-2.1.0}/.github/CONTRIBUTING.md +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/.github/ISSUE_TEMPLATE/documentation.md +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/.github/ISSUE_TEMPLATE/general_report.md +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/.github/renovate.json +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/.github/workflows/update-copyright-years-in-license-file.yaml +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/.github/workflows/weekly-docs.yaml +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/.gitignore +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/.pre-commit-config.yaml +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/CODE_OF_CONDUCT.md +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/CodeEntropy/__main__.py +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/CodeEntropy/cli.py +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/CodeEntropy/config/__init__.py +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/CodeEntropy/core/__init__.py +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/CodeEntropy/entropy/__init__.py +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/CodeEntropy/entropy/nodes/__init__.py +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/CodeEntropy/levels/__init__.py +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/CodeEntropy/levels/nodes/__init__.py +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/CodeEntropy/molecules/__init__.py +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/CodeEntropy/results/__init__.py +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/LICENSE +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/docs/Makefile +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/docs/README.md +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/docs/_static/README.md +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/docs/_static/custom.css +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/docs/_static/logos/biosim-codeentropy_logo_dark.png +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/docs/_static/logos/biosim-codeentropy_logo_light.png +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/docs/_templates/README.md +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/docs/api/CodeEntropy.cli.rst +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/docs/api/CodeEntropy.config.argparse.rst +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/docs/api/CodeEntropy.config.rst +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/docs/api/CodeEntropy.config.runtime.rst +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/docs/api/CodeEntropy.core.logging.rst +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/docs/api/CodeEntropy.core.rst +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/docs/api/CodeEntropy.entropy.configurational.rst +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/docs/api/CodeEntropy.entropy.graph.rst +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/docs/api/CodeEntropy.entropy.nodes.aggregate.rst +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/docs/api/CodeEntropy.entropy.nodes.configurational.rst +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/docs/api/CodeEntropy.entropy.nodes.rst +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/docs/api/CodeEntropy.entropy.nodes.vibrational.rst +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/docs/api/CodeEntropy.entropy.orientational.rst +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/docs/api/CodeEntropy.entropy.rst +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/docs/api/CodeEntropy.entropy.vibrational.rst +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/docs/api/CodeEntropy.entropy.water.rst +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/docs/api/CodeEntropy.entropy.workflow.rst +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/docs/api/CodeEntropy.levels.axes.rst +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/docs/api/CodeEntropy.levels.dihedrals.rst +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/docs/api/CodeEntropy.levels.forces.rst +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/docs/api/CodeEntropy.levels.frame_dag.rst +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/docs/api/CodeEntropy.levels.hierarchy.rst +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/docs/api/CodeEntropy.levels.level_dag.rst +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/docs/api/CodeEntropy.levels.linalg.rst +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/docs/api/CodeEntropy.levels.mda.rst +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/docs/api/CodeEntropy.levels.nodes.accumulators.rst +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/docs/api/CodeEntropy.levels.nodes.beads.rst +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/docs/api/CodeEntropy.levels.nodes.conformations.rst +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/docs/api/CodeEntropy.levels.nodes.covariance.rst +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/docs/api/CodeEntropy.levels.nodes.detect_levels.rst +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/docs/api/CodeEntropy.levels.nodes.detect_molecules.rst +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/docs/api/CodeEntropy.levels.nodes.rst +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/docs/api/CodeEntropy.levels.rst +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/docs/api/CodeEntropy.molecules.grouping.rst +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/docs/api/CodeEntropy.molecules.rst +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/docs/api/CodeEntropy.results.reporter.rst +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/docs/api/CodeEntropy.results.rst +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/docs/api/CodeEntropy.rst +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/docs/api/modules.rst +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/docs/developer_guide.rst +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/docs/faq.rst +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/docs/index.rst +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/readthedocs.yml +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/tests/__init__.py +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/tests/pytest.ini +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/tests/regression/configs/dna/config.yaml +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/tests/regression/conftest.py +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/tests/unit/CodeEntropy/cli/test___main__.py +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/tests/unit/CodeEntropy/cli/test_cli.py +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/tests/unit/CodeEntropy/config/argparse/conftest.py +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/tests/unit/CodeEntropy/config/argparse/test_argparse_build_parser.py +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/tests/unit/CodeEntropy/config/argparse/test_argparse_load_config.py +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/tests/unit/CodeEntropy/config/argparse/test_argparse_resolve.py +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/tests/unit/CodeEntropy/config/argparse/test_argparse_str2bool.py +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/tests/unit/CodeEntropy/config/argparse/test_argparse_validate_inputs.py +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/tests/unit/CodeEntropy/config/runtime/conftest.py +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/tests/unit/CodeEntropy/config/runtime/test_build_universe_branches.py +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/tests/unit/CodeEntropy/config/runtime/test_citation_data.py +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/tests/unit/CodeEntropy/config/runtime/test_create_job_folder.py +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/tests/unit/CodeEntropy/config/runtime/test_print_args_table.py +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/tests/unit/CodeEntropy/config/runtime/test_required_args.py +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/tests/unit/CodeEntropy/config/runtime/test_run_entropy_workflow_branches.py +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/tests/unit/CodeEntropy/config/runtime/test_runtime_properties.py +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/tests/unit/CodeEntropy/config/runtime/test_show_splash.py +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/tests/unit/CodeEntropy/config/runtime/test_unit_conversions.py +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/tests/unit/CodeEntropy/config/runtime/test_universe_io.py +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/tests/unit/CodeEntropy/core/logging/conftest.py +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/tests/unit/CodeEntropy/core/logging/test_configure_loggers.py +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/tests/unit/CodeEntropy/core/logging/test_error_filter.py +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/tests/unit/CodeEntropy/core/logging/test_get_console_singleton.py +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/tests/unit/CodeEntropy/core/logging/test_handlers_setup.py +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/tests/unit/CodeEntropy/core/logging/test_set_level.py +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/tests/unit/CodeEntropy/entropy/conftest.py +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/tests/unit/CodeEntropy/entropy/nodes/test_aggregate_node.py +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/tests/unit/CodeEntropy/entropy/nodes/test_configurational_node.py +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/tests/unit/CodeEntropy/entropy/test_water_entropy.py +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/tests/unit/CodeEntropy/levels/conftest.py +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/tests/unit/CodeEntropy/levels/nodes/test_build_beads_node.py +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/tests/unit/CodeEntropy/levels/nodes/test_detect_levels_node.py +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/tests/unit/CodeEntropy/levels/nodes/test_detect_molecules_node.py +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/tests/unit/CodeEntropy/levels/nodes/test_frame_covariance_node.py +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/tests/unit/CodeEntropy/levels/nodes/test_init_covariance_accumulators_node.py +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/tests/unit/CodeEntropy/levels/test_axes.py +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/tests/unit/CodeEntropy/levels/test_frame_graph.py +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/tests/unit/CodeEntropy/levels/test_hierarchy_builder.py +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/tests/unit/CodeEntropy/levels/test_level_dag_orchestration.py +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/tests/unit/CodeEntropy/levels/test_level_dag_reduce.py +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/tests/unit/CodeEntropy/levels/test_level_dag_reduction.py +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/tests/unit/CodeEntropy/levels/test_linalg_matrix_utils.py +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/tests/unit/CodeEntropy/levels/test_mda_universe_operations.py +0 -0
- {codeentropy-2.0.0 → codeentropy-2.1.0}/tests/unit/CodeEntropy/molecules/test_grouping.py +0 -0
|
@@ -33,7 +33,7 @@ jobs:
|
|
|
33
33
|
python -m pip install -e .[testing]
|
|
34
34
|
|
|
35
35
|
- name: Pytest (unit) • ${{ matrix.os }}, ${{ matrix.python-version }}
|
|
36
|
-
run: python -m pytest tests/unit
|
|
36
|
+
run: python -m pytest tests/unit
|
|
37
37
|
|
|
38
38
|
regression-quick:
|
|
39
39
|
name: Regression (quick)
|
|
@@ -62,7 +62,7 @@ jobs:
|
|
|
62
62
|
python -m pip install -e .[testing]
|
|
63
63
|
|
|
64
64
|
- name: Pytest (regression quick)
|
|
65
|
-
run: python -m pytest tests/regression
|
|
65
|
+
run: python -m pytest tests/regression
|
|
66
66
|
|
|
67
67
|
- name: Upload artifacts (failure)
|
|
68
68
|
if: failure()
|
|
@@ -163,30 +163,36 @@ jobs:
|
|
|
163
163
|
sed -i "s/^{% set version = \".*\" %}$/{% set version = \"${{ github.event.inputs.version }}\" %}/" conda-recipe/meta.yaml
|
|
164
164
|
grep '{% set version' conda-recipe/meta.yaml
|
|
165
165
|
|
|
166
|
-
- name: Setup Conda
|
|
166
|
+
- name: Setup Conda (conda-forge only)
|
|
167
167
|
uses: conda-incubator/setup-miniconda@v3
|
|
168
168
|
with:
|
|
169
169
|
miniforge-variant: Miniforge3
|
|
170
170
|
python-version: "3.12"
|
|
171
|
-
auto-activate
|
|
171
|
+
auto-activate: false
|
|
172
|
+
conda-remove-defaults: true
|
|
173
|
+
channels: conda-forge
|
|
174
|
+
channel-priority: strict
|
|
172
175
|
|
|
173
176
|
- name: Install build tools
|
|
174
177
|
shell: bash -l {0}
|
|
175
178
|
run: |
|
|
176
179
|
conda install -y conda-build anaconda-client
|
|
177
|
-
conda config --add channels conda-forge
|
|
178
|
-
conda config --set channel_priority strict
|
|
179
180
|
conda config --set anaconda_upload no
|
|
180
181
|
|
|
181
182
|
- name: Build package
|
|
182
183
|
shell: bash -l {0}
|
|
184
|
+
env:
|
|
185
|
+
PIP_NO_INDEX: "0"
|
|
183
186
|
run: |
|
|
187
|
+
PKG_PATH=$(conda build conda-recipe --output)
|
|
188
|
+
echo "PKG_PATH=$PKG_PATH" >> "$GITHUB_ENV"
|
|
184
189
|
conda build conda-recipe
|
|
190
|
+
test -f "$PKG_PATH"
|
|
191
|
+
echo "Built: $PKG_PATH"
|
|
185
192
|
|
|
186
193
|
- name: Upload to Anaconda
|
|
187
194
|
shell: bash -l {0}
|
|
188
195
|
env:
|
|
189
196
|
ANACONDA_API_TOKEN: ${{ secrets.ANACONDA_TOKEN }}
|
|
190
197
|
run: |
|
|
191
|
-
PKG_PATH=$(conda build conda-recipe --output)
|
|
192
198
|
anaconda -t "$ANACONDA_API_TOKEN" upload "$PKG_PATH" --user CCPBioSim --force
|
|
@@ -13,7 +13,6 @@ jobs:
|
|
|
13
13
|
regression:
|
|
14
14
|
name: Regression tests (including slow)
|
|
15
15
|
runs-on: ubuntu-24.04
|
|
16
|
-
timeout-minutes: 180
|
|
17
16
|
steps:
|
|
18
17
|
- name: Checkout repo
|
|
19
18
|
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6
|
|
@@ -36,7 +35,7 @@ jobs:
|
|
|
36
35
|
pip install -e .[testing]
|
|
37
36
|
|
|
38
37
|
- name: Run regression test suite
|
|
39
|
-
run: pytest tests/regression
|
|
38
|
+
run: pytest tests/regression --run-slow
|
|
40
39
|
|
|
41
40
|
- name: Upload regression artifacts on failure
|
|
42
41
|
if: failure()
|
|
@@ -25,7 +25,7 @@ import glob
|
|
|
25
25
|
import logging
|
|
26
26
|
import os
|
|
27
27
|
from dataclasses import dataclass
|
|
28
|
-
from typing import Any
|
|
28
|
+
from typing import Any
|
|
29
29
|
|
|
30
30
|
import yaml
|
|
31
31
|
|
|
@@ -48,11 +48,11 @@ class ArgSpec:
|
|
|
48
48
|
help: str
|
|
49
49
|
default: Any = None
|
|
50
50
|
type: Any = None
|
|
51
|
-
action:
|
|
52
|
-
nargs:
|
|
51
|
+
action: str | None = None
|
|
52
|
+
nargs: str | None = None
|
|
53
53
|
|
|
54
54
|
|
|
55
|
-
ARG_SPECS:
|
|
55
|
+
ARG_SPECS: dict[str, ArgSpec] = {
|
|
56
56
|
"top_traj_file": ArgSpec(
|
|
57
57
|
type=str,
|
|
58
58
|
nargs="+",
|
|
@@ -145,6 +145,12 @@ ARG_SPECS: Dict[str, ArgSpec] = {
|
|
|
145
145
|
default=True,
|
|
146
146
|
help="Use bonded axes to rotate forces for UA level vibrational entropies",
|
|
147
147
|
),
|
|
148
|
+
"search_type": ArgSpec(
|
|
149
|
+
type=str,
|
|
150
|
+
default="RAD",
|
|
151
|
+
help="Type of neighbor search to use."
|
|
152
|
+
"Default RAD; grid search is also available",
|
|
153
|
+
),
|
|
148
154
|
}
|
|
149
155
|
|
|
150
156
|
|
|
@@ -159,7 +165,7 @@ class ConfigResolver:
|
|
|
159
165
|
- validating trajectory-related numeric parameters
|
|
160
166
|
"""
|
|
161
167
|
|
|
162
|
-
def __init__(self, arg_specs:
|
|
168
|
+
def __init__(self, arg_specs: dict[str, ArgSpec] | None = None) -> None:
|
|
163
169
|
"""Initialize the manager.
|
|
164
170
|
|
|
165
171
|
Args:
|
|
@@ -168,7 +174,7 @@ class ConfigResolver:
|
|
|
168
174
|
"""
|
|
169
175
|
self._arg_specs = dict(arg_specs or ARG_SPECS)
|
|
170
176
|
|
|
171
|
-
def load_config(self, directory_path: str) ->
|
|
177
|
+
def load_config(self, directory_path: str) -> dict[str, Any]:
|
|
172
178
|
"""Load the first YAML config file found in a directory.
|
|
173
179
|
|
|
174
180
|
The current behavior matches your existing workflow:
|
|
@@ -188,7 +194,7 @@ class ConfigResolver:
|
|
|
188
194
|
|
|
189
195
|
config_path = yaml_files[0]
|
|
190
196
|
try:
|
|
191
|
-
with open(config_path,
|
|
197
|
+
with open(config_path, encoding="utf-8") as file:
|
|
192
198
|
config = yaml.safe_load(file) or {"run1": {}}
|
|
193
199
|
logger.info("Loaded configuration from: %s", config_path)
|
|
194
200
|
return config
|
|
@@ -253,7 +259,7 @@ class ConfigResolver:
|
|
|
253
259
|
)
|
|
254
260
|
continue
|
|
255
261
|
|
|
256
|
-
kwargs:
|
|
262
|
+
kwargs: dict[str, Any] = {}
|
|
257
263
|
if spec.type is not None:
|
|
258
264
|
kwargs["type"] = spec.type
|
|
259
265
|
if spec.default is not None:
|
|
@@ -266,7 +272,7 @@ class ConfigResolver:
|
|
|
266
272
|
return parser
|
|
267
273
|
|
|
268
274
|
def resolve(
|
|
269
|
-
self, args: argparse.Namespace, run_config:
|
|
275
|
+
self, args: argparse.Namespace, run_config: dict[str, Any] | None
|
|
270
276
|
) -> argparse.Namespace:
|
|
271
277
|
"""Merge CLI arguments with YAML configuration and adjust logging level.
|
|
272
278
|
|
|
@@ -306,8 +312,8 @@ class ConfigResolver:
|
|
|
306
312
|
|
|
307
313
|
@staticmethod
|
|
308
314
|
def _detect_cli_overrides(
|
|
309
|
-
args_dict:
|
|
310
|
-
) ->
|
|
315
|
+
args_dict: dict[str, Any], default_dict: dict[str, Any]
|
|
316
|
+
) -> set[str]:
|
|
311
317
|
"""Detect which args were explicitly overridden in the CLI.
|
|
312
318
|
|
|
313
319
|
Args:
|
|
@@ -322,8 +328,8 @@ class ConfigResolver:
|
|
|
322
328
|
def _apply_yaml_defaults(
|
|
323
329
|
self,
|
|
324
330
|
args: argparse.Namespace,
|
|
325
|
-
run_config:
|
|
326
|
-
cli_provided:
|
|
331
|
+
run_config: dict[str, Any],
|
|
332
|
+
cli_provided: set[str],
|
|
327
333
|
) -> None:
|
|
328
334
|
"""Apply YAML values onto args for keys not provided by CLI.
|
|
329
335
|
|
|
@@ -336,7 +342,7 @@ class ConfigResolver:
|
|
|
336
342
|
if yaml_value is None or key in cli_provided:
|
|
337
343
|
continue
|
|
338
344
|
if key in self._arg_specs:
|
|
339
|
-
logger.debug("Using YAML value for
|
|
345
|
+
logger.debug(f"Using YAML value for {key}: {yaml_value}")
|
|
340
346
|
setattr(args, key, yaml_value)
|
|
341
347
|
|
|
342
348
|
def _ensure_defaults(self, args: argparse.Namespace) -> None:
|
|
@@ -18,7 +18,7 @@ from __future__ import annotations
|
|
|
18
18
|
import logging
|
|
19
19
|
import os
|
|
20
20
|
import pickle
|
|
21
|
-
from typing import Any
|
|
21
|
+
from typing import Any
|
|
22
22
|
|
|
23
23
|
import MDAnalysis as mda
|
|
24
24
|
import requests
|
|
@@ -112,7 +112,7 @@ class CodeEntropyRunner:
|
|
|
112
112
|
|
|
113
113
|
return new_folder_path
|
|
114
114
|
|
|
115
|
-
def load_citation_data(self) ->
|
|
115
|
+
def load_citation_data(self) -> dict[str, Any] | None:
|
|
116
116
|
"""Load CITATION.cff from GitHub.
|
|
117
117
|
|
|
118
118
|
If the request fails (offline, blocked, etc.), returns None.
|
|
@@ -335,7 +335,7 @@ class CodeEntropyRunner:
|
|
|
335
335
|
kcal_units = args.kcal_force_units
|
|
336
336
|
|
|
337
337
|
if forcefile is None:
|
|
338
|
-
logger.debug("Loading Universe with
|
|
338
|
+
logger.debug(f"Loading Universe with {tprfile} and {trrfile}")
|
|
339
339
|
return mda.Universe(tprfile, trrfile, format=fileformat)
|
|
340
340
|
|
|
341
341
|
return universe_operations.merge_forces(
|
|
@@ -16,7 +16,6 @@ from __future__ import annotations
|
|
|
16
16
|
|
|
17
17
|
import logging
|
|
18
18
|
import os
|
|
19
|
-
from typing import Dict, Optional
|
|
20
19
|
|
|
21
20
|
from rich.console import Console
|
|
22
21
|
from rich.logging import RichHandler
|
|
@@ -55,7 +54,7 @@ class LoggingConfig:
|
|
|
55
54
|
handlers: Mapping of handler name to handler instance.
|
|
56
55
|
"""
|
|
57
56
|
|
|
58
|
-
_console:
|
|
57
|
+
_console: Console | None = None
|
|
59
58
|
|
|
60
59
|
@classmethod
|
|
61
60
|
def get_console(cls) -> Console:
|
|
@@ -80,7 +79,7 @@ class LoggingConfig:
|
|
|
80
79
|
|
|
81
80
|
self.level = level
|
|
82
81
|
self.console = self.get_console()
|
|
83
|
-
self.handlers:
|
|
82
|
+
self.handlers: dict[str, logging.Handler] = {}
|
|
84
83
|
|
|
85
84
|
self._setup_handlers()
|
|
86
85
|
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
"""Conformational entropy utilities.
|
|
2
|
+
|
|
3
|
+
This module provides:
|
|
4
|
+
|
|
5
|
+
- Assignment of discrete conformational states for a single dihedral time series.
|
|
6
|
+
- Computation of conformational entropy from a sequence of state labels.
|
|
7
|
+
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
import logging
|
|
13
|
+
from typing import Any
|
|
14
|
+
|
|
15
|
+
import numpy as np
|
|
16
|
+
|
|
17
|
+
logger = logging.getLogger(__name__)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class ConformationalEntropy:
|
|
21
|
+
"""Compute conformational entropy from states information."""
|
|
22
|
+
|
|
23
|
+
_GAS_CONST: float = 8.3144598484848
|
|
24
|
+
|
|
25
|
+
def __init__(self) -> None:
|
|
26
|
+
"""Math-only engine.
|
|
27
|
+
|
|
28
|
+
This class assigns conformational states and computes conformational entropy.
|
|
29
|
+
It does not depend on the workflow runner, universe, grouping, or reporting.
|
|
30
|
+
"""
|
|
31
|
+
pass
|
|
32
|
+
|
|
33
|
+
def conformational_entropy_calculation(self, states: Any) -> float:
|
|
34
|
+
"""Compute conformational entropy for a sequence of state labels.
|
|
35
|
+
|
|
36
|
+
Entropy is computed as:
|
|
37
|
+
|
|
38
|
+
S = -R * sum_i p_i * ln(p_i)
|
|
39
|
+
|
|
40
|
+
where p_i is the observed probability of state i in ``states``.
|
|
41
|
+
|
|
42
|
+
Args:
|
|
43
|
+
states: Sequence/array of discrete state labels. Empty/None yields 0.0.
|
|
44
|
+
number_frames: Frame count metadata.
|
|
45
|
+
|
|
46
|
+
Returns:
|
|
47
|
+
float: Conformational entropy in J/mol/K.
|
|
48
|
+
"""
|
|
49
|
+
arr = self._to_1d_array(states)
|
|
50
|
+
if arr is None or arr.size == 0:
|
|
51
|
+
return 0.0
|
|
52
|
+
|
|
53
|
+
values, counts = np.unique(arr, return_counts=True)
|
|
54
|
+
total_count = int(np.sum(counts))
|
|
55
|
+
if total_count <= 0 or values.size <= 1:
|
|
56
|
+
return 0.0
|
|
57
|
+
|
|
58
|
+
probs = counts.astype(float) / float(total_count)
|
|
59
|
+
probs = probs[probs > 0.0]
|
|
60
|
+
|
|
61
|
+
s_conf = -self._GAS_CONST * float(np.sum(probs * np.log(probs)))
|
|
62
|
+
logger.debug(f"Total conformational entropy: {s_conf}")
|
|
63
|
+
return s_conf
|
|
64
|
+
|
|
65
|
+
@staticmethod
|
|
66
|
+
def _to_1d_array(states: Any) -> np.ndarray | None:
|
|
67
|
+
"""Convert a state sequence into a 1D numpy array.
|
|
68
|
+
|
|
69
|
+
Args:
|
|
70
|
+
states: Input sequence/array.
|
|
71
|
+
|
|
72
|
+
Returns:
|
|
73
|
+
1D numpy array, or None if input is not usable.
|
|
74
|
+
"""
|
|
75
|
+
if states is None:
|
|
76
|
+
return None
|
|
77
|
+
|
|
78
|
+
if isinstance(states, np.ndarray):
|
|
79
|
+
arr = states.reshape(-1)
|
|
80
|
+
else:
|
|
81
|
+
try:
|
|
82
|
+
arr = np.asarray(list(states)).reshape(-1)
|
|
83
|
+
except TypeError:
|
|
84
|
+
return None
|
|
85
|
+
|
|
86
|
+
return arr
|
|
@@ -15,18 +15,19 @@ from __future__ import annotations
|
|
|
15
15
|
|
|
16
16
|
import logging
|
|
17
17
|
from dataclasses import dataclass
|
|
18
|
-
from typing import Any
|
|
18
|
+
from typing import Any
|
|
19
19
|
|
|
20
20
|
import networkx as nx
|
|
21
21
|
|
|
22
22
|
from CodeEntropy.entropy.nodes.aggregate import AggregateEntropyNode
|
|
23
23
|
from CodeEntropy.entropy.nodes.configurational import ConfigurationalEntropyNode
|
|
24
|
+
from CodeEntropy.entropy.nodes.orientational import OrientationalEntropyNode
|
|
24
25
|
from CodeEntropy.entropy.nodes.vibrational import VibrationalEntropyNode
|
|
25
26
|
|
|
26
27
|
logger = logging.getLogger(__name__)
|
|
27
28
|
|
|
28
29
|
|
|
29
|
-
SharedData =
|
|
30
|
+
SharedData = dict[str, Any]
|
|
30
31
|
|
|
31
32
|
|
|
32
33
|
@dataclass(frozen=True)
|
|
@@ -57,9 +58,9 @@ class EntropyGraph:
|
|
|
57
58
|
def __init__(self) -> None:
|
|
58
59
|
"""Initialize an empty entropy graph."""
|
|
59
60
|
self._graph: nx.DiGraph = nx.DiGraph()
|
|
60
|
-
self._nodes:
|
|
61
|
+
self._nodes: dict[str, Any] = {}
|
|
61
62
|
|
|
62
|
-
def build(self) ->
|
|
63
|
+
def build(self) -> EntropyGraph:
|
|
63
64
|
"""Populate the graph with the standard entropy workflow.
|
|
64
65
|
|
|
65
66
|
Returns:
|
|
@@ -68,10 +69,15 @@ class EntropyGraph:
|
|
|
68
69
|
specs = (
|
|
69
70
|
NodeSpec("vibrational_entropy", VibrationalEntropyNode()),
|
|
70
71
|
NodeSpec("configurational_entropy", ConfigurationalEntropyNode()),
|
|
72
|
+
NodeSpec("orientational_entropy", OrientationalEntropyNode()),
|
|
71
73
|
NodeSpec(
|
|
72
74
|
"aggregate_entropy",
|
|
73
75
|
AggregateEntropyNode(),
|
|
74
|
-
deps=(
|
|
76
|
+
deps=(
|
|
77
|
+
"vibrational_entropy",
|
|
78
|
+
"configurational_entropy",
|
|
79
|
+
"orientational_entropy",
|
|
80
|
+
),
|
|
75
81
|
),
|
|
76
82
|
)
|
|
77
83
|
|
|
@@ -82,7 +88,7 @@ class EntropyGraph:
|
|
|
82
88
|
|
|
83
89
|
def execute(
|
|
84
90
|
self, shared_data: SharedData, *, progress: object | None = None
|
|
85
|
-
) ->
|
|
91
|
+
) -> dict[str, Any]:
|
|
86
92
|
"""Execute the entropy graph in topological order.
|
|
87
93
|
|
|
88
94
|
Nodes are executed in dependency order (topological sort). Each node reads
|
|
@@ -105,7 +111,7 @@ class EntropyGraph:
|
|
|
105
111
|
Raises:
|
|
106
112
|
KeyError: If a node name is missing from the internal node registry.
|
|
107
113
|
"""
|
|
108
|
-
results:
|
|
114
|
+
results: dict[str, Any] = {}
|
|
109
115
|
|
|
110
116
|
for node_name in nx.topological_sort(self._graph):
|
|
111
117
|
node = self._nodes[node_name]
|
|
@@ -2,10 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
+
from collections.abc import Mapping, MutableMapping
|
|
5
6
|
from dataclasses import dataclass
|
|
6
|
-
from typing import Any
|
|
7
|
+
from typing import Any
|
|
7
8
|
|
|
8
|
-
EntropyResults =
|
|
9
|
+
EntropyResults = dict[str, Any]
|
|
9
10
|
|
|
10
11
|
|
|
11
12
|
@dataclass(frozen=True, slots=True)
|
|
@@ -25,11 +26,12 @@ class AggregateEntropyNode:
|
|
|
25
26
|
|
|
26
27
|
vibrational_key: str = "vibrational_entropy"
|
|
27
28
|
configurational_key: str = "configurational_entropy"
|
|
29
|
+
orientational_key: str = "orientational_entropy"
|
|
28
30
|
output_key: str = "entropy_results"
|
|
29
31
|
|
|
30
32
|
def run(
|
|
31
33
|
self, shared_data: MutableMapping[str, Any], **_: Any
|
|
32
|
-
) ->
|
|
34
|
+
) -> dict[str, EntropyResults]:
|
|
33
35
|
"""Run the aggregation step.
|
|
34
36
|
|
|
35
37
|
Args:
|
|
@@ -69,10 +71,13 @@ class AggregateEntropyNode:
|
|
|
69
71
|
"configurational_entropy": self._get_optional(
|
|
70
72
|
shared_data, self.configurational_key
|
|
71
73
|
),
|
|
74
|
+
"orientational_entropy": self._get_optional(
|
|
75
|
+
shared_data, self.orientational_key
|
|
76
|
+
),
|
|
72
77
|
}
|
|
73
78
|
|
|
74
79
|
@staticmethod
|
|
75
|
-
def _get_optional(shared_data: Mapping[str, Any], key: str) ->
|
|
80
|
+
def _get_optional(shared_data: Mapping[str, Any], key: str) -> Any | None:
|
|
76
81
|
"""Fetch an optional value from shared data.
|
|
77
82
|
|
|
78
83
|
Args:
|
|
@@ -3,16 +3,9 @@
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
5
|
import logging
|
|
6
|
+
from collections.abc import Iterable, Mapping, MutableMapping, Sequence
|
|
6
7
|
from typing import (
|
|
7
8
|
Any,
|
|
8
|
-
Dict,
|
|
9
|
-
Iterable,
|
|
10
|
-
Mapping,
|
|
11
|
-
MutableMapping,
|
|
12
|
-
Optional,
|
|
13
|
-
Sequence,
|
|
14
|
-
Tuple,
|
|
15
|
-
Union,
|
|
16
9
|
)
|
|
17
10
|
|
|
18
11
|
import numpy as np
|
|
@@ -23,8 +16,8 @@ logger = logging.getLogger(__name__)
|
|
|
23
16
|
|
|
24
17
|
GroupId = int
|
|
25
18
|
ResidueId = int
|
|
26
|
-
StateKey =
|
|
27
|
-
StateSequence =
|
|
19
|
+
StateKey = tuple[GroupId, ResidueId]
|
|
20
|
+
StateSequence = Sequence[Any] | np.ndarray
|
|
28
21
|
|
|
29
22
|
|
|
30
23
|
class ConfigurationalEntropyNode:
|
|
@@ -36,7 +29,7 @@ class ConfigurationalEntropyNode:
|
|
|
36
29
|
Results are written back into ``shared_data["configurational_entropy"]``.
|
|
37
30
|
"""
|
|
38
31
|
|
|
39
|
-
def run(self, shared_data: MutableMapping[str, Any], **_: Any) ->
|
|
32
|
+
def run(self, shared_data: MutableMapping[str, Any], **_: Any) -> dict[str, Any]:
|
|
40
33
|
"""Execute configurational entropy calculation.
|
|
41
34
|
|
|
42
35
|
Args:
|
|
@@ -58,7 +51,7 @@ class ConfigurationalEntropyNode:
|
|
|
58
51
|
ce = self._build_entropy_engine()
|
|
59
52
|
|
|
60
53
|
fragments = universe.atoms.fragments
|
|
61
|
-
results:
|
|
54
|
+
results: dict[int, dict[str, float]] = {}
|
|
62
55
|
|
|
63
56
|
for group_id, mol_ids in groups.items():
|
|
64
57
|
results[group_id] = {"ua": 0.0, "res": 0.0, "poly": 0.0}
|
|
@@ -104,9 +97,9 @@ class ConfigurationalEntropyNode:
|
|
|
104
97
|
|
|
105
98
|
def _get_state_containers(
|
|
106
99
|
self, shared_data: Mapping[str, Any]
|
|
107
|
-
) ->
|
|
108
|
-
|
|
109
|
-
|
|
100
|
+
) -> tuple[
|
|
101
|
+
dict[StateKey, StateSequence],
|
|
102
|
+
dict[GroupId, StateSequence] | Sequence[StateSequence | None],
|
|
110
103
|
]:
|
|
111
104
|
"""Retrieve conformational state containers.
|
|
112
105
|
|
|
@@ -144,7 +137,7 @@ class ConfigurationalEntropyNode:
|
|
|
144
137
|
residues: Iterable[Any],
|
|
145
138
|
states_ua: Mapping[StateKey, StateSequence],
|
|
146
139
|
n_frames: int,
|
|
147
|
-
reporter:
|
|
140
|
+
reporter: Any | None,
|
|
148
141
|
) -> float:
|
|
149
142
|
"""Compute united atom entropy for a group.
|
|
150
143
|
|
|
@@ -163,7 +156,7 @@ class ConfigurationalEntropyNode:
|
|
|
163
156
|
|
|
164
157
|
for res_id, res in enumerate(residues):
|
|
165
158
|
states = states_ua.get((group_id, res_id))
|
|
166
|
-
val = self._entropy_or_zero(ce, states
|
|
159
|
+
val = self._entropy_or_zero(ce, states)
|
|
167
160
|
total += val
|
|
168
161
|
|
|
169
162
|
if reporter is not None:
|
|
@@ -186,29 +179,28 @@ class ConfigurationalEntropyNode:
|
|
|
186
179
|
*,
|
|
187
180
|
ce: ConformationalEntropy,
|
|
188
181
|
group_id: int,
|
|
189
|
-
states_res:
|
|
182
|
+
states_res: dict[int, StateSequence] | Sequence[StateSequence | None],
|
|
190
183
|
n_frames: int,
|
|
191
184
|
) -> float:
|
|
192
185
|
"""Compute residue-level entropy for a group."""
|
|
193
186
|
group_states = self._get_group_states(states_res, group_id)
|
|
194
|
-
return self._entropy_or_zero(ce, group_states
|
|
187
|
+
return self._entropy_or_zero(ce, group_states)
|
|
195
188
|
|
|
196
189
|
def _entropy_or_zero(
|
|
197
190
|
self,
|
|
198
191
|
ce: ConformationalEntropy,
|
|
199
|
-
states:
|
|
200
|
-
n_frames: int,
|
|
192
|
+
states: StateSequence | None,
|
|
201
193
|
) -> float:
|
|
202
194
|
"""Return entropy value or zero if no state data exists."""
|
|
203
195
|
if not self._has_state_data(states):
|
|
204
196
|
return 0.0
|
|
205
|
-
return float(ce.conformational_entropy_calculation(states
|
|
197
|
+
return float(ce.conformational_entropy_calculation(states))
|
|
206
198
|
|
|
207
199
|
@staticmethod
|
|
208
200
|
def _get_group_states(
|
|
209
|
-
states_res:
|
|
201
|
+
states_res: dict[int, StateSequence] | Sequence[StateSequence | None],
|
|
210
202
|
group_id: int,
|
|
211
|
-
) ->
|
|
203
|
+
) -> StateSequence | None:
|
|
212
204
|
"""Fetch group states from container."""
|
|
213
205
|
if isinstance(states_res, dict):
|
|
214
206
|
return states_res.get(group_id)
|
|
@@ -217,7 +209,7 @@ class ConfigurationalEntropyNode:
|
|
|
217
209
|
return None
|
|
218
210
|
|
|
219
211
|
@staticmethod
|
|
220
|
-
def _has_state_data(states:
|
|
212
|
+
def _has_state_data(states: StateSequence | None) -> bool:
|
|
221
213
|
"""Check if state container has usable data."""
|
|
222
214
|
if states is None:
|
|
223
215
|
return False
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"""Node for computing orientational entropy from neighbors."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import logging
|
|
6
|
+
from collections.abc import MutableMapping, Sequence
|
|
7
|
+
from typing import (
|
|
8
|
+
Any,
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
import numpy as np
|
|
12
|
+
|
|
13
|
+
from CodeEntropy.entropy.orientational import OrientationalEntropy
|
|
14
|
+
|
|
15
|
+
logger = logging.getLogger(__name__)
|
|
16
|
+
|
|
17
|
+
GroupId = int
|
|
18
|
+
ResidueId = int
|
|
19
|
+
StateKey = tuple[GroupId, ResidueId]
|
|
20
|
+
StateSequence = Sequence[Any] | np.ndarray
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class OrientationalEntropyNode:
|
|
24
|
+
"""Compute orientational entropy using precomputed neighbors and symmetry.
|
|
25
|
+
|
|
26
|
+
This node reads number of neighbors and symmetry from ``shared_data`` and
|
|
27
|
+
computes entropy contributions at the molecular (highest) level.
|
|
28
|
+
|
|
29
|
+
Results are written back into ``shared_data["orientational_entropy"]``.
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
def run(self, shared_data: MutableMapping[str, Any], **_: Any) -> dict[str, Any]:
|
|
33
|
+
"""Execute orientational entropy calculation.
|
|
34
|
+
|
|
35
|
+
Args:
|
|
36
|
+
shared_data: Shared workflow state dictionary.
|
|
37
|
+
|
|
38
|
+
Returns:
|
|
39
|
+
Dictionary containing orientational entropy results.
|
|
40
|
+
|
|
41
|
+
Raises:
|
|
42
|
+
KeyError: If required keys are missing.
|
|
43
|
+
"""
|
|
44
|
+
groups = shared_data["groups"]
|
|
45
|
+
levels = shared_data["levels"]
|
|
46
|
+
neighbors = shared_data["neighbors"]
|
|
47
|
+
symmetry_number = shared_data["symmetry_number"]
|
|
48
|
+
linear = shared_data["linear"]
|
|
49
|
+
reporter = shared_data.get("reporter")
|
|
50
|
+
|
|
51
|
+
oe = self._build_entropy_engine()
|
|
52
|
+
|
|
53
|
+
results: dict[int, float] = {}
|
|
54
|
+
|
|
55
|
+
for group_id, mol_ids in groups.items():
|
|
56
|
+
results[group_id] = 0
|
|
57
|
+
if not mol_ids:
|
|
58
|
+
continue
|
|
59
|
+
rep_mol_id = mol_ids[0]
|
|
60
|
+
highest_level = levels[rep_mol_id][-1]
|
|
61
|
+
|
|
62
|
+
neighbor = neighbors[group_id]
|
|
63
|
+
symmetry = symmetry_number[group_id]
|
|
64
|
+
line = linear[group_id]
|
|
65
|
+
|
|
66
|
+
result_value = oe.calculate(
|
|
67
|
+
neighbor,
|
|
68
|
+
symmetry,
|
|
69
|
+
line,
|
|
70
|
+
)
|
|
71
|
+
results[group_id] = result_value
|
|
72
|
+
|
|
73
|
+
if reporter is not None:
|
|
74
|
+
reporter.add_results_data(
|
|
75
|
+
group_id, highest_level, "Orientational", result_value
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
shared_data["orientational_entropy"] = results
|
|
79
|
+
|
|
80
|
+
return {"orientational_entropy": results}
|
|
81
|
+
|
|
82
|
+
def _build_entropy_engine(self) -> OrientationalEntropy:
|
|
83
|
+
"""Create the entropy calculation engine."""
|
|
84
|
+
return OrientationalEntropy()
|