Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
15 commits
Select commit Hold shift + click to select a range
3426f4f
include Python `v3.14` within `project-ci.yaml` and `release.yaml`
harryswift01 Oct 15, 2025
cdcae41
add Python `v3.14` version to `pyproject.toml` for GitHub badge update
harryswift01 Oct 15, 2025
48313f7
update `MDAnalysis` version to `2.10.0` to support Python `3.14`
harryswift01 Oct 27, 2025
1e3dc8b
update testing dependencies within `pyproject.toml`
harryswift01 Nov 3, 2025
328e159
update pre-commit dependencies within `pyproject.toml`
harryswift01 Nov 3, 2025
5a631ea
update required dependencies within `pyproject.toml`
harryswift01 Nov 3, 2025
7d910e1
fix `test_log_tables_rich_output` test in relation to the updated `ri…
harryswift01 Nov 3, 2025
162d315
add a new test case `test_assign_conformation_last_bin_peak` to ensur…
harryswift01 Nov 3, 2025
063daa2
add a new test case `test_update_force_torque_matrices_united_atom_in…
harryswift01 Nov 3, 2025
864876e
add `# pragma: no cover` to `main.py` since upgrades to `pytest`
harryswift01 Nov 5, 2025
5bb03fd
Merge branch 'main' of https://github.com/CCPBioSim/CodeEntropy into …
harryswift01 Nov 5, 2025
994667b
update `numpy` dependency within `pyproject.toml` to `v2.3.0`
harryswift01 Nov 5, 2025
76d8048
update `waterEntropy` dependency to `v1.2.1` within `pyproject.toml`
harryswift01 Nov 6, 2025
a05f9b7
Merge branch 'main' of https://github.com/CCPBioSim/CodeEntropy into …
harryswift01 Nov 10, 2025
f6631a2
update `numpy` and `waterEntropy` dependencies within `pyproject.toml…
harryswift01 Nov 10, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions .github/workflows/project-ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:
strategy:
matrix:
os: [ubuntu-24.04, windows-2025, macos-15]
python-version: ["3.11", "3.12", "3.13"]
python-version: ["3.11", "3.12", "3.13", "3.14"]
steps:
- name: Checkout repo
uses: actions/checkout@v5.0.0
Expand All @@ -40,10 +40,10 @@ jobs:
timeout-minutes: 15
steps:
- uses: actions/checkout@v5.0.0
- name: Set up Python 3.13
- name: Set up Python 3.14
uses: actions/setup-python@v6.0.0
with:
python-version: 3.13
python-version: 3.14
- name: Install python dependencies
run: |
pip install --upgrade pip
Expand All @@ -56,10 +56,10 @@ jobs:
timeout-minutes: 15
steps:
- uses: actions/checkout@v5.0.0
- name: Set up Python 3.13
- name: Set up Python 3.14
uses: actions/setup-python@v6.0.0
with:
python-version: 3.13
python-version: 3.14
- name: Install python dependencies
run: |
pip install --upgrade pip
Expand All @@ -75,7 +75,7 @@ jobs:
timeout-minutes: 15
strategy:
matrix:
python-version: ["3.11", "3.12", "3.13"]
python-version: ["3.11", "3.12", "3.13", "3.14"]
mdanalysis-version: ["2.9.0", "latest"]
name: MDAnalysis Compatibility Tests
steps:
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ jobs:
- name: Set up Python
uses: actions/setup-python@v6.0.0
with:
python-version: 3.13
python-version: 3.14

- name: Get latest release from pip
id: latestreleased
Expand Down Expand Up @@ -133,7 +133,7 @@ jobs:
- name: Set up Python
uses: actions/setup-python@v6.0.0
with:
python-version: 3.13
python-version: 3.14

- name: Install flit
run: |
Expand Down
2 changes: 1 addition & 1 deletion CodeEntropy/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,4 @@ def main():

if __name__ == "__main__":

main()
main() # pragma: no cover
27 changes: 14 additions & 13 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ classifiers = [
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Programming Language :: Python :: 3.14",
"Intended Audience :: Science/Research",
"License :: OSI Approved :: MIT License",
"Natural Language :: English",
Expand All @@ -37,15 +38,15 @@ classifiers = [
keywords = ["entropy", "macromolecular systems", "MD simulation"]
requires-python = ">=3.11"
dependencies = [
"numpy==2.2.3",
"mdanalysis>=2.9.0",
"pandas==2.2.3",
"psutil==5.9.5",
"PyYAML==6.0.2",
"python-json-logger==3.3.0",
"rich==14.0.0",
"numpy==2.3.4",
"mdanalysis>=2.10.0",
"pandas==2.3.3",
"psutil==7.1.3",
"PyYAML==6.0.3",
"python-json-logger==4.0.0",
"rich==14.2.0",
"art==6.5",
"waterEntropy==1.2.0",
"waterEntropy==1.2.2",
"requests>=2.32.5",
]

Expand All @@ -56,14 +57,14 @@ Documentation = "https://codeentropy.readthedocs.io"

[project.optional-dependencies]
testing = [
"pytest==8.2.2",
"pytest-cov==5.0.0",
"pytest-sugar==1.0.0"
"pytest>=8.4.2",
"pytest-cov>=7.0.0",
"pytest-sugar>=1.1.1"
]

pre-commit = [
"pre-commit==3.7.1",
"pylint==3.2.5"
"pre-commit>=4.3.0",
"pylint>=4.0.0"
]
docs = [
"sphinx",
Expand Down
1 change: 0 additions & 1 deletion tests/test_CodeEntropy/test_data_logger.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,6 @@ def test_save_dataframes_as_json(self):

def test_log_tables_rich_output(self):
console = LoggingConfig.get_console()
console.clear_live()

self.logger.add_results_data(
0, "united_atom", "Transvibrational", 653.4041220313459
Expand Down
45 changes: 45 additions & 0 deletions tests/test_CodeEntropy/test_entropy.py
Original file line number Diff line number Diff line change
Expand Up @@ -1657,6 +1657,51 @@ def test_assign_conformation(self):
assert np.all(result >= 0)
assert np.issubdtype(result.dtype, np.floating)

def test_assign_conformation_last_bin_peak(self):
"""
Test that the last bin in the histogram is correctly evaluated as a peak
when its population is greater than or equal to its neighbors.
"""

dihedral = MagicMock()
dihedral.value = MagicMock(side_effect=[5, 10, 250, 260, 350, 355])

# Mock trajectory frames
mock_timesteps = [MagicMock(frame=i) for i in range(6)]
data_container = MagicMock()
data_container.trajectory.__getitem__.return_value = mock_timesteps

# Create dummy universe and managers
tprfile = os.path.join(self.test_data_dir, "md_A4_dna.tpr")
trrfile = os.path.join(self.test_data_dir, "md_A4_dna_xf.trr")
u = mda.Universe(tprfile, trrfile)

args = MagicMock(bin_width=60, temperature=300, selection_string="all")
run_manager = RunManager("mock_folder/job001")
level_manager = LevelManager()
data_logger = DataLogger()
group_molecules = MagicMock()

ce = ConformationalEntropy(
run_manager, args, u, data_logger, level_manager, group_molecules
)

result = ce.assign_conformation(
data_container=data_container,
dihedral=dihedral,
number_frames=6,
bin_width=60,
start=0,
end=6,
step=1,
)

# Basic checks
assert isinstance(result, np.ndarray)
assert len(result) == 6
assert np.all(result >= 0)
assert np.issubdtype(result.dtype, np.floating)

def test_conformational_entropy_calculation(self):
"""
Test `conformational_entropy_calculation` method to verify
Expand Down
67 changes: 67 additions & 0 deletions tests/test_CodeEntropy/test_levels.py
Original file line number Diff line number Diff line change
Expand Up @@ -1065,6 +1065,73 @@ def test_update_force_torque_matrices_united_atom(self):
np.testing.assert_array_equal(torque_avg["ua"][key], t_mat_mock)
self.assertEqual(frame_counts["ua"][key], 1)

def test_update_force_torque_matrices_united_atom_increment(self):
"""
Test that `update_force_torque_matrices` correctly updates force and torque
matrices for the 'united_atom' level when the key already exists.
"""
level_manager = LevelManager()
entropy_manager = MagicMock()
mol = MagicMock()

# Simulate one residue with two atoms
residue = MagicMock()
residue.atoms.indices = [0, 1]
mol.residues = [residue]
mol.trajectory.__getitem__.return_value = None

selected_atoms = MagicMock()
entropy_manager._run_manager.new_U_select_atom.return_value = selected_atoms
selected_atoms.trajectory.__getitem__.return_value = None

f_mat_1 = np.array([[1.0]], dtype=np.float64)
t_mat_1 = np.array([[2.0]], dtype=np.float64)
f_mat_2 = np.array([[3.0]], dtype=np.float64)
t_mat_2 = np.array([[4.0]], dtype=np.float64)

level_manager.get_matrices = MagicMock(return_value=(f_mat_1, t_mat_1))

force_avg = {"ua": {}, "res": [None], "poly": [None]}
torque_avg = {"ua": {}, "res": [None], "poly": [None]}
frame_counts = {"ua": {}, "res": [None], "poly": [None]}

# First call: initialize
level_manager.update_force_torque_matrices(
entropy_manager=entropy_manager,
mol=mol,
group_id=0,
level="united_atom",
level_list=["residue", "united_atom"],
time_index=0,
num_frames=10,
force_avg=force_avg,
torque_avg=torque_avg,
frame_counts=frame_counts,
)

# Second call: update
level_manager.get_matrices = MagicMock(return_value=(f_mat_2, t_mat_2))

level_manager.update_force_torque_matrices(
entropy_manager=entropy_manager,
mol=mol,
group_id=0,
level="united_atom",
level_list=["residue", "united_atom"],
time_index=1,
num_frames=10,
force_avg=force_avg,
torque_avg=torque_avg,
frame_counts=frame_counts,
)

expected_force = f_mat_1 + (f_mat_2 - f_mat_1) / 2
expected_torque = t_mat_1 + (t_mat_2 - t_mat_1) / 2

np.testing.assert_array_almost_equal(force_avg["ua"][(0, 0)], expected_force)
np.testing.assert_array_almost_equal(torque_avg["ua"][(0, 0)], expected_torque)
self.assertEqual(frame_counts["ua"][(0, 0)], 2)

def test_update_force_torque_matrices_residue(self):
"""
Test that `update_force_torque_matrices` correctly updates force and torque
Expand Down