Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added dt support for xtc and trr trajectories. #4908

Open
wants to merge 17 commits into
base: develop
Choose a base branch
from

Conversation

pbuslaev
Copy link

@pbuslaev pbuslaev commented Feb 10, 2025

Fixes #4905

Changes made in this Pull Request:

  • I added basic dt support for XTC and XDR Reader/Writer

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--4908.org.readthedocs.build/en/4908/

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 Feb 11, 2025

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 93.41%. Comparing base (adddc32) to head (3b16338).

Additional details and impacted files
@@             Coverage Diff             @@
##           develop    #4908      +/-   ##
===========================================
- Coverage    93.42%   93.41%   -0.01%     
===========================================
  Files          177      189      +12     
  Lines        21859    22942    +1083     
  Branches      3078     3085       +7     
===========================================
+ Hits         20422    21432    +1010     
- Misses         986     1059      +73     
  Partials       451      451              

☔ 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.

Copy link
Member

@orbeckst orbeckst left a comment

Choose a reason for hiding this comment

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

Overall this is looking pretty solid. Please see comments below. Could you please address them?

@@ -148,6 +149,8 @@ def __init__(
itself is that of the sub system.
refresh_offsets : bool (optional)
force refresh of offsets
dt : float (optional)
timestep in MDAnalysis units to load trajectory with
Copy link
Member

Choose a reason for hiding this comment

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

Clearly document what happens here.

State that None reads the time as stored in the trajectory. Choosing dt overrides the time that is stored in the trajectory and assigns frame * dt as time.

Comment on lines +118 to +119
elif self._dt == ts.dt:
time = ts.time
Copy link
Member

Choose a reason for hiding this comment

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

Delete this case: this leads to weird behavior when the initial frame is at 0 but the time is not. In this case, setting dt will behave differently from what the user would expect, namely that time = frame * dt. Make sure that the code exactly implements what you document.

Copy link
Author

@pbuslaev pbuslaev Mar 26, 2025

Choose a reason for hiding this comment

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

My thinking here, was that if dt is set, and it is exactly equal to one of the trajectory, I don't want to touch the time in the frame.

Copy link
Member

Choose a reason for hiding this comment

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

I understand but that's not how it's documented. If the user does not want to change anything then they should simply not set dt. Less magic is better.

@@ -327,13 +335,16 @@ def __init__(self, filename, n_atoms, convert_units=True, **kwargs):
number of atoms to be written
convert_units : bool (optional)
convert from MDAnalysis units to format specific units
dt : float (optional)
timestep in MDAnalysis units to write trajectory with
Copy link
Member

Choose a reason for hiding this comment

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

document exactly what dt does and what the default means

Comment on lines +109 to +110
elif self._dt == ts.dt:
time = ts.time
Copy link
Member

Choose a reason for hiding this comment

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

as in TRR – remove this case because it leads to ambiguous behavior

time = ts.time
else:
time = self._dt * ts.frame
step = ts.data.get('step', ts.frame)
Copy link
Member

Choose a reason for hiding this comment

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

good fix

@@ -64,10 +64,12 @@ def __init__(self, filename, n_atoms, convert_units=True,
number of atoms to write
convert_units : bool (optional)
convert into MDAnalysis units
dt : float (optional)
timestep in MDAnalysis units to load trajectory with
Copy link
Member

Choose a reason for hiding this comment

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

document exact behavior, emphasize that None is the default that reads time from trajectory and that dt as a float is for special cases when one wants to set a different time step from what is stored

precision : float (optional)
set precision of saved trjactory to this number of decimal places.
"""
super(XTCWriter, self).__init__(filename, n_atoms, convert_units,
super(XTCWriter, self).__init__(filename, n_atoms, convert_units, dt,
Copy link
Member

Choose a reason for hiding this comment

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

use kwargs for the super call (sorry that convert_units was not done)

Suggested change
super(XTCWriter, self).__init__(filename, n_atoms, convert_units, dt,
super(XTCWriter, self).__init__(filename, n_atoms, convert_units=convert_units, dt=dt,

(you probably need to line-break ... actually, just run through black)

@@ -164,7 +171,11 @@ def _read_next_timestep(self, ts=None):
def _frame_to_ts(self, frame, ts):
"""convert a xtc-frame to a mda TimeStep"""
ts.frame = self._frame
ts.time = frame.time
dt = self._kwargs["dt"]
if dt is not None:
Copy link
Member

Choose a reason for hiding this comment

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

Move the default behavior first in if block

def test_Writer_with_dt_setting(self, tmpdir):
universe = mda.Universe(GRO, self.filename, convert_units=True)
ext = os.path.splitext(self.filename)[1]
outfile = str(tmpdir.join("/xdr-reader-test" + ext))
Copy link
Member

Choose a reason for hiding this comment

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

Do you have to convert to string? Is Writer not able to use the Path instance?

Copy link
Member

Choose a reason for hiding this comment

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

(or is tmpdir something else .... some py.path?)

Copy link
Member

Choose a reason for hiding this comment

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

(And yes .... you took the old code, it's just possible that this code is so old that it predates the ability of readers/writers to work with Path objects.)

@@ -245,6 +278,31 @@ def test_Writer(self, tmpdir):
u.atoms.positions, universe.atoms.positions, self.prec
)

def test_Writer_with_dt_setting(self, tmpdir):
universe = mda.Universe(GRO, self.filename, convert_units=True)
Copy link
Member

Choose a reason for hiding this comment

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

I don't like replicating the code of test_Writer, less copy&paste makes for more maintainable code. Can you please refactor so that the two methods share most of their code? Perhaps there's even a way to make it a parametrized test.

@orbeckst orbeckst changed the title draft: Added dt support for xtc and trr trajectories. Added dt support for xtc and trr trajectories. Mar 13, 2025
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.

Add time step parameter to XTC Writers and Readers
3 participants