-
Notifications
You must be signed in to change notification settings - Fork 844
Analysis progmeter #892
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
Analysis progmeter #892
Changes from all commits
1480ac7
095f9b0
ba8c775
174042c
4c90171
d55a4a0
ba662ae
9755a9f
9edaa24
ffdf479
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 |
|---|---|---|
|
|
@@ -2,8 +2,8 @@ | |
| # vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4 | ||
| # | ||
| # MDAnalysis --- http://www.MDAnalysis.org | ||
| # Copyright (c) 2006-2015 Naveen Michaud-Agrawal, Elizabeth J. Denning, Oliver Beckstein | ||
| # and contributors (see AUTHORS for the full list) | ||
| # Copyright (c) 2006-2015 Naveen Michaud-Agrawal, Elizabeth J. Denning, Oliver | ||
| # Beckstein and contributors (see AUTHORS for the full list) | ||
| # | ||
| # Released under the GNU Public Licence, v2 or any higher version | ||
| # | ||
|
|
@@ -24,61 +24,116 @@ | |
| """ | ||
| from six.moves import range | ||
|
|
||
| import numpy as np | ||
| import logging | ||
| from MDAnalysis.lib.log import ProgressMeter | ||
|
|
||
| logger = logging.getLogger(__name__) | ||
|
|
||
|
|
||
| class AnalysisBase(object): | ||
| """Base class for defining multi frame analysis | ||
|
|
||
| The analysis base class is designed as a template for creating | ||
| multiframe analysis. | ||
|
|
||
| The class implements the following methods: | ||
|
|
||
| _setup_frames(trajectory, start=None, stop=None, step=None) | ||
| Pass a Reader object and define the desired iteration pattern | ||
| through the trajectory | ||
|
|
||
| run | ||
| The user facing run method. Calls the analysis methods | ||
| defined below | ||
|
|
||
| Your analysis can implement the following methods, which are | ||
| called from run: | ||
|
|
||
| _prepare | ||
| Called before iteration on the trajectory has begun. | ||
| Data structures can be set up at this time, however most | ||
| error checking should be done in the __init__ | ||
|
|
||
| _single_frame | ||
| Called after the trajectory is moved onto each new frame. | ||
|
|
||
| _conclude | ||
| Called once iteration on the trajectory is finished. | ||
| Apply normalisation and averaging to results here. | ||
| """Base class for defining multi frame analysis, it is designed as a | ||
| template for creating multiframe analysis. This class will automatically | ||
| take care of setting up the trajectory reader for iterating and offers to | ||
| show a progress meter. | ||
|
|
||
| To define a new Analysis, `AnalysisBase` needs to be subclassed | ||
| `_single_frame` must be defined. It is also possible to define | ||
| `_prepare` and `_conclude` for pre and post processing. See the example | ||
| below. | ||
|
|
||
| .. code-block:: python | ||
|
Member
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. This code block is now the definition of the There should be some text at the module level similar to the one that used to be here and formally describe the API.
Member
Author
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. how can we easily link to this? I thought it would be enough to make an
Member
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.
I suppose that works. Just remark somewhere above that this piece of code is the definition of what the Analysis API looks like at the moment. I was thinking about a document similar to the Trajectory API but to be honest, this PR is not really the place for that.
Anything that helps developers :-) – but I’d say we leave all of this for another PR, say, “Writing Analysis classes docs” (or have we already got something like that?). |
||
| class NewAnalysis(AnalysisBase): | ||
| def __init__(self, atomgroup, parameter, **kwargs): | ||
| super(NewAnalysis, self).__init__(atomgroup.universe.trajectory, | ||
| **kwargs) | ||
| self._parameter = parameter | ||
| self._ag = atomgroup | ||
|
|
||
| def _prepare(self): | ||
| # OPTIONAL | ||
| # Called before iteration on the trajectory has begun. | ||
| # Data structures can be set up at this time | ||
| self.result = [] | ||
|
|
||
| def _single_frame(self): | ||
| # REQUIRED | ||
| # Called after the trajectory is moved onto each new frame. | ||
| # store result of `some_function` for a single frame | ||
| self.result.append(some_function(self._ag, self._parameter)) | ||
|
|
||
| def _conclude(self): | ||
| # OPTIONAL | ||
| # Called once iteration on the trajectory is finished. | ||
| # Apply normalisation and averaging to results here. | ||
| self.result = np.asarray(self.result) / np.sum(self.result) | ||
|
|
||
| Afterwards the new analysis can be run like this. | ||
|
|
||
| .. code-block:: python | ||
| na = NewAnalysis(u.select_atoms('name CA'), 35).run() | ||
|
Member
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. I like this. |
||
| print(na.result) | ||
|
|
||
| """ | ||
| def __init__(self, trajectory, start=None, | ||
| stop=None, step=None, quiet=True): | ||
|
Member
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. Sorry for
Member
Author
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. Yeah we can do that. LIkely something we should do before 1.0.0. Can you open a bug for this. The deprecation is easy to do just tedious to catch all the instances where we use quiet. |
||
| """ | ||
| Parameters | ||
| ---------- | ||
| trajectory : mda.Reader | ||
| A trajectory Reader | ||
| start : int, optional | ||
| start frame of analysis | ||
| stop : int, optional | ||
| stop frame of analysis | ||
| step : int, optional | ||
| number of frames to skip between each analysed frame | ||
| quiet : bool, optional | ||
| Turn off verbosity | ||
| """ | ||
| self._quiet = quiet | ||
| self._setup_frames(trajectory, start, stop, step) | ||
|
|
||
| def _setup_frames(self, trajectory, start=None, | ||
| stop=None, step=None): | ||
| """ | ||
| Pass a Reader object and define the desired iteration pattern | ||
| through the trajectory | ||
|
|
||
| Parameters | ||
| ---------- | ||
| trajectory : mda.Reader | ||
| A trajectory Reader | ||
| start : int, optional | ||
| start frame of analysis | ||
| stop : int, optional | ||
| stop frame of analysis | ||
| step : int, optional | ||
| number of frames to skip between each analysed frame | ||
| """ | ||
| self._trajectory = trajectory | ||
| start, stop, step = trajectory.check_slice_indices( | ||
| start, stop, step) | ||
| self.start = start | ||
| self.stop = stop | ||
| self.step = step | ||
| self.n_frames = len(range(start, stop, step)) | ||
| interval = int(self.n_frames // 100) | ||
| if interval == 0: | ||
| interval = 1 | ||
|
|
||
| # ensure _quiet is set when __init__ wasn't called, this is to not | ||
| # break pre 0.16.0 API usage of AnalysisBase | ||
| if not hasattr(self, '_quiet'): | ||
| self._quiet = True | ||
| self._pm = ProgressMeter(self.n_frames if self.n_frames else 1, | ||
| interval=interval, quiet=self._quiet) | ||
|
|
||
| def _single_frame(self): | ||
| """Calculate data from a single frame of trajectory | ||
|
|
||
| Don't worry about normalising, just deal with a single frame. | ||
| """ | ||
| pass | ||
| raise NotImplementedError("Only implemented in child classes") | ||
|
|
||
| def _prepare(self): | ||
| """Set things up before the analysis loop begins""" | ||
|
|
@@ -91,7 +146,7 @@ def _conclude(self): | |
| """ | ||
| pass | ||
|
|
||
| def run(self, **kwargs): | ||
| def run(self): | ||
| """Perform the calculation""" | ||
| logger.info("Starting preparation") | ||
| self._prepare() | ||
|
|
@@ -101,5 +156,7 @@ def run(self, **kwargs): | |
| self._ts = ts | ||
| # logger.info("--> Doing frame {} of {}".format(i+1, self.n_frames)) | ||
| self._single_frame() | ||
| self._pm.echo(self._frame_index) | ||
| logger.info("Finishing up") | ||
| self._conclude() | ||
| return self | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't this be when quiet=True?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is correct. You are thinking of
verbose=Truewhich is the normal way people turn on logging and output. For some reason MDAnalysis has decided in the past to rather go with the wordquietand thereFalsewould say the function can print and log stuff for me,There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah right yeah, it's backwards to what I expect, ok cool