Skip to content
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
3 changes: 2 additions & 1 deletion package/CHANGELOG
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ The rules for this file:
calcraven,xiki-tempula, mieczyslaw, manuel.nuno.melo, PicoCentauri,
hanatok, rmeli, aditya-kamath, tirkarthi, LeonardoBarneschi, hejamu,
biogen98, orioncohen, z3y50n, hp115, ojeda-e, thadanipaarth, HenryKobin,
1ut, sulays
1ut, sulays, PicoCentauri

* 2.0.0

Expand Down Expand Up @@ -103,6 +103,7 @@ Fixes
* Fix syntax warning over comparison of literals using is (Issue #3066)

Enhancements
* Switch GNMAnalysis to AnalysisBase (Issue #3243)
* Adds python 3.9 support (Issue #2974, PR #3027, #3245)
* Added an MDAnalysis shields.io badge to the README (Issue #3227, PR #3229)
* Added sort method to the atomgroup (Issue #2976, PR #3188)
Expand Down
100 changes: 46 additions & 54 deletions package/MDAnalysis/analysis/gnm.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,11 +86,13 @@

"""
import itertools
import logging
import warnings

import numpy as np

import warnings
import logging
from .base import AnalysisBase


logger = logging.getLogger('MDAnalysis.analysis.GNM')

Expand Down Expand Up @@ -189,7 +191,7 @@ def order_list(w):
return list_map


class GNMAnalysis(object):
class GNMAnalysis(AnalysisBase):
"""Basic tool for GNM analysis.

Each frame is treated as a novel structure and the GNM
Expand Down Expand Up @@ -217,6 +219,13 @@ class GNMAnalysis(object):
`Bonus_groups` is contained in `selection` as this could lead to
double counting. No checks are applied. Default is ``None``.

Attributes
----------
results : list
GNM results per frame:
results = [(time,eigenvalues[1],eigenvectors[1]),
(time,eigenvalues[1],eigenvectors[1]), ...]

See Also
--------
:class:`closeContactGNMAnalysis`
Expand All @@ -228,6 +237,8 @@ class GNMAnalysis(object):
.. versionchanged:: 1.0.0
Changed `selection` keyword to `select`

.. versionchanged:: 2.0.0
Use :class:`~MDAnalysis.analysis.AnalysisBase` as parent class.
"""

def __init__(self,
Expand All @@ -236,6 +247,7 @@ def __init__(self,
cutoff=7.0,
ReportVector=None,
Bonus_groups=None):
super(GNMAnalysis, self).__init__(universe.trajectory)
self.u = universe
self.select = select
self.cutoff = cutoff
Expand Down Expand Up @@ -306,49 +318,31 @@ def generate_kirchoff(self):

return matrix

def run(self, start=None, stop=None, step=None):
"""Analyze trajectory and produce timeseries.

Parameters
----------
start : int (optional)
stop : int (optional)
step : int (optional)

Returns
-------
results : list
GNM results per frame::

results = [(time,eigenvalues[1],eigenvectors[1]),(time,eigenvalues[1],eigenvectors[1])... ]

.. versionchanged:: 0.16.0
use start, stop, step instead of skip
"""
logger.info("GNM analysis: starting")

def _prepare(self):
self.timeseries = []
self._timesteps = []

for ts in self.u.trajectory[start:stop:step]:
self._timesteps.append(ts.time)

matrix = self.generate_kirchoff()
try:
u, w, v = np.linalg.svd(matrix)
except np.linalg.LinAlgError:
print("\nFrame skip at", ts.time,
"(SVD failed to converge). Cutoff", self.cutoff)
continue
#Save the results somewhere useful in some useful format. Usefully.
self._generate_output(
w,
v,
self.results,
ts.time,
matrix,
ReportVector=self.ReportVector,
counter=ts.frame)

def _single_frame(self):
matrix = self.generate_kirchoff()
try:
_, w, v = np.linalg.svd(matrix)
except np.linalg.LinAlgError:
msg = f"SVD with cutoff {self.cutoff} failed to converge. "
msg += f"Skip frame at {self._ts.time}."
warnings.warn(msg)
logger.warning(msg)
return
# Save the results somewhere useful in some useful format. Usefully.
self._generate_output(
w,
v,
self.results,
self._ts.time,
matrix,
ReportVector=self.ReportVector,
counter=self._ts.frame)

def _conclude(self):
self._timesteps = self.times


class closeContactGNMAnalysis(GNMAnalysis):
Expand Down Expand Up @@ -394,6 +388,9 @@ class closeContactGNMAnalysis(GNMAnalysis):
.. versionchanged:: 1.0.0
MassWeight option (see above deprecation entry).
Changed `selection` keyword to `select`

.. versionchanged:: 2.0.0
Use :class:`~MDAnalysis.analysis.AnalysisBase` as parent class.
"""

def __init__(self,
Expand All @@ -402,18 +399,13 @@ def __init__(self,
cutoff=4.5,
ReportVector=None,
weights="size"):
self.u = universe
self.select = select
self.cutoff = cutoff
self.results = [] # final result
self._timesteps = None # time for each frame
self.ReportVector = ReportVector
self.ca = self.u.select_atoms(self.select)

super(closeContactGNMAnalysis, self).__init__(universe,
select,
cutoff,
ReportVector)
self.weights = weights

def generate_kirchoff(self):
natoms = self.ca.n_atoms
nresidues = self.ca.n_residues
positions = self.ca.positions
residue_index_map = [
Expand Down
12 changes: 11 additions & 1 deletion testsuite/MDAnalysisTests/analysis/test_gnm.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
# J. Comput. Chem. 32 (2011), 2319--2327, doi:10.1002/jcc.21787
#
import os
from unittest.mock import patch

import MDAnalysis as mda
import MDAnalysis.analysis.gnm
Expand Down Expand Up @@ -80,6 +81,15 @@ def test_generate_kirchoff(universe):
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])


def test_gnm_SVD_fail(universe):
with patch.object(np.linalg, "svd") as np_load_mock:
np_load_mock.side_effect = np.linalg.LinAlgError
msg = "SVD with cutoff 7.0 failed to converge. "
msg += "Skip frame at 0.0."
with pytest.warns(UserWarning, match=msg):
mda.analysis.gnm.GNMAnalysis(universe).run(stop=1)


def test_closeContactGNMAnalysis(universe):
gnm = mda.analysis.gnm.closeContactGNMAnalysis(universe, weights="size")
gnm.run(stop=2)
Expand Down Expand Up @@ -127,4 +137,4 @@ def test_closeContactGNMAnalysis_weights_None(universe):
0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -43.0, -3.0])
0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -43.0, -3.0])