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

Netcdf with no time #4074

Merged
merged 18 commits into from
Mar 22, 2023
Merged
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
1 change: 1 addition & 0 deletions package/AUTHORS
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@ Chronological list of authors
- Vishal Parmar
- Moritz Schaeffler
- Xu Hong Chen
- Domenico Marson

External code
-------------
Expand Down
3 changes: 2 additions & 1 deletion package/CHANGELOG
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,11 @@ The rules for this file:

??/??/?? IAlibay, pgbarletta, mglagolev, hmacdope, manuel.nuno.melo, chrispfae,
ooprathamm, MeetB7, BFedder, v-parmar, MoSchaeffler, jbarnoud, jandom,
xhgchen, jaclark5
xhgchen, jaclark5, DrDomenicoMarson
* 2.5.0

Fixes
* Fix for NetCDF trajectories without `time` variable (Issue #4073)
* Allows shape_parameter and asphericity to yield per residue quantities
(Issue #3002, PR #3905)
* Add tests for "No path data" exception raise in test_psa.py (Issue #4036)
Expand Down
19 changes: 15 additions & 4 deletions package/MDAnalysis/coordinates/TRJ.py
Original file line number Diff line number Diff line change
Expand Up @@ -528,7 +528,7 @@ def __init__(self, filename, n_atoms=None, mmap=None, **kwargs):
# len(dimensions['frame']) == 10: in any case, we need to get
# the number of frames from somewhere such as the time variable:
if self.n_frames is None:
self.n_frames = self.trjfile.variables['time'].shape[0]
self.n_frames = self.trjfile.variables['coordinates'].shape[0]
except KeyError:
errmsg = (f"NCDF trajectory {self.filename} does not contain "
f"frame information")
Expand All @@ -544,7 +544,17 @@ def __init__(self, filename, n_atoms=None, mmap=None, **kwargs):

# checks for not-implemented features (other units would need to be
# hacked into MDAnalysis.units)
self._verify_units(self.trjfile.variables['time'].units, 'picosecond')
try:
self._verify_units(self.trjfile.variables['time'].units, 'picosecond')
self.has_time = True
except KeyError:
self.has_time = False
IAlibay marked this conversation as resolved.
Show resolved Hide resolved
wmsg = ("NCDF trajectory does not contain `time` information;"
" `time` will be set as an increasing index")
warnings.warn(wmsg)
logger.warning(wmsg)


self._verify_units(self.trjfile.variables['coordinates'].units,
'angstrom')

Expand Down Expand Up @@ -640,7 +650,8 @@ def _read_frame(self, frame):
self.n_frames))
# note: self.trjfile.variables['coordinates'].shape == (frames, n_atoms, 3)
ts._pos[:] = self._get_var_and_scale('coordinates', frame)
ts.time = self._get_var_and_scale('time', frame)
if self.has_time:
ts.time = self._get_var_and_scale('time', frame)
if self.has_velocities:
ts._velocities[:] = self._get_var_and_scale('velocities', frame)
if self.has_forces:
Expand Down Expand Up @@ -685,7 +696,7 @@ def _get_dt(self):
try:
t1 = self.trjfile.variables['time'][1]
t0 = self.trjfile.variables['time'][0]
except IndexError:
except (IndexError, KeyError):
raise AttributeError
return t1 - t0

Expand Down
31 changes: 30 additions & 1 deletion testsuite/MDAnalysisTests/coordinates/test_netcdf.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@

from MDAnalysisTests.datafiles import (PFncdf_Top, PFncdf_Trj,
GRO, TRR, XYZ_mini,
PRM_NCBOX, TRJ_NCBOX, DLP_CONFIG)
PRM_NCBOX, TRJ_NCBOX, DLP_CONFIG,
CPPTRAJ_TRAJ_TOP, CPPTRAJ_TRAJ)
from MDAnalysisTests.coordinates.test_trj import _TRJReaderTest
from MDAnalysisTests.coordinates.reference import (RefVGV, RefTZ2)
from MDAnalysisTests import make_Universe
Expand Down Expand Up @@ -299,6 +300,34 @@ def test_box(self, universe, index, expected):
assert_almost_equal(self.box_refs[expected], universe.dimensions)


class TestNCDFReader4(object):
"""NCDF Trajectory exported by cpptaj, without `time` variable."""
prec = 3

@pytest.fixture(scope='class')
def u(self):
return mda.Universe(CPPTRAJ_TRAJ_TOP,
IAlibay marked this conversation as resolved.
Show resolved Hide resolved
[CPPTRAJ_TRAJ, CPPTRAJ_TRAJ])

def test_chain_times(self, u):
"""Check times entries for a chain of trajectories without
a defined time variable"""
ref_times = [0.0, 1.0, 2.0, 3.0, 4.0, 5.0]
time_list = [ts.time for ts in u.trajectory]
assert ref_times == time_list

IAlibay marked this conversation as resolved.
Show resolved Hide resolved
def test_dt(self, u):
ref = 1.0
assert u.trajectory.dt == pytest.approx(ref)
assert u.trajectory.ts.dt == pytest.approx(ref)

def test_warn_user_no_time_information(self, u):
wmsg = ("NCDF trajectory does not contain `time` information;"
" `time` will be set as an increasing index")
with pytest.warns(UserWarning, match=wmsg):
u2 = mda.Universe(CPPTRAJ_TRAJ_TOP, CPPTRAJ_TRAJ)


class _NCDFGenerator(object):
"""A class for generating abitrary ncdf files and exhaustively test
edge cases which might not be found in the wild"""
Expand Down
Binary file not shown.
Loading