Skip to content

Instantly share code, notes, and snippets.

@dotsdl
Created December 9, 2016 22:41
Show Gist options
  • Save dotsdl/b93f9150d8d57004165e5ae899f66dbd to your computer and use it in GitHub Desktop.
Save dotsdl/b93f9150d8d57004165e5ae899f66dbd to your computer and use it in GitHub Desktop.
Testing out proposed updating AtomGroups in MDAnalysis-0.16.0-dev0
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Trying out `UpdatingAtomGroup`s, a feature being proposed for inclusion into 0.16.0"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"import MDAnalysis as mda\n",
"from MDAnalysisTests.datafiles import GRO, XTC"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"/home/alter/Library/mdanalysis/MDAnalysis/package/MDAnalysis/topology/guessers.py:54: UserWarning: Failed to guess the mass for the following atom types: M\n",
" \"\".format(', '.join(misses)))\n"
]
}
],
"source": [
"u = mda.Universe(GRO, XTC)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We can get `UpdatingAtomGroup`s from `select_atoms`:"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"ag = u.select_atoms('around 5 name CA', updating=True)"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"<UpdatingAtomGroup with 4990 atoms>"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"ag"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"This applies the selection object against the source `AtomGroup`, in this case `u.atoms`, each time its attributes are accessed if the trajectory frame has changed:"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"[4990, 5030, 4985, 5042, 5041, 5037, 5019, 4970, 4998, 4985]"
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"[ag.n_atoms for ts in u.trajectory]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Doing slicing on an `UpdatingAtomGroup` yields an `AtomGroup`:"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"<AtomGroup with 258 atoms>"
]
},
"execution_count": 6,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"ag[ag.types == 'N']"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"An `UpdatingAtomGroup` obtained from an `UpdatingAtomGroup` updates if its base `UpdatingAtomGroup` updates:"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"ag2 = ag.select_atoms('type N O', updating=True)"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"[1076, 1084, 1061, 1095, 1085, 1098, 1085, 1074, 1077, 1080]"
]
},
"execution_count": 8,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"[ag2.n_atoms for ts in u.trajectory]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"But does this extend downward into another group?"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"ag3 = ag2.select_atoms('around 5 global name CA', updating=True)"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"[1076, 1084, 1061, 1095, 1085, 1098, 1085, 1074, 1077, 1080]"
]
},
"execution_count": 10,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"[ag3.n_atoms for ts in u.trajectory]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Looks like it. We can test against the equivalent usage without using `UpdatingAtomGroups`:"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"[1076, 1084, 1061, 1095, 1085, 1098, 1085, 1074, 1077, 1080]"
]
},
"execution_count": 11,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"[u.select_atoms('(around 5 name CA)').select_atoms('(type N O)').select_atoms('around 5 global name CA').n_atoms for ts in u.trajectory]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"How does this work? Each `UpdatingAtomGroup` knows which `AtomGroup` it came from:"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"<UpdatingAtomGroup with 4990 atoms>"
]
},
"execution_count": 13,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"ag2._base_group"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"I get the bad feeling that having `AtomGroups` chained together as this scheme does, though cool, will make parallelization with these either really painful, really fragile, or both. Not sure I'd want to maintain that kind of functionality and deal with user issues with it. I much prefer AtomGroups whose state is as self-contained and simple as possible, as base `AtomGroup` is (even though most of its state is contained in the `Universe` itself)."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We can get the same effect as this scheme by just holding on to the selection and re-applying it. Though perhaps not as aesthetically pleasing, it's\n",
"\n",
"1. more explicit\n",
"2. far simpler underneath the hood\n",
"3. shouldn't cause (the same) issues with parallelization"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"[4990, 5030, 4985, 5042, 5041, 5037, 5019, 4970, 4998, 4985]"
]
},
"execution_count": 12,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"[u.select_atoms('around 5 name CA').n_atoms for ts in u.trajectory]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## what about making an updating selection out of a non-updating one?"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"You can presumably make an updating selection out of one that isn't updating:"
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"ag_non = u.select_atoms('around 5 name CA')"
]
},
{
"cell_type": "code",
"execution_count": 16,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"False"
]
},
"execution_count": 16,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"ag_non.updating"
]
},
{
"cell_type": "code",
"execution_count": 17,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"ag_non.updating = True"
]
},
{
"cell_type": "code",
"execution_count": 18,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"<UpdatingAtomGroup with 4990 atoms>"
]
},
"execution_count": 18,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"ag_non"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The information needed to apply the selection is held onto by the `AtomGroup`:"
]
},
{
"cell_type": "code",
"execution_count": 19,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"(<MDAnalysis.core.selection.AroundSelection at 0x7fe89aeb71d0>,)"
]
},
"execution_count": 19,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"ag_non._selections"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"...I don't like that the AtomGroup, even non-updating ones, are now heavier, frankly."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"What happens if I get a `ResidueGroup`, then an `AtomGroup`, from my `UpdatingAtomGroup`?"
]
},
{
"cell_type": "code",
"execution_count": 20,
"metadata": {
"collapsed": false
},
"outputs": [
{
"ename": "AttributeError",
"evalue": "AtomGroup has no attribute _selections",
"output_type": "error",
"traceback": [
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[0;31mAttributeError\u001b[0m Traceback (most recent call last)",
"\u001b[0;32m<ipython-input-20-4b918d7f547a>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mag_non\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mresidues\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0matoms\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_selections\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
"\u001b[0;32m/home/alter/Library/mdanalysis/MDAnalysis/package/MDAnalysis/core/groups.pyc\u001b[0m in \u001b[0;36m__getattr__\u001b[0;34m(self, attr)\u001b[0m\n\u001b[1;32m 922\u001b[0m \u001b[0;32mpass\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 923\u001b[0m raise AttributeError(\"{cls} has no attribute {attr}\".format(\n\u001b[0;32m--> 924\u001b[0;31m cls=self.__class__.__name__, attr=attr))\n\u001b[0m\u001b[1;32m 925\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 926\u001b[0m \u001b[0;34m@\u001b[0m\u001b[0mproperty\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;31mAttributeError\u001b[0m: AtomGroup has no attribute _selections"
]
}
],
"source": [
"ag_non.residues.atoms._selections"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"so not all AtomGroups can be made into an `UpdatingAtomGroup`. I think this amounts to interface shear, and I don't think it's something we should do."
]
},
{
"cell_type": "code",
"execution_count": 21,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"ag_hmm = ag_non.residues.atoms"
]
},
{
"cell_type": "code",
"execution_count": 22,
"metadata": {
"collapsed": false
},
"outputs": [
{
"ename": "TypeError",
"evalue": "Attempted to make <class 'MDAnalysis.core.groups.AtomGroup'> instance dynamically updating, but it does not seem to have originated from a 'select_atoms' selection (it lacks '_base_group', '_selections', and '_lastupdate' attributes).",
"output_type": "error",
"traceback": [
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)",
"\u001b[0;32m<ipython-input-22-c2c8810e3c81>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mag_hmm\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mupdating\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mTrue\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
"\u001b[0;32m/home/alter/Library/mdanalysis/MDAnalysis/package/MDAnalysis/core/groups.pyc\u001b[0m in \u001b[0;36mupdating\u001b[0;34m(self, value)\u001b[0m\n\u001b[1;32m 1577\u001b[0m \u001b[0;34m\"(it lacks '_base_group', '_selections', and \"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1578\u001b[0m \u001b[0;34m\"'_lastupdate' attributes).\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 1579\u001b[0;31m .format(self.__class__))\n\u001b[0m\u001b[1;32m 1580\u001b[0m \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1581\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m__class__\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_u\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_classes\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mUpdatingAtomGroup\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;31mTypeError\u001b[0m: Attempted to make <class 'MDAnalysis.core.groups.AtomGroup'> instance dynamically updating, but it does not seem to have originated from a 'select_atoms' selection (it lacks '_base_group', '_selections', and '_lastupdate' attributes)."
]
}
],
"source": [
"ag_hmm.updating = True"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Yeah, this feels complicated to me. If there's not really a performance gain I feel like it complicates MDAnalysis' interface, and could be asking for trouble when trying do more complicated things, such as parallelization. It also introduces more state in the `AtomGroup`, which may or may not be present depending on *how* it was obtained. This is fragile."
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 2",
"language": "python2",
"name": "python2"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 2
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython2",
"version": "2.7.12"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment