-
Notifications
You must be signed in to change notification settings - Fork 824
Analysis - Linear Density module #670
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
Merged
richardjgowers
merged 10 commits into
MDAnalysis:develop
from
mattiafelice-palermo:feature-LinearDensity
Feb 11, 2016
Merged
Changes from all commits
Commits
Show all changes
10 commits
Select commit
Hold shift + click to select a range
b6dfa88
Added lineardensity module
mattiafelice-palermo eadb51a
Fixed: np arrays instead of lists for charges and masses, correct imp…
mattiafelice-palermo f38bc45
Fixed improper use of list comprehension; Added docstrings
mattiafelice-palermo a677115
Added standard header
mattiafelice-palermo 5605394
Created stub rst for the analysis module and added link under Volumet…
mattiafelice-palermo a3a9550
Added myself to authors
mattiafelice-palermo 38d09a2
Modified changelog
mattiafelice-palermo 90c574c
Lineardensity does not take universe as argument anymore and is compa…
mattiafelice-palermo fd44b72
Test added
mattiafelice-palermo 0f0aefa
Trajectory name taken from variable filename and not dcdfilename, rem…
mattiafelice-palermo File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,256 @@ | ||
| # -*- Mode: python; tab-width: 4; indent-tabs-mode:nil; coding:utf-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) | ||
| # | ||
| # Released under the GNU Public Licence, v2 or any higher version | ||
| # | ||
| # Please cite your use of MDAnalysis in published work: | ||
| # | ||
| # N. Michaud-Agrawal, E. J. Denning, T. B. Woolf, and O. Beckstein. | ||
| # MDAnalysis: A Toolkit for the Analysis of Molecular Dynamics Simulations. | ||
| # J. Comput. Chem. 32 (2011), 2319--2327, doi:10.1002/jcc.21787 | ||
| # | ||
|
|
||
| """ | ||
| Linear Density --- :mod:`MDAnalysis.analysis.lineardensity` | ||
| =========================================================== | ||
|
|
||
| A tool to compute mass and charge density profiles along the three | ||
| cartesian axes of the simulation cell. Works only for orthorombic, | ||
| fixed volume cells (thus for simulations in canonical NVT ensemble). | ||
| """ | ||
| from __future__ import division | ||
|
|
||
| import os.path as path | ||
| import numpy as np | ||
|
|
||
| from MDAnalysis.analysis.base import AnalysisBase | ||
|
|
||
| class LinearDensity(AnalysisBase): | ||
| """Linear density profile | ||
| LinearDensity(selection, grouping='atoms', binsize=0.25) | ||
|
|
||
| Parameters | ||
| ---------- | ||
| selection : `AtomGroup` object | ||
| Any atomgroup | ||
|
|
||
| Keywords | ||
| -------- | ||
| grouping : str {'atoms', 'residues', 'segments', 'fragments'} | ||
| Density profiles will be computed on the center of geometry | ||
| of a selected group of atoms ['atoms'] | ||
|
|
||
| binsize : float | ||
| Bin width in Angstrom used to build linear density | ||
| histograms. Defines the resolution of the resulting density | ||
| profile (smaller --> higher resolution) [0.25] | ||
|
|
||
| start : int | ||
| The frame to start at [0] | ||
| stop : int | ||
| The frame to end at [-1] | ||
| step : int | ||
| The step size through the trajectory in frames [0] | ||
|
|
||
| Example | ||
| ------- | ||
| First create a LinearDensity object by supplying a selection, | ||
| then use the `run` method: | ||
| ldens = LinearDensity(selection) | ||
| ldens.run() | ||
|
|
||
| Density profiles can be written to file through the `save` method: | ||
| ldens.save(description='mydensprof', form='txt') | ||
| which will output the density profiles in a file named | ||
| <trajectory_filename>.mydensprof_<grouping>.ldens | ||
| Results can be saved in npz format by specifying `form='npz'` | ||
|
|
||
| .. versionadded:: 0.14.0 | ||
| """ | ||
| def __init__(self, selection, grouping='atoms', binsize=0.25, | ||
| start=None, stop=None, step=None): | ||
| self._ags = [selection] # allows use of run(parallel=True) | ||
| self._universe = selection.universe | ||
| self._setup_frames(self._universe.trajectory, start, stop, step) | ||
|
|
||
| self.binsize = binsize | ||
|
|
||
| # group of atoms on which to compute the COM (same as used in | ||
| # AtomGroup.wrap()) | ||
| self.grouping = grouping | ||
|
|
||
| # Dictionary containing results | ||
| self.results = {'x': {'dim': 0}, 'y': {'dim': 1}, 'z': {'dim': 2}} | ||
| # Box sides | ||
| self.dimensions = self._universe.dimensions[:3] | ||
| self.volume = np.prod(self.dimensions) | ||
| bins = (self.dimensions // self.binsize).astype(int) # number of bins | ||
|
|
||
| # Here we choose a number of bins of the largest cell side so that | ||
| # x, y and z values can use the same "coord" column in the output file | ||
| self.nbins = bins.max() | ||
| slices_vol = self.volume/bins | ||
|
|
||
| self.keys = ['pos', 'pos_std', 'char', 'char_std'] | ||
|
|
||
| # Initialize results array with zeros | ||
| for dim in self.results: | ||
| idx = self.results[dim]['dim'] | ||
| self.results[dim].update({'slice volume': slices_vol[idx]}) | ||
| for key in self.keys: | ||
| self.results[dim].update({key: np.zeros(self.nbins)}) | ||
|
|
||
| # Variables later defined in _prepare() method | ||
| self.masses = None | ||
| self.charges = None | ||
| self.totalmass = None | ||
|
|
||
| def _prepare(self): | ||
| # group must be a local variable, otherwise there will be | ||
| # issues with parallelization | ||
| group = getattr(self._ags[0], self.grouping) | ||
|
|
||
| # Get masses and charges for the selection | ||
| try: # in case it's not an atom | ||
| self.masses = np.array([elem.total_mass() for elem in group]) | ||
| self.charges = np.array([elem.total_charge() for elem in group]) | ||
| except AttributeError: # much much faster for atoms | ||
| self.masses = self._ags[0].masses | ||
| self.charges = self._ags[0].charges | ||
|
|
||
| self.totalmass = np.sum(self.masses) | ||
|
|
||
| def _single_frame(self): | ||
| self.group = getattr(self._ags[0], self.grouping) | ||
| self._ags[0].wrap(compound=self.grouping) | ||
|
|
||
| # Find position of atom/group of atoms | ||
| if self.grouping == 'atoms': | ||
| positions = self._ags[0].positions # faster for atoms | ||
| else: | ||
| positions = np.array([elem.centroid() for elem in self.group]) # COM for res/frag/etc | ||
|
|
||
| for dim in ['x', 'y', 'z']: | ||
| idx = self.results[dim]['dim'] | ||
|
|
||
| key = 'pos' | ||
| key_std = 'pos_std' | ||
| # histogram for positions weighted on masses | ||
| hist, _ = np.histogram(positions[:, idx], weights=self.masses, | ||
| bins=self.nbins, range=(0.0, max(self.dimensions))) | ||
|
|
||
| self.results[dim][key] += hist | ||
| self.results[dim][key_std] += np.square(hist) | ||
|
|
||
| key = 'char' | ||
| key_std = 'char_std' | ||
| # histogram for positions weighted on charges | ||
| hist, _ = np.histogram(positions[:, idx], weights=self.charges, | ||
| bins=self.nbins, range=(0.0, max(self.dimensions))) | ||
|
|
||
| self.results[dim][key] += hist | ||
| self.results[dim][key_std] += np.square(hist) | ||
|
|
||
| def _conclude(self): | ||
| k = 6.022e-1 # divide by avodagro and convert from A3 to cm3 | ||
|
|
||
| # Average results over the number of configurations | ||
| for dim in ['x', 'y', 'z']: | ||
| for key in ['pos', 'pos_std', 'char', 'char_std']: | ||
| self.results[dim][key] /= self.nframes | ||
| # Compute standard deviation for the error | ||
| self.results[dim]['pos_std'] = np.sqrt(self.results[dim]['pos_std'] | ||
| - np.square(self.results[dim]['pos'])) | ||
| self.results[dim]['char_std'] = np.sqrt(self.results[dim]['char_std'] | ||
| - np.square(self.results[dim]['char'])) | ||
|
|
||
| for dim in ['x', 'y', 'z']: | ||
| self.results[dim]['pos'] /= (self.results[dim]['slice volume']*k) | ||
| self.results[dim]['char'] /= (self.results[dim]['slice volume']*k) | ||
| self.results[dim]['pos_std'] /= (self.results[dim]['slice volume']*k) | ||
| self.results[dim]['char_std'] /= (self.results[dim]['slice volume']*k) | ||
|
|
||
| def save(self, description='', form='txt'): | ||
| """ Save density profile to file | ||
| Allows to save the density profile to either a ASCII txt file or a | ||
| binary numpy npz file. Output file has extension 'ldens' and begins | ||
| with the name of the trajectory file. | ||
|
|
||
| Keywords | ||
| -------- | ||
| description : str | ||
| An arbitrary description added to the output filename. Can be useful | ||
| form : str {'txt', 'npz'} | ||
| Format of the output. 'txt' will generate an ASCII text file while 'npz' | ||
| will produce a numpy binary file. | ||
|
|
||
| Example | ||
| ------- | ||
| After initializing and running a `LinearDensity` object, results can be written | ||
| to file as follows: | ||
| ldens.save(description='mydensprof', form='txt') | ||
| which will output the linear density profiles in a file named | ||
| <trajectory_filename>.mydensprof_<grouping>.ldens | ||
| """ | ||
| # Take root of trajectory filename for output file naming | ||
| trajname = path.splitext(path.basename(self._universe.trajectory.filename))[0] | ||
| # additional string for naming the output file | ||
| description = description + "_" + str(self.grouping) | ||
| filename = trajname+"." + description + ".ldens" | ||
|
|
||
| if form is 'txt': | ||
| self._savetxt(filename) | ||
| elif form is 'npz': | ||
| self._savez(filename) | ||
| else: | ||
| raise ValueError('form argument must be either txt or npz') | ||
|
|
||
| def _savetxt(self, filename): | ||
| bins = np.linspace(0.0, max(self.dimensions), num=self.nbins) | ||
|
|
||
| # Create list of results which will be output | ||
| output = [bins] | ||
|
|
||
| for dim in ['x', 'y', 'z']: | ||
| output.append(self.results[dim]['pos']) | ||
| output.append(self.results[dim]['pos_std']) | ||
|
|
||
| for dim in ['x', 'y', 'z']: | ||
| output.append(self.results[dim]['char']) | ||
| output.append(self.results[dim]['char_std']) | ||
|
|
||
| density = self.totalmass/self.volume | ||
| header = "1 coord [Ang] 2-7 mass density (x,sx,y,sz,z,sz) [g/cm^3]" + \ | ||
| "8-13 charge density (x,sx,y,sz,z,sz) [e/A^3]\n Average density: "\ | ||
| + str(density) + " g/cm3" | ||
| np.savetxt(filename, np.column_stack(output), fmt='%10.5f', header=header) | ||
|
|
||
| def _savez(self, filename): | ||
| bins = np.linspace(0.0, max(self.dimensions), num=self.nbins) | ||
| dictionary = {'bins': bins} | ||
|
|
||
| for dim in self.results: | ||
| self.results[dim].pop('dim') | ||
| self.results[dim].pop('slice volume') | ||
| for key in self.results[dim]: | ||
| dictionary[dim+"_"+key] = self.results[dim][key] | ||
|
|
||
| np.savez(filename, **dictionary) | ||
|
|
||
| def _add_other_results(self, other): | ||
| # For parallel analysis | ||
| results = self.results | ||
| for dim in ['x', 'y', 'z']: | ||
| key = 'pos' | ||
| key_std = 'pos_std' | ||
| results[dim][key] += other[dim][key] | ||
| results[dim][key_std] += other[dim][key_std] | ||
|
|
||
| key = 'char' | ||
| key_std = 'char_std' | ||
| results[dim][key] += other[dim][key] | ||
| results[dim][key_std] += other[dim][key_std] | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
2 changes: 2 additions & 0 deletions
2
package/doc/sphinx/source/documentation_pages/analysis/lineardensity.rst
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| .. automodule:: MDAnalysis.analysis.lineardensity | ||
|
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -106,6 +106,7 @@ Volumetric analysis | |
| :maxdepth: 1 | ||
|
|
||
| analysis/density | ||
| analysis/lineardensity | ||
| analysis/waterdynamics | ||
|
|
||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,42 @@ | ||
| # -*- Mode: python; tab-width: 4; indent-tabs-mode:nil; coding:utf-8 -*- | ||
| # vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4 fileencoding=utf-8 | ||
| # | ||
| # 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) | ||
| # | ||
| # Released under the GNU Public Licence, v2 or any higher version | ||
| # | ||
| # Please cite your use of MDAnalysis in published work: | ||
| # | ||
| # N. Michaud-Agrawal, E. J. Denning, T. B. Woolf, and O. Beckstein. | ||
| # MDAnalysis: A Toolkit for the Analysis of Molecular Dynamics Simulations. | ||
| # J. Comput. Chem. 32 (2011), 2319--2327, doi:10.1002/jcc.21787 | ||
| # | ||
| import MDAnalysis as mda | ||
| import numpy as np | ||
|
|
||
| from MDAnalysisTests.datafiles import waterPSF, waterDCD | ||
| from MDAnalysis.analysis.lineardensity import LinearDensity | ||
| from numpy.testing import TestCase, assert_allclose | ||
|
|
||
| class TestLinearDensity(TestCase): | ||
| def setUp(self): | ||
| self.universe = mda.Universe(waterPSF, waterDCD) | ||
| self.sel_string = 'all' | ||
| self.selection = self.universe.select_atoms(self.sel_string) | ||
|
|
||
| self.xpos = np.array([ 0., 0., 0., 0.0072334, 0.00473299, 0., | ||
| 0., 0., 0., 0. ]) | ||
|
|
||
| def test_serial(self): | ||
| ld = LinearDensity(self.selection, binsize=5) | ||
| ld.run() | ||
| assert_allclose(self.xpos, ld.results['x']['pos'], rtol=1e-6, atol=0) | ||
|
|
||
| # def test_parallel(self): | ||
| # ld = LinearDensity(self.universe, self.selection, binsize=5) | ||
| # ld.run(parallel=True) | ||
| # assert_equal(self.xpos, ld.results['x']['pos']) | ||
|
|
||
|
|
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
Order your imports as:
With a blank line between each