-
Notifications
You must be signed in to change notification settings - Fork 723
Feature non linear time averaged msd #5066
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
Changes from 19 commits
60973ba
0dc3db1
f6f55a1
e363635
5aa09ca
871faa2
00fc309
c90f52e
7ad3e09
b1ee485
2bbdffb
ee764b7
0f50810
7b16b9f
72b3dd3
e367984
069bec5
ac4b4b2
3ceca5c
1a24e36
daad519
29df80e
b578a67
e26f53a
125e710
498a061
788758d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||
---|---|---|---|---|
|
@@ -103,8 +103,7 @@ | |||
|
||||
msd = MSD.results.timeseries | ||||
|
||||
Visual inspection of the MSD is important, so let's take a look at it with a | ||||
simple plot. | ||||
Visual inspection of the MSD is important, so let's take a look at it with a simple plot. | ||||
|
||||
.. code-block:: python | ||||
|
||||
|
@@ -173,7 +172,7 @@ | |||
start_index = int(start_time/timestep) | ||||
end_time = 60 | ||||
linear_model = linregress(lagtimes[start_index:end_index], | ||||
msd[start_index:end_index]) | ||||
msd[start_index:end_index]) | ||||
gitsirsha marked this conversation as resolved.
Show resolved
Hide resolved
|
||||
slope = linear_model.slope | ||||
error = linear_model.stderr | ||||
# dim_fac is 3 as we computed a 3D msd with 'xyz' | ||||
|
@@ -245,6 +244,7 @@ | |||
from .base import AnalysisBase | ||||
from ..core import groups | ||||
from tqdm import tqdm | ||||
import collections | ||||
|
||||
logger = logging.getLogger("MDAnalysis.analysis.msd") | ||||
|
||||
|
@@ -281,15 +281,34 @@ class EinsteinMSD(AnalysisBase): | |||
the MSD. Otherwise, use the simple "windowed" algorithm. | ||||
The tidynamics package is required for `fft=True`. | ||||
Defaults to ``True``. | ||||
non_linear : bool | ||||
If ``True``, calculates MSD for trajectory where frames are | ||||
non-linearly dumped. To use this set `fft=False`. | ||||
Defaults to ``False``. | ||||
orbeckst marked this conversation as resolved.
Show resolved
Hide resolved
|
||||
|
||||
.. versionadded:: 2.10.0 | ||||
|
||||
|
||||
Attributes | ||||
---------- | ||||
dim_fac : int | ||||
Dimensionality :math:`d` of the MSD. | ||||
results.timeseries : :class:`numpy.ndarray` | ||||
The averaged MSD over all the particles with respect to lag-time. | ||||
The averaged MSD over all the particles with respect to constant lag-time or | ||||
unique Δt intervals. | ||||
results.msds_by_particle : :class:`numpy.ndarray` | ||||
The MSD of each individual particle with respect to lag-time. | ||||
The MSD of each individual particle with respect to constant lag-time or | ||||
unique Δt intervals. | ||||
for `non_linear=False`: a 2D array of shape (n_lagtimes, n_atoms) | ||||
for `non_linear=True`: a 2D array of shape (n_delta_t_values, n_atoms) | ||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The formatting does not look good when rendered, see MDAnalysis.analysis.msd.EinsteinMSD.results.msds_by_particle in the docs. Please change the formatting so that it makes sense to a reader. Always look at the rendered docs. You can read more about reST formatting with sphinx in the sphinx reST primer and accompanying docs. ![]() |
||||
results.delta_t_values : :class:`numpy.ndarray` | ||||
Array of unique Δt (time differences) at which time-averaged MSD values are | ||||
orbeckst marked this conversation as resolved.
Show resolved
Hide resolved
|
||||
computed (for `non_linear=True`). | ||||
For `non_linear=False` it is Null array. Time differences are same as the lag-times. | ||||
(To access: `lagtimes = np.arange(nframes)*timestep`). | ||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's change this so that it is also correct in The docs manually compute There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's in msd.py mdanalysis/package/MDAnalysis/analysis/msd.py Line 114 in 91146c5
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thank you! Sorry for my oversight. |
||||
|
||||
.. versionadded:: 2.10.0 | ||||
|
||||
ag : :class:`AtomGroup` | ||||
The :class:`AtomGroup` resulting from your selection | ||||
n_frames : int | ||||
|
@@ -299,27 +318,23 @@ class EinsteinMSD(AnalysisBase): | |||
|
||||
|
||||
.. versionadded:: 2.0.0 | ||||
orbeckst marked this conversation as resolved.
Show resolved
Hide resolved
|
||||
.. versionchanged:: 2.10.0 | ||||
Added ability to calculate MSD from samples that are not linearly spaced with the | ||||
new `non_linear` keyword argument. | ||||
""" | ||||
|
||||
def __init__(self, u, select="all", msd_type="xyz", fft=True, **kwargs): | ||||
r""" | ||||
Parameters | ||||
---------- | ||||
u : Universe or AtomGroup | ||||
An MDAnalysis :class:`Universe` or :class:`AtomGroup`. | ||||
select : str | ||||
A selection string. Defaults to "all" in which case | ||||
all atoms are selected. | ||||
msd_type : {'xyz', 'xy', 'yz', 'xz', 'x', 'y', 'z'} | ||||
Desired dimensions to be included in the MSD. | ||||
fft : bool | ||||
If ``True``, uses a fast FFT based algorithm for computation of | ||||
the MSD. Otherwise, use the simple "windowed" algorithm. | ||||
The tidynamics package is required for `fft=True`. | ||||
""" | ||||
def __init__( | ||||
self, | ||||
u, | ||||
select="all", | ||||
msd_type="xyz", | ||||
fft=True, | ||||
non_linear=False, | ||||
**kwargs, | ||||
): | ||||
if isinstance(u, groups.UpdatingAtomGroup): | ||||
raise TypeError( | ||||
"UpdatingAtomGroups are not valid for MSD " "computation" | ||||
"UpdatingAtomGroups are not valid for MSD computation" | ||||
) | ||||
|
||||
super(EinsteinMSD, self).__init__(u.universe.trajectory, **kwargs) | ||||
|
@@ -329,6 +344,7 @@ def __init__(self, u, select="all", msd_type="xyz", fft=True, **kwargs): | |||
self.msd_type = msd_type | ||||
self._parse_msd_type() | ||||
self.fft = fft | ||||
self.non_linear = non_linear | ||||
|
||||
# local | ||||
self.ag = u.select_atoms(self.select) | ||||
|
@@ -338,6 +354,7 @@ def __init__(self, u, select="all", msd_type="xyz", fft=True, **kwargs): | |||
# result | ||||
self.results.msds_by_particle = None | ||||
self.results.timeseries = None | ||||
self.results.delta_t_values = None | ||||
orbeckst marked this conversation as resolved.
Show resolved
Hide resolved
|
||||
|
||||
def _prepare(self): | ||||
# self.n_frames only available here | ||||
|
@@ -383,10 +400,13 @@ def _single_frame(self): | |||
] | ||||
|
||||
def _conclude(self): | ||||
if self.fft: | ||||
self._conclude_fft() | ||||
if self.non_linear: | ||||
self._conclude_non_linear() | ||||
else: | ||||
self._conclude_simple() | ||||
if self.fft: | ||||
self._conclude_fft() | ||||
else: | ||||
self._conclude_simple() | ||||
|
||||
def _conclude_simple(self): | ||||
r"""Calculates the MSD via the simple "windowed" algorithm.""" | ||||
|
@@ -421,3 +441,44 @@ def _conclude_fft(self): # with FFT, np.float64 bit prescision required. | |||
positions[:, n, :] | ||||
) | ||||
self.results.timeseries = self.results.msds_by_particle.mean(axis=1) | ||||
|
||||
def _conclude_non_linear(self): | ||||
|
||||
dump_times = self.times | ||||
gitsirsha marked this conversation as resolved.
Show resolved
Hide resolved
|
||||
n_frames = self.n_frames | ||||
n_atoms = self.n_particles | ||||
positions = self._position_array.astype(np.float64) | ||||
orbeckst marked this conversation as resolved.
Show resolved
Hide resolved
|
||||
|
||||
msd_dict = collections.defaultdict( | ||||
list | ||||
) # Dictionary to collect MSDs: {Δt: [msd1, msd2, ...]} | ||||
gitsirsha marked this conversation as resolved.
Show resolved
Hide resolved
|
||||
msds_by_particle_dict = collections.defaultdict(list) | ||||
|
||||
# TODO: optimize the code | ||||
# Looping over all the frames as if the referenced gets shifted frame to frame | ||||
orbeckst marked this conversation as resolved.
Show resolved
Hide resolved
|
||||
for i in range(n_frames): | ||||
for j in range(i + 1, n_frames): | ||||
delta_t = dump_times[j] - dump_times[i] | ||||
gitsirsha marked this conversation as resolved.
Show resolved
Hide resolved
|
||||
# Compute displacement and squared displacement | ||||
disp = positions[j] - positions[i] | ||||
squared_disp = np.sum(disp**2, axis=1) | ||||
msd = np.mean(squared_disp) | ||||
# Store MSD under corresponding Δt | ||||
msd_dict[delta_t].append(msd) | ||||
msds_by_particle_dict[delta_t].append(squared_disp) | ||||
|
||||
msd_dict[0] = [0] | ||||
msds_by_particle_dict[0.0] = [np.zeros(n_atoms)] | ||||
|
||||
# For each delta_t, stacked all squared_disp arrays and averaging over axis=0 (time origins) | ||||
delta_t_values = sorted(msd_dict.keys()) | ||||
avg_msds = [np.mean(msd_dict[dt]) for dt in delta_t_values] | ||||
msds_by_particle_array = np.zeros((len(delta_t_values), n_atoms)) | ||||
orbeckst marked this conversation as resolved.
Show resolved
Hide resolved
|
||||
for idx, dt in enumerate(delta_t_values): | ||||
# Stack list of arrays like -- (n_time_origins, n_atoms) | ||||
arr = np.vstack(msds_by_particle_dict[dt]) | ||||
msds_by_particle_array[idx, :] = np.mean(arr, axis=0) | ||||
|
||||
self.results.timeseries = np.array(avg_msds) | ||||
self.results.delta_t_values = np.array(delta_t_values) | ||||
self.results.msds_by_particle = msds_by_particle_array |
Uh oh!
There was an error while loading. Please reload this page.