From 56a3a33624caf8dc61c0e57424a21473802afb4a Mon Sep 17 00:00:00 2001 From: Philip Loche Date: Tue, 27 Apr 2021 00:18:42 +0200 Subject: [PATCH 1/9] Switch GNMAnalysis to AnalysisBase --- package/CHANGELOG | 3 +- package/MDAnalysis/analysis/gnm.py | 92 ++++++++++++------------------ 2 files changed, 39 insertions(+), 56 deletions(-) diff --git a/package/CHANGELOG b/package/CHANGELOG index 714c0159b96..14544c34fa5 100644 --- a/package/CHANGELOG +++ b/package/CHANGELOG @@ -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 @@ -102,6 +102,7 @@ Fixes * Fix syntax warning over comparison of literals using is (Issue #3066) Enhancements + * Switch GNMAnalysis to AnalysisBase (Issue #3243) * Added an MDAnalysis shields.io badge to the README (Issue #3227, PR #3229) * Added sort method to the atomgroup (Issue #2976, PR #3188) * ITPParser now reads [ atomtypes ] sections in ITP files, used for charges diff --git a/package/MDAnalysis/analysis/gnm.py b/package/MDAnalysis/analysis/gnm.py index 65c5356f73c..d8b87d274a2 100644 --- a/package/MDAnalysis/analysis/gnm.py +++ b/package/MDAnalysis/analysis/gnm.py @@ -89,7 +89,8 @@ import numpy as np -import warnings +from .base import AnalysisBase + import logging logger = logging.getLogger('MDAnalysis.analysis.GNM') @@ -189,7 +190,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 @@ -217,17 +218,22 @@ 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` - .. versionchanged:: 0.16.0 Made :meth:`generate_output` a private method :meth:`_generate_output`. .. versionchanged:: 1.0.0 Changed `selection` keyword to `select` - """ def __init__(self, @@ -236,6 +242,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 @@ -306,49 +313,29 @@ 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: + u, w, v = np.linalg.svd(matrix) + except np.linalg.LinAlgError: + print("\nFrame skip at", self._ts.time, + "(SVD failed to converge). Cutoff", self.cutoff) + 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): @@ -402,18 +389,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 = [ From 8927ad33ebb6f836049a87fb56e2abeb7825ffd7 Mon Sep 17 00:00:00 2001 From: Philip Loche Date: Tue, 27 Apr 2021 00:29:55 +0200 Subject: [PATCH 2/9] Fixed PEP8 issues --- package/MDAnalysis/analysis/gnm.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package/MDAnalysis/analysis/gnm.py b/package/MDAnalysis/analysis/gnm.py index d8b87d274a2..5c033f6d098 100644 --- a/package/MDAnalysis/analysis/gnm.py +++ b/package/MDAnalysis/analysis/gnm.py @@ -322,9 +322,9 @@ def _single_frame(self): u, w, v = np.linalg.svd(matrix) except np.linalg.LinAlgError: print("\nFrame skip at", self._ts.time, - "(SVD failed to converge). Cutoff", self.cutoff) + "(SVD failed to converge). Cutoff", self.cutoff) return - #Save the results somewhere useful in some useful format. Usefully. + # Save the results somewhere useful in some useful format. Usefully. self._generate_output( w, v, From 8eb4cae37d16e5cb4fa29c3c580928c434e76515 Mon Sep 17 00:00:00 2001 From: Philip Loche Date: Tue, 27 Apr 2021 22:37:38 +0200 Subject: [PATCH 3/9] Created warning --- package/MDAnalysis/analysis/gnm.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/package/MDAnalysis/analysis/gnm.py b/package/MDAnalysis/analysis/gnm.py index 5c033f6d098..ce21f031124 100644 --- a/package/MDAnalysis/analysis/gnm.py +++ b/package/MDAnalysis/analysis/gnm.py @@ -86,12 +86,13 @@ """ import itertools +import logging +import warnings import numpy as np from .base import AnalysisBase -import logging logger = logging.getLogger('MDAnalysis.analysis.GNM') @@ -319,10 +320,12 @@ def _prepare(self): def _single_frame(self): matrix = self.generate_kirchoff() try: - u, w, v = np.linalg.svd(matrix) + _, w, v = np.linalg.svd(matrix) except np.linalg.LinAlgError: - print("\nFrame skip at", self._ts.time, - "(SVD failed to converge). Cutoff", self.cutoff) + 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( From bdfba40629d22d934a4a5adf76211ecb4b33a8ca Mon Sep 17 00:00:00 2001 From: Philip Loche Date: Wed, 28 Apr 2021 00:52:13 +0200 Subject: [PATCH 4/9] Added testcase --- testsuite/MDAnalysisTests/analysis/test_gnm.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/testsuite/MDAnalysisTests/analysis/test_gnm.py b/testsuite/MDAnalysisTests/analysis/test_gnm.py index 9587a664d74..f658cd16c6f 100644 --- a/testsuite/MDAnalysisTests/analysis/test_gnm.py +++ b/testsuite/MDAnalysisTests/analysis/test_gnm.py @@ -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 @@ -80,6 +81,18 @@ 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): + gnm = mda.analysis.gnm.GNMAnalysis(universe) + # Initilize attributes like self._ts + # necessary for print the warning + gnm.run(stop=1) + + with patch.object(np.linalg, "svd") as np_load_mock: + np_load_mock.side_effect = np.linalg.LinAlgError + with pytest.warns(UserWarning): + assert gnm._single_frame() is None + + def test_closeContactGNMAnalysis(universe): gnm = mda.analysis.gnm.closeContactGNMAnalysis(universe, weights="size") gnm.run(stop=2) From 7157d407ff5e864056215356f4381f8cc95f62f9 Mon Sep 17 00:00:00 2001 From: Philip Loche Date: Wed, 28 Apr 2021 08:33:25 +0200 Subject: [PATCH 5/9] Removed trailing space Co-authored-by: Irfan Alibay --- testsuite/MDAnalysisTests/analysis/test_gnm.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/testsuite/MDAnalysisTests/analysis/test_gnm.py b/testsuite/MDAnalysisTests/analysis/test_gnm.py index f658cd16c6f..9557278fdc6 100644 --- a/testsuite/MDAnalysisTests/analysis/test_gnm.py +++ b/testsuite/MDAnalysisTests/analysis/test_gnm.py @@ -83,7 +83,7 @@ def test_generate_kirchoff(universe): def test_gnm_SVD_fail(universe): gnm = mda.analysis.gnm.GNMAnalysis(universe) - # Initilize attributes like self._ts + # Initilize attributes like self._ts # necessary for print the warning gnm.run(stop=1) @@ -140,4 +140,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]) \ No newline at end of file + 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]) From 89b7a6b22b35f150f6aee7bca504ef2a0423bc63 Mon Sep 17 00:00:00 2001 From: Philip Loche Date: Wed, 28 Apr 2021 08:56:24 +0200 Subject: [PATCH 6/9] Add versionchanged notice --- package/MDAnalysis/analysis/gnm.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/package/MDAnalysis/analysis/gnm.py b/package/MDAnalysis/analysis/gnm.py index ce21f031124..6a3179ad87f 100644 --- a/package/MDAnalysis/analysis/gnm.py +++ b/package/MDAnalysis/analysis/gnm.py @@ -235,6 +235,9 @@ class GNMAnalysis(AnalysisBase): .. versionchanged:: 1.0.0 Changed `selection` keyword to `select` + + .. versionchanged:: 2.0.0 + Use :class:`~MDAnalysis.analysis.AnalysisBase` as parent class. """ def __init__(self, From b8322e5e9a02230a81de085c79d740331f26eaa8 Mon Sep 17 00:00:00 2001 From: Philip Loche Date: Wed, 28 Apr 2021 08:56:58 +0200 Subject: [PATCH 7/9] Add warning match --- testsuite/MDAnalysisTests/analysis/test_gnm.py | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/testsuite/MDAnalysisTests/analysis/test_gnm.py b/testsuite/MDAnalysisTests/analysis/test_gnm.py index 9557278fdc6..0bb25e1b4c7 100644 --- a/testsuite/MDAnalysisTests/analysis/test_gnm.py +++ b/testsuite/MDAnalysisTests/analysis/test_gnm.py @@ -82,15 +82,12 @@ def test_generate_kirchoff(universe): def test_gnm_SVD_fail(universe): - gnm = mda.analysis.gnm.GNMAnalysis(universe) - # Initilize attributes like self._ts - # necessary for print the warning - gnm.run(stop=1) - with patch.object(np.linalg, "svd") as np_load_mock: np_load_mock.side_effect = np.linalg.LinAlgError - with pytest.warns(UserWarning): - assert gnm._single_frame() is None + 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): From 6490aa8a3a4ce4c57a959a24ff51b8736edcfb19 Mon Sep 17 00:00:00 2001 From: Philip Loche Date: Wed, 28 Apr 2021 13:40:15 +0200 Subject: [PATCH 8/9] Fixed doc Co-authored-by: Irfan Alibay --- package/MDAnalysis/analysis/gnm.py | 1 + 1 file changed, 1 insertion(+) diff --git a/package/MDAnalysis/analysis/gnm.py b/package/MDAnalysis/analysis/gnm.py index 6a3179ad87f..986771bd90b 100644 --- a/package/MDAnalysis/analysis/gnm.py +++ b/package/MDAnalysis/analysis/gnm.py @@ -230,6 +230,7 @@ class GNMAnalysis(AnalysisBase): -------- :class:`closeContactGNMAnalysis` + .. versionchanged:: 0.16.0 Made :meth:`generate_output` a private method :meth:`_generate_output`. From c09bec25683908c3443e139feb15127527c11a79 Mon Sep 17 00:00:00 2001 From: Philip Loche Date: Wed, 28 Apr 2021 13:41:37 +0200 Subject: [PATCH 9/9] Added another versionchanged info --- package/MDAnalysis/analysis/gnm.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/package/MDAnalysis/analysis/gnm.py b/package/MDAnalysis/analysis/gnm.py index 986771bd90b..d4fd2700f34 100644 --- a/package/MDAnalysis/analysis/gnm.py +++ b/package/MDAnalysis/analysis/gnm.py @@ -388,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,