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

Nongaussian parameter #3896

Open
wants to merge 18 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 5 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/CHANGELOG
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ Fixes
(e.g. bonds, angles) (PR #3779).

Enhancements
* Nongaussian parameter available from msd.run(fft=False), (#3895)
* LAMMPSDump Reader optionally unwraps trajectories with image flags upon
loading (#3843
* LAMMPSDump Reader now imports velocities and forces (#3843)
Expand Down
36 changes: 34 additions & 2 deletions package/MDAnalysis/analysis/msd.py
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,7 @@
Maginn2019
Yeh2004
Bulow2020
Fuchs1998


Classes
Expand Down Expand Up @@ -267,6 +268,10 @@
class EinsteinMSD(AnalysisBase):
r"""Class to calculate Mean Squared Displacement by the Einstein relation.

If `fft=False` so that the "windowed" algorithm is used, the second order
Copy link
Member

Choose a reason for hiding this comment

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

I think we need to make the parameter an optional addition to the fft=False run. MSDs are already expensive (esp without an FFT) and tacking on more compulsory computation is not ideal. Much better to have it as an optional kwarg.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fair enough, that also begs the question on whether this package will move toward cython modules?

Copy link
Member

Choose a reason for hiding this comment

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

for the MSD package? There is likely some benefit there. We are generally encouraging of Cython contributions and have a bunch of extensions already written in Cython.

If you go down the cython side and need a hand feel free to ping. See setup.py for the minimal setup for a cython extension.

nonbonded parameter is also computed to capture heterogiety as different
jaclark5 marked this conversation as resolved.
Show resolved Hide resolved
jaclark5 marked this conversation as resolved.
Show resolved Hide resolved
time scales. See :cite:p:`Fuchs1998` for more information.

Parameters
----------
u : Universe or AtomGroup
Expand All @@ -291,6 +296,12 @@ class EinsteinMSD(AnalysisBase):
The averaged MSD over all the particles with respect to lag-time.
results.msds_by_particle : :class:`numpy.ndarray`
The MSD of each individual particle with respect to lag-time.
results.nongaussian : :class:`numpy.ndarray`
Only available when `fft==False`. The averaged nongaussian
jaclark5 marked this conversation as resolved.
Show resolved Hide resolved
parameter over all the particles with respect to lag-time.
results.msds_by_nongaussian : :class:`numpy.ndarray`
Only available when `fft==False`. The nongaussian parameter
of each individual particle with respect to lag-time.
ag : :class:`AtomGroup`
The :class:`AtomGroup` resulting from your selection
n_frames : int
Expand All @@ -299,6 +310,9 @@ class EinsteinMSD(AnalysisBase):
Number of particles MSD was calculated over.


.. versionchanged:: 2.4.0
jaclark5 marked this conversation as resolved.
Show resolved Hide resolved
Added second order non-gaussian parameter to output for "simple"
algorithm.
.. versionadded:: 2.0.0
"""

Expand Down Expand Up @@ -338,12 +352,18 @@ def __init__(self, u, select='all', msd_type='xyz', fft=True, **kwargs):
# result
self.results.msds_by_particle = None
self.results.timeseries = None
if not fft:
jaclark5 marked this conversation as resolved.
Show resolved Hide resolved
self.results.nongaussian_by_particle = None
self.results.nongaussian_parameter = None

def _prepare(self):
# self.n_frames only available here
# these need to be zeroed prior to each run() call
self.results.msds_by_particle = np.zeros((self.n_frames,
self.n_particles))
if not self.fft:
jaclark5 marked this conversation as resolved.
Show resolved Hide resolved
self.results.nongaussian_by_particle = np.zeros((self.n_frames,
self.n_particles))
self._position_array = np.zeros(
(self.n_frames, self.n_particles, self.dim_fac))
# self.results.timeseries not set here
Expand Down Expand Up @@ -382,16 +402,28 @@ def _conclude(self):
self._conclude_simple()

def _conclude_simple(self):
r""" Calculates the MSD via the simple "windowed" algorithm.
r""" Calculates the MSD via the simple "windowed" algorithm
with nongaussian parameter.

"""
lagtimes = np.arange(1, self.n_frames)
positions = self._position_array.astype(np.float64)
for lag in lagtimes:
disp = positions[:-lag, :, :] - positions[lag:, :, :]
sqdist = np.square(disp).sum(axis=-1)
self.results.msds_by_particle[lag, :] = np.mean(sqdist, axis=0)
tmp = np.mean(sqdist, axis=0)
jaclark5 marked this conversation as resolved.
Show resolved Hide resolved
self.results.msds_by_particle[lag, :] = tmp
self.results.nongaussian_by_particle[lag, :] = 3.0/5.0*np.mean(
np.square(sqdist), axis=0)/np.square(tmp) - 1.0

self.results.timeseries = self.results.msds_by_particle.mean(axis=1)
self.results.nongaussian_parameter = (3.0/5.0*
np.mean(
(self.results.nongaussian_by_particle + 1.0)*5.0/3.0
*np.square(self.results.msds_by_particle),
axis=1
)
/np.square(self.results.timeseries) - 1.0)

def _conclude_fft(self): # with FFT, np.float64 bit prescision required.
r""" Calculates the MSD via the FCA fast correlation algorithm.
Expand Down
14 changes: 13 additions & 1 deletion package/doc/sphinx/source/references.bib
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
@article{Fuchs1998,
author = {Fuchs, M. and Gotze, W. and Mayr, M. R.},
doi = {10.1103/PhysRevE.58.3384},
journal = {Physical Review E},
Number = {3},
Pages = {3384--3399},
Publisher = {American Physical Society},
Title = {Asymptotic laws for tagged-particle motion in glassy systems},
Volume = {58},
year = {1998}
}

@article{MichaudAgrawal2011,
author = {Michaud-Agrawal, Naveen and Denning, Elizabeth J. and Woolf, Thomas B. and Beckstein, Oliver},
title = {MDAnalysis: A toolkit for the analysis of molecular dynamics simulations},
Expand Down Expand Up @@ -734,4 +746,4 @@ @incollection{Waveren2005
url = {http://www.intel.com/cd/ids/developer/asmo-na/eng/293748.htm},
booktitle = {},
id = {transformations}
}
}
14 changes: 14 additions & 0 deletions testsuite/MDAnalysisTests/analysis/test_msd.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,12 @@ def test_simple_step_traj_all_dims(self, step_traj, NSTEP, dim,
m_simple = MSD(step_traj, 'all', msd_type=dim, fft=False)
m_simple.run()
poly = characteristic_poly(NSTEP, dim_factor)
alpha = -0.4*np.ones(NSTEP)
jaclark5 marked this conversation as resolved.
Show resolved Hide resolved
alpha[0] = np.nan
assert_almost_equal(m_simple.results.timeseries, poly, decimal=4)
assert_almost_equal(m_simple.results.nongaussian_parameter,
alpha,
decimal=5)

@pytest.mark.parametrize("dim, dim_factor", [
('xyz', 3), ('xy', 2), ('xz', 2), ('yz', 2), ('x', 1), ('y', 1),
Expand All @@ -147,6 +152,15 @@ def test_random_walk_u_simple(self, random_walk_u):
norm = np.linalg.norm(msd_rw.results.timeseries)
val = 3932.39927487146
assert_almost_equal(norm, val, decimal=5)
# nongaussian parameter may have negative values (above -2.5) and
# postiive values, but converge to zero at long times.
jaclark5 marked this conversation as resolved.
Show resolved Hide resolved
assert_almost_equal(msd_rw.results.nongaussian_parameter[:20],
jaclark5 marked this conversation as resolved.
Show resolved Hide resolved
np.array([np.nan, 0.00049, 0.00048, 0.00536,
hmacdope marked this conversation as resolved.
Show resolved Hide resolved
-0.00299, 0.00014, -0.0046 , -0.00612,
-0.00307, 0.00033, 0.00584, 0.0131 ,
0.01516, 0.01666, 0.01924, 0.02052,
0.01961, 0.01743, 0.01355, 0.00997]),
decimal=5)


@pytest.mark.skipif(import_not_available("tidynamics"),
Expand Down