Skip to content

Commit c71cb40

Browse files
committed
Merge remote-tracking branch 'origin/main' into 313-bug-regression-tests-fail
2 parents 1334ca8 + 7196a55 commit c71cb40

11 files changed

Lines changed: 252 additions & 15 deletions

File tree

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
name: Update Regression Baselines
2+
3+
on:
4+
workflow_dispatch:
5+
6+
concurrency:
7+
group: update-regression-baselines-${{ github.ref }}
8+
cancel-in-progress: true
9+
10+
permissions:
11+
contents: write
12+
13+
jobs:
14+
update-baselines:
15+
name: Update regression baselines
16+
runs-on: ubuntu-24.04
17+
timeout-minutes: 30
18+
19+
steps:
20+
- name: Checkout
21+
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6
22+
with:
23+
ref: ${{ github.ref }}
24+
25+
- name: Set up Python
26+
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
27+
with:
28+
python-version: "3.14"
29+
cache: pip
30+
31+
- name: Install testing dependencies
32+
run: |
33+
python -m pip install --upgrade pip
34+
python -m pip install -e .[testing]
35+
36+
- name: Update regression baselines
37+
run: pytest tests/regression --update-baselines
38+
39+
- name: Commit updated baselines
40+
uses: stefanzweifel/git-auto-commit-action@778341af668090896ca464160c2def5d1d1a3eb0 # v6
41+
with:
42+
commit_message: "test(regression): update baselines"
43+
commit_user_name: github-actions[bot]
44+
commit_user_email: 41898282+github-actions[bot]@users.noreply.github.com

CITATION.cff

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,5 +76,5 @@ keywords:
7676
- biomolecular simulations
7777
- protein flexibility
7878
license: MIT
79-
version: 2.1.1
80-
date-released: '2026-04-01'
79+
version: 2.2.2
80+
date-released: '2026-05-01'

CodeEntropy/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,4 @@
88
and statistical mechanics.
99
"""
1010

11-
__version__ = "2.1.1"
11+
__version__ = "2.2.2"

CodeEntropy/config/runtime.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -335,8 +335,14 @@ def _build_universe(
335335
kcal_units = args.kcal_force_units
336336

337337
if forcefile is None:
338-
logger.debug(f"Loading Universe with {tprfile} and {trrfile}")
339-
return mda.Universe(tprfile, trrfile, format=fileformat)
338+
if fileformat == "LAMMPSDUMP":
339+
logger.debug(
340+
f"Loading Universe with {tprfile} and {trrfile} (LAMMPSDUMP)"
341+
)
342+
return universe_operations.convert_lammps(tprfile, trrfile, fileformat)
343+
else:
344+
logger.debug(f"Loading Universe with {tprfile} and {trrfile}")
345+
return mda.Universe(tprfile, trrfile, format=fileformat)
340346

341347
return universe_operations.merge_forces(
342348
tprfile, trrfile, forcefile, fileformat, kcal_units

CodeEntropy/entropy/nodes/vibrational.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -323,7 +323,7 @@ def _compute_force_torque_entropy(
323323
EntropyPair containing translational entropy (from force covariance) and
324324
rotational entropy (from torque covariance).
325325
"""
326-
if fmat is None or tmat is None:
326+
if fmat is None and tmat is None:
327327
return EntropyPair(trans=0.0, rot=0.0)
328328

