Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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.0",
"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.1",
"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
Loading