Skip to content

Conversation

Rupesh-Singh-Karki
Copy link

@Rupesh-Singh-Karki Rupesh-Singh-Karki commented Sep 27, 2025

Fixes #5115

Changes made in this Pull Request:

  • Add units attribute to DumpReader class specifying LAMMPS "real" units (time: fs, length: Angstrom, velocity: Angstrom/fs, force: kcal/(mol*Angstrom))
  • Implement force unit conversion in _read_next_timestep() method to convert forces from native kcal/(molAngstrom) to MDAnalysis base units kJ/(molAngstrom)
  • Add unit conversion calls for positions, velocities, and forces when convert_units=True (default behavior)
  • Update docstring to document the automatic force unit conversion behavior
  • Add comprehensive tests for force unit conversion functionality:
    • Test units attribute definition
    • Test conversion factor calculation (4.184)
    • Test actual force conversion using existing test files
    • Test conversion consistency across all trajectory frames
  • Ensure backward compatibility with convert_units=False option

This fix resolves the inconsistency where LAMMPSDUMP forces remained in kcal/(molAngstrom) while other trajectory formats (GROMACS TRR, AMBER NetCDF) properly converted forces to kJ/(molAngstrom). Now all trajectory formats use consistent force units for downstream analysis.

PR Checklist

  • Issue raised/referenced?
  • Tests updated/added?
  • Documentation updated/added?
  • package/CHANGELOG file updated?
  • Is your name in package/AUTHORS? (If it is not, add it!)

Developers Certificate of Origin

I certify that I can submit this code contribution as described in the Developer Certificate of Origin, under the MDAnalysis LICENSE.


📚 Documentation preview 📚: https://mdanalysis--5117.org.readthedocs.build/en/5117/

Copy link

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hello there first time contributor! Welcome to the MDAnalysis community! We ask that all contributors abide by our Code of Conduct and that first time contributors introduce themselves on GitHub Discussions so we can get to know you. You can learn more about participating here. Please also add yourself to package/AUTHORS as part of this PR.

Copy link

codecov bot commented Sep 27, 2025

Codecov Report

❌ Patch coverage is 46.93878% with 26 lines in your changes missing coverage. Please review.
✅ Project coverage is 85.82%. Comparing base (519ac56) to head (518bca9).
⚠️ Report is 27 commits behind head on develop.

Files with missing lines Patch % Lines
package/MDAnalysis/coordinates/LAMMPS.py 46.93% 18 Missing and 8 partials ⚠️

❗ There is a different number of reports uploaded between BASE (519ac56) and HEAD (518bca9). Click for more details.

HEAD has 3 uploads less than BASE
Flag BASE (519ac56) HEAD (518bca9)
6 3
Additional details and impacted files
@@             Coverage Diff             @@
##           develop    #5117      +/-   ##
===========================================
- Coverage    93.88%   85.82%   -8.07%     
===========================================
  Files          180      180              
  Lines        22422    22496      +74     
  Branches      3186     3202      +16     
===========================================
- Hits         21052    19308    -1744     
- Misses         902     2722    +1820     
+ Partials       468      466       -2     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@orbeckst
Copy link
Member

@hmacdope @jaclark5 could you review this PR? I think you both have some LAMMPS experience. Or can you think of someone else?

@orbeckst
Copy link
Member

@hmacdope I have tentatively assigned you as PR shepherd. If you don't have the bandwidth, please find someone else or un-assign yourself and let me know. Thanks.

Copy link
Member

@tylerjereddy tylerjereddy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This does seem reasonably solid at first glance:

  • no old tests were modified, only new tests added
  • 3/4 of the new tests fail before the new source patch is applied, and all pass after

I made a few small suggestions. I'm not a LAMMPS expert (though it is heavily used here).


assert DumpReader.units == expected_units

def test_force_unit_conversion_factor(self):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the only test that doesn't fail when the source patch in this PR is reverted.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test appears to be now passing?


# Test that native forces are unchanged when convert_units=False
# Just check they are reasonable values (not zero everywhere)
assert not np.allclose(forces_native, 0.0)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, this check is perhaps a bit less convincing. What about checking the first and last force with LAMMPS or another reader library and ensuring those are preserved in MDA with convert_units=False?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is assuming that the forces in native units are zero? Consider using assert_allclose with the forces values copied directly from the dump file

Copy link
Contributor

@jaclark5 jaclark5 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for doing this! It looks like these changes would commit the DumpReader to expecting real units, however, lj and metal are also very common options. You're going to have to implement the timeunit and lengthunit keywords and then introduce an energy keyword energyunit. This would be consistent with the LAMMPS.DCDReader and then the documentation accordingly:

        self.units["time"] = kwargs.pop("timeunit", self.units["time"])
        self.units["length"] = kwargs.pop("lengthunit", self.units["length"])

Copy link
Contributor

@jaclark5 jaclark5 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The changes look great. Only ~40% of the lines of code are covered by these tests, once that's up to 100% and we go through the tests I think it'll be ready


# Test that native forces are unchanged when convert_units=False
# Just check they are reasonable values (not zero everywhere)
assert not np.allclose(forces_native, 0.0)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is assuming that the forces in native units are zero? Consider using assert_allclose with the forces values copied directly from the dump file


assert DumpReader.units == expected_units

def test_force_unit_conversion_factor(self):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test appears to be now passing?

# MDAnalysis.analysis.lineardensity


@pytest.fixture(scope="module", params=params_for_cls(LinearDensity))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't remove that.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't change anything in this file unless you have to.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Convert units of trajectory data when constructing a universe

7 participants