1# -*- Mode: python; tab-width: 4; indent-tabs-mode:nil; coding:utf-8 -*-
2# vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4 fileencoding=utf-8
3#
4# MDAnalysis --- https://www.mdanalysis.org
5# Copyright (c) 2006-2017 The MDAnalysis Development Team and contributors
6# (see the file AUTHORS for the full list of names)
7#
8# Released under the GNU Public Licence, v2 or any higher version
9#
10# Please cite your use of MDAnalysis in published work:
11#
12# R. J. Gowers, M. Linke, J. Barnoud, T. J. E. Reddy, M. N. Melo, S. L. Seyler,
13# D. L. Dotson, J. Domanski, S. Buchoux, I. M. Kenney, and O. Beckstein.
14# MDAnalysis: A Python package for the rapid analysis of molecular dynamics
15# simulations. In S. Benthall and S. Rostrup editors, Proceedings of the 15th
16# Python in Science Conference, pages 102-109, Austin, TX, 2016. SciPy.
17#
18# N. Michaud-Agrawal, E. J. Denning, T. B. Woolf, and O. Beckstein.
19# MDAnalysis: A Toolkit for the Analysis of Molecular Dynamics Simulations.
20# J. Comput. Chem. 32 (2011), 2319--2327, doi:10.1002/jcc.21787
21#
22from __future__ import division, absolute_import
23
24import pytest
25from six.moves import range
26
27import numpy as np
28
29from numpy.testing import assert_equal
30
31import MDAnalysis as mda
32from MDAnalysis.analysis import base
33
34from MDAnalysisTests.datafiles import PSF, DCD
35from MDAnalysisTests.util import no_deprecated_call
36
37
38class FrameAnalysis(base.AnalysisBase):
39    """Just grabs frame numbers of frames it goes over"""
40    def __init__(self, reader, **kwargs):
41        super(FrameAnalysis, self).__init__(reader, **kwargs)
42        self.traj = reader
43        self.frames = []
44
45    def _single_frame(self):
46        self.frames.append(self._ts.frame)
47
48
49class IncompleteAnalysis(base.AnalysisBase):
50    def __init__(self, reader, **kwargs):
51        super(IncompleteAnalysis, self).__init__(reader, **kwargs)
52
53
54class OldAPIAnalysis(base.AnalysisBase):
55    """for version 0.15.0"""
56    def __init__(self, reader, **kwargs):
57        self._setup_frames(reader, **kwargs)
58
59    def _single_frame(self):
60        pass
61
62
63@pytest.fixture()
64def u():
65    return mda.Universe(PSF, DCD)
66
67
68def test_default(u):
69    an = FrameAnalysis(u.trajectory).run()
70    assert an.n_frames == len(u.trajectory)
71    assert_equal(an.frames, list(range(len(u.trajectory))))
72
73
74def test_start(u):
75    an = FrameAnalysis(u.trajectory).run(start=20)
76    assert an.n_frames == len(u.trajectory) - 20
77    assert_equal(an.frames, list(range(20, len(u.trajectory))))
78
79
80def test_stop(u):
81    an = FrameAnalysis(u.trajectory).run(stop=20)
82    assert an.n_frames == 20
83    assert_equal(an.frames, list(range(20)))
84
85
86def test_step(u):
87    an = FrameAnalysis(u.trajectory).run(step=20)
88    assert an.n_frames == 5
89    assert_equal(an.frames, list(range(98))[::20])
90
91
92def test_verbose(u):
93    a = FrameAnalysis(u.trajectory, verbose=True)
94    assert a._verbose
95
96
97def test_incomplete_defined_analysis(u):
98    with pytest.raises(NotImplementedError):
99        IncompleteAnalysis(u.trajectory).run()
100
101
102def test_old_api(u):
103    OldAPIAnalysis(u.trajectory).run()
104
105
106def test_filter_baseanalysis_kwargs_VE():
107    def bad_f(mobile, verbose=2):
108        pass
109
110    kwargs = {'step': 3, 'foo': None}
111
112    with pytest.raises(ValueError):
113        base._filter_baseanalysis_kwargs(bad_f, kwargs)
114
115
116def test_filter_baseanalysis_kwargs():
117    def good_f(mobile, ref):
118        pass
119
120    kwargs = {'step': 3, 'foo': None}
121
122    base_kwargs, kwargs = base._filter_baseanalysis_kwargs(good_f, kwargs)
123
124    assert 2 == len(kwargs)
125    assert kwargs['foo'] == None
126
127    assert len(base_kwargs) == 1
128    assert base_kwargs['verbose'] is False
129
130
131def simple_function(mobile):
132    return mobile.center_of_geometry()
133
134
135def test_AnalysisFromFunction():
136    u = mda.Universe(PSF, DCD)
137    step = 2
138    ana1 = base.AnalysisFromFunction(
139        simple_function, mobile=u.atoms).run(step=step)
140    ana2 = base.AnalysisFromFunction(simple_function, u.atoms).run(step=step)
141    ana3 = base.AnalysisFromFunction(
142        simple_function, u.trajectory, u.atoms).run(step=step)
143
144    results = []
145    for ts in u.trajectory[::step]:
146        results.append(simple_function(u.atoms))
147    results = np.asarray(results)
148
149    for ana in (ana1, ana2, ana3):
150        assert_equal(results, ana.results)
151
152
153def test_analysis_class():
154    ana_class = base.analysis_class(simple_function)
155    assert issubclass(ana_class, base.AnalysisBase)
156    assert issubclass(ana_class, base.AnalysisFromFunction)
157
158    u = mda.Universe(PSF, DCD)
159    step = 2
160    ana = ana_class(u.atoms).run(step=step)
161
162    results = []
163    for ts in u.trajectory[::step]:
164        results.append(simple_function(u.atoms))
165    results = np.asarray(results)
166
167    assert_equal(results, ana.results)
168    with pytest.raises(ValueError):
169        ana_class(2)
170
171
172def test_analysis_class_decorator():
173    # Issue #1511
174    # analysis_class should not raise
175    # a DeprecationWarning
176    u = mda.Universe(PSF, DCD)
177
178    def distance(a, b):
179        return np.linalg.norm((a.centroid() - b.centroid()))
180
181    Distances = base.analysis_class(distance)
182
183    with no_deprecated_call():
184        d = Distances(u.atoms[:10], u.atoms[10:20]).run()
185
186@pytest.mark.parametrize('param', ['start', 'stop', 'step'])
187def test_runargs_deprecation(param):
188    u = mda.Universe(PSF, DCD)
189
190    class NothingAnalysis(base.AnalysisBase):
191        def _single_frame(self):
192            self.results = []
193
194    with pytest.warns(DeprecationWarning):
195        ana = NothingAnalysis(u.trajectory, **{param: 10})
196
197    ana.run()
198