329329
f = self._mat_ops.filter_zero_rows_columns(
@@ -333,7 +333,7 @@ def _compute_force_torque_entropy(
333333
np.asarray(tmat), atol=self._zero_atol
334334
)
335335

336-
if f.size == 0 or t.size == 0:
336+
if f.size == 0 and t.size == 0:
337337
return EntropyPair(trans=0.0, rot=0.0)
338338

339339
s_trans = ve.vibrational_entropy_calculation(

CodeEntropy/levels/mda.py

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,97 @@ def extract_fragment(
121121
selection_string = f"index {frag.indices[0]}:{frag.indices[-1]}"
122122
return self.select_atoms(universe, selection_string)
123123

124+
def convert_lammps(
125+
self,
126+
tprfile: str,
127+
trrfile,
128+
fileformat: str | None = None,
129+
) -> mda.Universe:
130+
"""Update the units produced from the universe produced from LAMMPS
131+
format topology and trajectory files. MDA currently has a bug that
132+
results in forces not being converted to the correct units
133+
(see issue for more details:
134+
https://github.com/MDAnalysis/mdanalysis/issues/5115
135+
)
136+
The method currently expects the following additional columns in the
137+
lammps dump file: fx fy fz c_5 c_7
138+
where c_5 and c_7 are the atom potential and kinetic energies respectively.
139+
140+
This method loads:
141+
142+
- Coordinates and dimensions from the coordinate trajectory
143+
(``tprfile`` + ``trrfile``).
144+
145+
Args:
146+
tprfile: Topology input file.
147+
trrfile: Coordinate trajectory file(s). This can be a single path or a
148+
list, as accepted by MDAnalysis.
149+
fileformat: Optional file format for the coordinate trajectory, as
150+
recognised by MDAnalysis.
151+
152+
Returns:
153+
MDAnalysis.Universe: A new Universe containing coordinates, forces and
154+
dimensions loaded into memory.
155+
156+
Raises:
157+
ValueError: If fileformat is not one of the supported values.
158+
"""
159+
160+
def _convert_lammps_forces_energies(ts):
161+
"""
162+
Convert lammps forces from kcal/mol/Ang to kJ/mol/Ang.
163+
Assumes columns for per-atom potential (c_5) and kinetic energies (c_7)
164+
are provided and converts these too.
165+
166+
Args:
167+
ts: MDAnalysis timeseries from the trajectory.
168+
169+
Returns:
170+
A converted time series.
171+
"""
172+
ts.forces *= 4.184
173+
ts.data["c_5"] *= 4.184
174+
ts.data["c_7"] *= 4.184
175+
return ts
176+
177+
def _convert_lammps_forces(ts):
178+
"""
179+
Convert lammps forces from kcal/mol/Ang to kJ/mol/Ang.
180+
181+
Args:
182+
ts: MDAnalysis timeseries from the trajectory.
183+
184+
Returns:
185+
A converted time series.
186+
"""
187+
ts.forces *= 4.184
188+
return ts
189+
190+
if fileformat == "LAMMPSDUMP":
191+
try:
192+
return mda.Universe(
193+
tprfile,
194+
trrfile,
195+
format=fileformat,
196+
additional_columns=["fx", "fy", "fz", "c_5", "c_7"],
197+
transformations=[_convert_lammps_forces_energies],
198+
)
199+
except KeyError:
200+
logger.debug(
201+
f"Warning: Energy columns not found in LAMMPSDUMP: {trrfile}"
202+
)
203+
return mda.Universe(
204+
tprfile,
205+
trrfile,
206+
format=fileformat,
207+
additional_columns=["fx", "fy", "fz"],
208+
transformations=[_convert_lammps_forces],
209+
)
210+
else:
211+
raise ValueError(
212+
f"Incorrect file format: {fileformat}, LAMMPSDUMP expected"
213+
)
214+
124215
def merge_forces(
125216
self,
126217
tprfile: str,

CodeEntropy/levels/neighbors.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,11 @@ def _get_rdkit_mol(self, universe, mol_id):
167167
rdkit_mol = frag.convert_to("RDKIT", force=True, inferrer=None)
168168
logger.debug("Warning: Dummy atoms found")
169169
else:
170-
rdkit_mol = molecule.convert_to("RDKIT", force=True)
170+
try:
171+
rdkit_mol = molecule.convert_to("RDKIT", force=True)
172+
except Exception:
173+
logger.debug("Warning: Constraint bonds to H atoms found")
174+
rdkit_mol = molecule.convert_to("RDKIT", force=True, inferrer=None)
171175

172176
number_heavy = rdkit_mol.GetNumHeavyAtoms()
173177
number_hydrogen = rdkit_mol.GetNumAtoms() - number_heavy

conda-recipe/meta.yaml

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ requirements:
3939
- distributed >=2026.1.2,<2026.2.0
4040
- dask-jobqueue >=0.9,<0.10
4141
- pytest-xdist >=3.8, <3.9
42-
- numba >=0.65.0, <0.7
42+
- numba >=0.65.1, <0.70
4343

4444
test:
4545
imports:
@@ -48,7 +48,13 @@ test:
4848
- CodeEntropy --help
4949

5050
about:
51-
home: https://ccpbiosim.github.io/CodeEntropy/
51+
home: https://github.com/CCPBioSim/CodeEntropy
5252
license: MIT
53+
license_family: MIT
5354
license_file: LICENSE
54-
summary: "Entropy analysis tools for macromolecular systems and MD simulation"
55+
license_url: https://github.com/CCPBioSim/CodeEntropy/blob/main/LICENSE
56+
summary: Python package for calculating configurational entropy from molecular dynamics simulations using the multiscale cell correlation method.
57+
description: "CodeEntropy is a Python package for computing the configurational entropy of macromolecular systems using forces sampled from molecular dynamics (MD) simulations. It implements the multiscale cell correlation method to provide accurate and efficient entropy estimates, supporting a wide range of applications in molecular simulation and statistical mechanics."
58+
dev_url: https://github.com/CCPBioSim/CodeEntropy
59+
doc_url: https://codeentropy.readthedocs.io/en/latest/
60+
doc_source_url: https://github.com/CCPBioSim/CodeEntropy/blob/main/README.md

docs/developer_guide.rst

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,13 +60,46 @@ Run tests with coverage::
6060

6161
pytest --cov CodeEntropy --cov-report=term-missing
6262

63-
Update regression baselines::
63+
Run a specific test::
64+
65+
pytest tests/unit/.../test_file.py::test_function
66+
67+
Updating Regression Baselines
68+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
69+
70+
Regression baselines should only be updated when a change intentionally alters
71+
the expected numerical output of CodeEntropy. Do not update baselines simply
72+
because a regression test fails.
73+
74+
Before updating baselines, confirm that:
75+
76+
- The code change is intentional and understood.
77+
- The new output has been reviewed.
78+
- The regression difference is expected.
79+
- The pull request explains why the baselines changed.
80+
81+
For local updates, run::
6482

6583
pytest tests/regression --update-baselines
6684

67-
Run a specific test::
85+
For pull requests, baselines can also be updated using the GitHub Actions
86+
workflow **Update Regression Baselines**.
6887

69-
pytest tests/unit/.../test_file.py::test_function
88+
To use it:
89+
90+
1. Push your changes to your PR branch.
91+
2. Open the **Actions** tab on GitHub.
92+
3. Select **Update Regression Baselines**.
93+
4. Click **Run workflow**.
94+
5. Select your PR branch.
95+
6. Run the workflow.
96+
97+
The workflow runs the regression tests with ``--update-baselines`` and commits
98+
any changed baseline files back to the selected branch.
99+
100+
Only use this workflow when the baseline changes are intentional. If a regression
101+
test fails unexpectedly, investigate the failure instead of updating the
102+
baseline.
70103

71104
Regression Test Data
72105
--------------------

tests/unit/CodeEntropy/entropy/nodes/test_vibrational_node.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -321,7 +321,7 @@ def test_compute_force_torque_entropy_returns_zero_when_missing_matrix(shared_gr
321321
node = VibrationalEntropyNode()
322322
ve = MagicMock()
323323
pair = node._compute_force_torque_entropy(
324-
ve=ve, temp=298.0, fmat=None, tmat=np.eye(3), flexible=0, highest=True
324+
ve=ve, temp=298.0, fmat=None, tmat=None, flexible=0, highest=True
325325
)
326326
assert pair == EntropyPair(trans=0.0, rot=0.0)
327327

0 commit comments

Comments
 (0)