1
2
3
4
5
6 """
7 Distance plugin
8 ===============
9
10 Time series of a selected set of distances.
11
12 Plugin class
13 ------------
14
15 .. autoclass:: Distances
16 :members: worker_class
17 :undoc-members:
18
19 Worker class
20 ------------
21
22 The worker class performs the analysis.
23
24 .. autoclass:: _Distances
25 :members:
26
27
28 """
29 __docformat__ = "restructuredtext en"
30
31 import sys
32 import os.path
33 import warnings
34 import subprocess
35 import tempfile
36 import numpy
37
38 import gromacs
39 from gromacs.utilities import AttributeDict, asiterable
40 from gromacs.formats import XVG
41 from gromacs.analysis.core import Worker, Plugin
42
43
44
45
46
47
49 """Analysis of distances.
50
51 See :class:`Distances` for usage.
52
53 Also used as a base class for :class:`mindistances._MinDistances`.
54 """
55
56
57 names = ["distance"]
58
59
60 xlabels = {"distance": r"time $t/$ns",
61 "contacts": r"time $t/$ns",
62 }
63
64 ylabels = {"distance": r"distance $d/$nm",
65 "contacts": r"contacts $N$",
66 }
67
68 default_plot_columns = [0, 1]
69
71 """Set up customized distance analysis.
72
73 :Arguments:
74 groups : list of index group names
75 The first entry is the *primary group*. All other entries
76 are *secondary groups* and the plugin calculates the minimum distance
77 between members of the primary group and the members of each
78 secondary group.
79 ndx : index filename or list
80 All index files that contain the listed groups.
81 cutoff : float
82 A contact is recorded if the distance is <cutoff [0.6 nm]
83 """
84
85
86
87 indexgroups = kwargs.pop('groups',None)
88 if indexgroups is None or len(indexgroups) < 2 or type(indexgroups) is str:
89 raise ValueError("groups must be a list with at least a primary and secondary group")
90 ndx = kwargs.pop('ndx', None)
91 cutoff = kwargs.pop('cutoff', 0.6)
92
93
94
95 super(_Distances,self).__init__(**kwargs)
96
97 self.parameters.indexgroups = indexgroups
98 self.parameters.ndx = ndx
99 self.parameters.cutoff = cutoff
100
101 if not self.simulation is None:
102 self._register_hook()
103
105 """Run when registering; requires simulation.
106
107 Defines output files (note that we overwrite the
108 parameters.filenames and figname that super might have set).
109 """
110
111 super(_Distances, self)._register_hook(**kwargs)
112 assert not self.simulation is None
113
114
115 self.parameters.filenames = {
116 'distance': self.plugindir('distance.xvg'),
117 }
118
119
120 self.parameters.figname = self.figdir('distances')
121
122
123
124
125 - def run(self,**kwargs):
126 """Run ``g_dist `` to compute distances between A and B groups.
127
128 Additional arguments can be provided (e.g. ``-b`` or ``-e``)
129 but an error will result if one tries to set parameters that
130 are already being set by the method itself such as ``-s`` or
131 ``-d``; one must to provide the appropriate values to the
132 class constructor.
133
134 If the primary output file already exists then no data are generated
135 and the method returns immediately unless one sets *force* = ``True``.
136 """
137 force = kwargs.pop('force',False)
138 if not force and \
139 self.check_file_exists(self.parameters.filenames['distance'], resolve='warn'):
140 return
141 indexgroups = self.parameters.indexgroups
142 ngroups = len(indexgroups) - 1
143 if ngroups != 1:
144 raise ValueError("g_dist can only compute the distance between a primary and a secondary group")
145 gromacs.g_dist(s=self.simulation.tpr, n=self.parameters.ndx, f=self.simulation.xtc,
146 o=self.parameters.filenames['distance'],
147 input=indexgroups,
148 **kwargs)
149
157
158 - def plot(self, names=None, **kwargs):
159 """Plot the selected data.
160
161 :Arguments:
162 names : string or list
163 Selects which results should be plotted. ``None`` plots all
164 in separate graphs.
165 columns : list
166 Which columns to plot; typically the default is ok.
167 figure
168 - ``True``: save figures in the given formats
169 - "name.ext": save figure under this filename (``ext`` -> format)
170 - ``False``: only show on screen
171 formats : sequence
172 sequence of all formats that should be saved [('png', 'pdf')]
173 callbacks : dict
174 **hack**: provide a dictionary that contains callback functions
175 to customize the plot. They will be called at the end of
176 generating a subplot and must be indexed by *name*. They will
177 be called with the keyword arguments *name* and *axis*
178 (current subplot axis object)::
179
180 callback(name=name, axis=ax)
181 kwargs
182 All other keyword arguments are directly passed to
183 meth:`gromacs.formats.XVG.plot`.
184 """
185 import pylab
186
187 figure = kwargs.pop('figure', False)
188 extensions = kwargs.pop('formats', ('pdf','png'))
189 callbacks = kwargs.pop('callbacks', None)
190 def ps2ns(a):
191 """Transform first column (in ps) to ns."""
192 _a = numpy.array(a, copy=True)
193 _a[0] *= 0.001
194 return _a
195 kwargs.setdefault('transform', ps2ns)
196 kwargs.setdefault('columns', self.default_plot_columns)
197
198 if names is None:
199 names = self.results.keys()
200 names = asiterable(names)
201 ngraphs = len(names)
202 for plotNum, name in enumerate(names):
203 plotNum += 1
204 ax = pylab.subplot(1, ngraphs, plotNum)
205 try:
206 data = self.results[name].plot(**kwargs)
207 except KeyError:
208 ax.close()
209 raise KeyError('name = %r not known, choose one of %r' % (name, self.results.keys()))
210
211 pylab.xlabel(self.xlabels[name])
212 pylab.ylabel(self.ylabels[name])
213
214
215 if not callbacks is None:
216 try:
217 callbacks[name](name=name, axis=ax)
218 except KeyError:
219 pass
220
221
222 if figure is True:
223 for ext in extensions:
224 self.savefig(ext=ext)
225 elif figure:
226 self.savefig(filename=figure)
227
228
229
230
231
232
233
235 """*Distances* plugin.
236
237 The distance between the center of mass of two index groups are
238 calculated for each time step and written to files.
239
240 .. class:: Distances(groups, ndx, [cutoff, [, name[, simulation]]])
241
242 :Arguments:
243 name : string
244 plugin name (used to access it)
245 simulation : instance
246 The :class:`gromacs.analysis.Simulation` instance that owns the plugin.
247 groups : list of index group names
248 The first entry is the *primary group*, the second is the
249 *secondary group.
250 ndx : index filename or list
251 All index files that contain the listed groups.
252 cutoff : float
253 A contact is recorded if the distance is <cutoff [0.6 nm]
254
255 Example:
256
257 Generate index files with the groups of interest, for instance
258 with :class:`gromacs.cbook.IndexBuilder`::
259
260 from gromacs.cbook import IndexBuilder
261 A_grp, A_ndx = IndexBuilder(tpr, ['@a 62549 & r NA'], names=['Na1_ion'], offset=-9,
262 out_ndx='Na1.ndx', name_all="Na1").combine()
263 B = IndexBuilder(tpr, ['S312:OG','T313:OG1','A38:O','I41:O','A309:O'], offset=-9,
264 out_ndx='Na1_site.ndx', name_all="Na1_site")
265 B_grp, B_ndx = B.combine()
266 all_ndx_files = [A_ndx, B_ndx]
267
268 To calculate the distance between "Na1" and the "Na1_site", create an instance with
269 the appropriate parameters and add them to a :class:`gromacs.analysis.Simulation` instance::
270
271 dist_Na1_site = Distances(name='Dsite', groups=['Na1', 'Na1_site'], ndx=all_ndx_files)
272 S.add_plugin(dist_Na1_site)
273
274
275 """
276 worker_class = _Distances
277