-
Notifications
You must be signed in to change notification settings - Fork 839
Parallelize lindensity #5007
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
Parallelize lindensity #5007
Changes from all commits
2ab2bf5
164790d
cea4f7d
3151d79
31427a2
02dd5d6
551914e
09d1a15
12b487d
cc66edc
56e771e
c767ce7
2d6a33c
b468be9
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 | ||||
|---|---|---|---|---|---|---|
|
|
@@ -36,6 +36,7 @@ | |||||
| from MDAnalysis.analysis.base import AnalysisBase, Results | ||||||
| from MDAnalysis.units import constants | ||||||
| from MDAnalysis.lib.util import deprecate | ||||||
| from MDAnalysis.analysis.results import ResultsGroup | ||||||
|
|
||||||
|
|
||||||
| # TODO: Remove in version 3.0.0 | ||||||
|
|
@@ -188,6 +189,10 @@ class LinearDensity(AnalysisBase): | |||||
| It contains the bin edges of the histrogram bins for calculated | ||||||
| densities and can be used for easier plotting of histogram data. | ||||||
|
|
||||||
| .. versionchanged:: 2.10.0 | ||||||
| * Introduced :meth:`get_supported_backends` allowing for parallel execution | ||||||
| on :mod:`multiprocessing` and :mod:`dask` backends. | ||||||
| * Removed undocumented and unused attribute :attr:`totalmass`. | ||||||
|
|
||||||
| .. deprecated:: 2.2.0 | ||||||
| The `results` dictionary has been changed and the attributes | ||||||
|
|
@@ -198,6 +203,16 @@ class LinearDensity(AnalysisBase): | |||||
| and :attr:`results.x.charge_density_stddev` instead. | ||||||
| """ | ||||||
|
|
||||||
| _analysis_algorithm_is_parallelizable = True | ||||||
|
|
||||||
| @classmethod | ||||||
| def get_supported_backends(cls): | ||||||
| return ( | ||||||
| "serial", | ||||||
| "multiprocessing", | ||||||
| "dask", | ||||||
| ) | ||||||
|
|
||||||
| def __init__(self, select, grouping="atoms", binsize=0.25, **kwargs): | ||||||
| super(LinearDensity, self).__init__( | ||||||
| select.universe.trajectory, **kwargs | ||||||
|
|
@@ -242,13 +257,56 @@ def __init__(self, select, grouping="atoms", binsize=0.25, **kwargs): | |||||
| for key in self.keys: | ||||||
| self.results[dim][key] = np.zeros(self.nbins) | ||||||
|
|
||||||
| # Variables later defined in _single_frame() method | ||||||
| self.masses = None | ||||||
| self.charges = None | ||||||
| self.totalmass = None | ||||||
| # Get masses and charges for the selection (e.g. UpdatingAtomGroup) | ||||||
| if self.grouping == "atoms": | ||||||
| self.masses = self._ags[0].masses | ||||||
| self.charges = self._ags[0].charges | ||||||
|
|
||||||
| elif self.grouping in ["residues", "segments", "fragments"]: | ||||||
| self.masses = self._ags[0].total_mass(compound=self.grouping) | ||||||
| self.charges = self._ags[0].total_charge(compound=self.grouping) | ||||||
|
|
||||||
| else: | ||||||
| raise AttributeError( | ||||||
| f"{self.grouping} is not a valid value for grouping." | ||||||
| ) | ||||||
|
tulga-rdn marked this conversation as resolved.
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. Can you add self.totalmass = np.sum(self.masses)here?
Contributor
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. Also fails the tests
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. May be for updating atomgroups. Ok.
Contributor
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. Sorry, this one works, I was testing on an old iteration of the code |
||||||
|
|
||||||
| @staticmethod | ||||||
| def _custom_aggregator(results): | ||||||
| # NB: the *stddev values here are not the standard deviation, | ||||||
| # but the variance. The stddev is calculated in _conclude() | ||||||
|
PicoCentauri marked this conversation as resolved.
|
||||||
| mass_density = np.sum( | ||||||
| [entry["mass_density"] for entry in results], axis=0 | ||||||
| ) | ||||||
| mass_density_stddev = np.sum( | ||||||
| [entry["mass_density_stddev"] for entry in results], axis=0 | ||||||
| ) | ||||||
| charge_density = np.sum( | ||||||
| [entry["charge_density"] for entry in results], axis=0 | ||||||
| ) | ||||||
| charge_density_stddev = np.sum( | ||||||
| [entry["charge_density_stddev"] for entry in results], axis=0 | ||||||
| ) | ||||||
| return Results( | ||||||
| dim=results[0]["dim"], | ||||||
| slice_volume=results[0]["slice_volume"], | ||||||
| hist_bin_edges=results[0]["hist_bin_edges"], | ||||||
| mass_density=mass_density, | ||||||
| mass_density_stddev=mass_density_stddev, | ||||||
| charge_density=charge_density, | ||||||
| charge_density_stddev=charge_density_stddev, | ||||||
| ) | ||||||
|
|
||||||
| def _get_aggregator(self): | ||||||
| return ResultsGroup( | ||||||
| lookup={ | ||||||
| "x": self._custom_aggregator, | ||||||
| "y": self._custom_aggregator, | ||||||
| "z": self._custom_aggregator, | ||||||
| } | ||||||
| ) | ||||||
|
|
||||||
| def _single_frame(self): | ||||||
| # Get masses and charges for the selection | ||||||
|
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. You added all the mass/charge extraction to You should then also move the Can you please check that this will still work and pass the tests? (Or do you see a problem arising by doing this?)
Contributor
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. No, it doesn't pass the tests :(
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. Thanks for testing. I also read the line in the versionchanged 2.2.0 LinearDensity now works with updating atom groups. — for this to work, we do need to keep the masses/charges extraction in I do not quite get why the parallel analysis fails when you initialize them to
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.
Suggested change
Contributor
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. Done |
||||||
| if self.grouping == "atoms": | ||||||
| self.masses = self._ags[0].masses | ||||||
| self.charges = self._ags[0].charges | ||||||
|
|
@@ -262,11 +320,8 @@ def _single_frame(self): | |||||
| f"{self.grouping} is not a valid value for grouping." | ||||||
| ) | ||||||
|
|
||||||
| self.totalmass = np.sum(self.masses) | ||||||
|
|
||||||
| 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 | ||||||
|
|
||||||
Uh oh!
There was an error while loading. Please reload this page.