61ee58e7a305c3a7f233d458e2d145b45dc6fb7c
[alexxy/gromacs.git] / src / gmxlib / selection / sm_distance.c
1 /*
2  *
3  *                This source code is part of
4  *
5  *                 G   R   O   M   A   C   S
6  *
7  *          GROningen MAchine for Chemical Simulations
8  *
9  * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
10  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
11  * Copyright (c) 2001-2009, The GROMACS development team,
12  * check out http://www.gromacs.org for more information.
13
14  * This program is free software; you can redistribute it and/or
15  * modify it under the terms of the GNU General Public License
16  * as published by the Free Software Foundation; either version 2
17  * of the License, or (at your option) any later version.
18  *
19  * If you want to redistribute modifications, please consider that
20  * scientific software is very special. Version control is crucial -
21  * bugs must be traceable. We will be happy to consider code for
22  * inclusion in the official distribution, but derived work must not
23  * be called official GROMACS. Details are found in the README & COPYING
24  * files - if they are missing, get the official version at www.gromacs.org.
25  *
26  * To help us fund GROMACS development, we humbly ask that you cite
27  * the papers on the package - you can find them in the top README file.
28  *
29  * For more info, check our website at http://www.gromacs.org
30  */
31 /*! \internal \file
32  * \brief Implementation of distance-based selection methods.
33  *
34  * This file implements the \p distance, \p mindistance and \p within
35  * selection methods.
36  */
37 #ifdef HAVE_CONFIG_H
38 #include <config.h>
39 #endif
40
41 #include <macros.h>
42 #include <pbc.h>
43 #include <smalloc.h>
44 #include <vec.h>
45
46 #include <nbsearch.h>
47 #include <position.h>
48 #include <selmethod.h>
49
50 /*! \internal \brief
51  * Data structure for distance-based selection method.
52  *
53  * The same data structure is used by all the distance-based methods.
54  */
55 typedef struct
56 {
57     /** Cutoff distance. */
58     real                cutoff;
59     /** Positions of the reference points. */
60     gmx_ana_pos_t       p;
61     /** Neighborhood search data. */
62     gmx_ana_nbsearch_t *nb;
63 } t_methoddata_distance;
64
65 /** Allocates data for distance-based selection methods. */
66 static void *
67 init_data_common(int npar, gmx_ana_selparam_t *param);
68 /** Initializes a distance-based selection method. */
69 static int
70 init_common(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data);
71 /** Frees the data allocated for a distance-based selection method. */
72 static void
73 free_data_common(void *data);
74 /** Initializes the evaluation of a distance-based within selection method for a frame. */
75 static int
76 init_frame_common(t_topology *top, t_trxframe *fr, t_pbc *pbc, void *data);
77 /** Evaluates the \p distance selection method. */
78 static int
79 evaluate_distance(t_topology *top, t_trxframe *fr, t_pbc *pbc,
80                   gmx_ana_pos_t *pos, gmx_ana_selvalue_t *out, void *data);
81 /** Evaluates the \p within selection method. */
82 static int
83 evaluate_within(t_topology *top, t_trxframe *fr, t_pbc *pbc,
84                 gmx_ana_pos_t *pos, gmx_ana_selvalue_t *out, void *data);
85
86 /** Parameters for the \p distance selection method. */
87 static gmx_ana_selparam_t smparams_distance[] = {
88     {"cutoff", {REAL_VALUE, 1, {NULL}}, NULL, SPAR_OPTIONAL},
89     {"from",   {POS_VALUE,  1, {NULL}}, NULL, SPAR_DYNAMIC},
90 };
91
92 /** Parameters for the \p mindistance selection method. */
93 static gmx_ana_selparam_t smparams_mindistance[] = {
94     {"cutoff", {REAL_VALUE, 1, {NULL}}, NULL, SPAR_OPTIONAL},
95     {"from",   {POS_VALUE, -1, {NULL}}, NULL, SPAR_DYNAMIC | SPAR_VARNUM},
96 };
97
98 /** Parameters for the \p within selection method. */
99 static gmx_ana_selparam_t smparams_within[] = {
100     {NULL, {REAL_VALUE,  1, {NULL}}, NULL, 0},
101     {"of", {POS_VALUE,  -1, {NULL}}, NULL, SPAR_DYNAMIC | SPAR_VARNUM},
102 };
103
104 /** Help text for the distance selection methods. */
105 static const char *help_distance[] = {
106     "DISTANCE-BASED SELECTION KEYWORDS[PAR]",
107
108     "[TT]distance from POS [cutoff REAL][tt][BR]",
109     "[TT]mindistance from POS_EXPR [cutoff REAL][tt][BR]",
110     "[TT]within REAL of POS_EXPR[tt][PAR]",
111
112     "[TT]distance[tt] and [TT]mindistance[tt] calculate the distance from the",
113     "given position(s), the only difference being in that [TT]distance[tt]",
114     "only accepts a single position, while any number of positions can be",
115     "given for [TT]mindistance[tt], which then calculates the distance to the",
116     "closest position.",
117     "[TT]within[tt] directly selects atoms that are within [TT]REAL[tt] of",
118     "[TT]POS_EXPR[tt].[PAR]",
119
120     "For the first two keywords, it is possible to specify a cutoff to speed",
121     "up the evaluation: all distances above the specified cutoff are",
122     "returned as equal to the cutoff.",
123     "Currently, this does nothing, but in the future, it allows the use of",
124     "grid-based neighborhood search techniques.",
125 };
126
127 /** \internal Selection method data for the \p distance method. */
128 gmx_ana_selmethod_t sm_distance = {
129     "distance", REAL_VALUE, SMETH_DYNAMIC,
130     asize(smparams_distance), smparams_distance,
131     &init_data_common,
132     NULL,
133     &init_common,
134     NULL,
135     &free_data_common,
136     &init_frame_common,
137     NULL,
138     &evaluate_distance,
139     {"distance from POS [cutoff REAL]", asize(help_distance), help_distance},
140 };
141
142 /** \internal Selection method data for the \p distance method. */
143 gmx_ana_selmethod_t sm_mindistance = {
144     "mindistance", REAL_VALUE, SMETH_DYNAMIC,
145     asize(smparams_mindistance), smparams_mindistance,
146     &init_data_common,
147     NULL,
148     &init_common,
149     NULL,
150     &free_data_common,
151     &init_frame_common,
152     NULL,
153     &evaluate_distance,
154     {"mindistance from POS_EXPR [cutoff REAL]", asize(help_distance), help_distance},
155 };
156
157 /** \internal Selection method data for the \p within method. */
158 gmx_ana_selmethod_t sm_within = {
159     "within", GROUP_VALUE, SMETH_DYNAMIC,
160     asize(smparams_within), smparams_within,
161     &init_data_common,
162     NULL,
163     &init_common,
164     NULL,
165     &free_data_common,
166     &init_frame_common,
167     NULL,
168     &evaluate_within,
169     {"within REAL of POS_EXPR", asize(help_distance), help_distance},
170 };
171
172 /*!
173  * \param[in]     npar  Not used (should be 2).
174  * \param[in,out] param Method parameters (should point to one of the distance
175  *   parameter arrays).
176  * \returns       Pointer to the allocated data (\c t_methoddata_distance).
177  *
178  * Allocates memory for a \c t_methoddata_distance structure and
179  * initializes the parameter as follows:
180  *  - the first parameter defines the value for
181  *    \c t_methoddata_distance::cutoff.
182  *  - the second parameter defines the reference positions and the value is
183  *    stored in \c t_methoddata_distance::p.
184  */
185 static void *
186 init_data_common(int npar, gmx_ana_selparam_t *param)
187 {
188     t_methoddata_distance *data;
189
190     snew(data, 1);
191     data->cutoff     = -1;
192     param[0].val.u.r = &data->cutoff;
193     param[1].val.u.p = &data->p;
194     return data;
195 }
196
197 /*!
198  * \param   top   Not used.
199  * \param   npar  Not used (should be 2).
200  * \param   param Method parameters (should point to one of the distance
201  *   parameter arrays).
202  * \param   data  Pointer to \c t_methoddata_distance to initialize.
203  * \returns 0 on success, a non-zero error code on failure.
204  *
205  * Initializes the neighborhood search data structure
206  * (\c t_methoddata_distance::nb).
207  * Also checks that the cutoff is valid.
208  */
209 static int
210 init_common(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data)
211 {
212     t_methoddata_distance *d = (t_methoddata_distance *)data;
213
214     if ((param[0].flags & SPAR_SET) && d->cutoff <= 0)
215     {
216         fprintf(stderr, "error: distance cutoff should be > 0");
217         return -1;
218     }
219     return gmx_ana_nbsearch_create(&d->nb, d->cutoff, d->p.nr);
220 }
221
222 /*!
223  * \param data Data to free (should point to a \c t_methoddata_distance).
224  *
225  * Frees the memory allocated for \c t_methoddata_distance::xref and
226  * \c t_methoddata_distance::nb.
227  */
228 static void
229 free_data_common(void *data)
230 {
231     t_methoddata_distance *d = (t_methoddata_distance *)data;
232
233     if (d->nb)
234     {
235         gmx_ana_nbsearch_free(d->nb);
236     }
237 }
238
239 /*!
240  * \param[in]  top  Not used.
241  * \param[in]  fr   Current frame.
242  * \param[in]  pbc  PBC structure.
243  * \param      data Should point to a \c t_methoddata_distance.
244  * \returns    0 on success, a non-zero error code on error.
245  *
246  * Initializes the neighborhood search for the current frame.
247  */
248 static int
249 init_frame_common(t_topology *top, t_trxframe *fr, t_pbc *pbc, void *data)
250 {
251     t_methoddata_distance *d = (t_methoddata_distance *)data;
252
253     return gmx_ana_nbsearch_pos_init(d->nb, pbc, &d->p);
254 }
255
256 /*!
257  * See sel_updatefunc_pos() for description of the parameters.
258  * \p data should point to a \c t_methoddata_distance.
259  *
260  * Calculates the distance of each position from \c t_methoddata_distance::p
261  * and puts them in \p out->u.r.
262  */
263 static int
264 evaluate_distance(t_topology *top, t_trxframe *fr, t_pbc *pbc,
265                   gmx_ana_pos_t *pos, gmx_ana_selvalue_t *out, void *data)
266 {
267     t_methoddata_distance *d = (t_methoddata_distance *)data;
268     int  b, i;
269     real n;
270
271     out->nr = pos->g->isize;
272     for (b = 0; b < pos->nr; ++b)
273     {
274         n = gmx_ana_nbsearch_pos_mindist(d->nb, pos, b);
275         for (i = pos->m.mapb.index[b]; i < pos->m.mapb.index[b+1]; ++i)
276         {
277             out->u.r[i] = n;
278         }
279     }
280     return 0;
281 }
282
283 /*!
284  * See sel_updatefunc() for description of the parameters.
285  * \p data should point to a \c t_methoddata_distance.
286  *
287  * Finds the atoms that are closer than the defined cutoff to
288  * \c t_methoddata_distance::xref and puts them in \p out.g.
289  */
290 static int
291 evaluate_within(t_topology *top, t_trxframe *fr, t_pbc *pbc,
292                 gmx_ana_pos_t *pos, gmx_ana_selvalue_t *out, void *data)
293 {
294     t_methoddata_distance *d = (t_methoddata_distance *)data;
295     int                    b;
296
297     out->u.g->isize = 0;
298     for (b = 0; b < pos->nr; ++b)
299     {
300         if (gmx_ana_nbsearch_pos_is_within(d->nb, pos, b))
301         {
302             gmx_ana_pos_append(NULL, out->u.g, pos, b, 0);
303         }
304     }
305     return 0;
306 }