Merge remote-tracking branch 'origin/release-4-6' into HEAD
[alexxy/gromacs.git] / src / gromacs / selection / sm_position.cpp
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
33  * Implements position evaluation selection methods.
34  *
35  * \author Teemu Murtola <teemu.murtola@cbr.su.se>
36  * \ingroup module_selection
37  */
38 #ifdef HAVE_CONFIG_H
39 #include <config.h>
40 #endif
41
42 #include <macros.h>
43 #include <smalloc.h>
44 #include <string2.h>
45
46 #include "gromacs/selection/indexutil.h"
47 #include "gromacs/selection/poscalc.h"
48 #include "gromacs/selection/position.h"
49 #include "gromacs/selection/selmethod.h"
50
51 #include "keywords.h"
52 #include "selelem.h"
53
54 /*! \internal \brief
55  * Data structure for position keyword evaluation.
56  */
57 typedef struct
58 {
59     /** Position calculation collection to use. */
60     gmx::PositionCalculationCollection *pcc;
61     /** Index group for which the center should be evaluated. */
62     gmx_ana_index_t    g;
63     /** Position evaluation data structure. */
64     gmx_ana_poscalc_t *pc;
65     /** true if periodic boundary conditions should be used. */
66     bool               bPBC;
67     /** Type of positions to calculate. */
68     char              *type;
69     /** Flags for the position calculation. */
70     int                flags;
71 } t_methoddata_pos;
72
73 /** Allocates data for position evaluation selection methods. */
74 static void *
75 init_data_pos(int npar, gmx_ana_selparam_t *param);
76 /** Sets the position calculation collection for position evaluation selection methods. */
77 static void
78 set_poscoll_pos(gmx::PositionCalculationCollection *pcc, void *data);
79 /** Initializes position evaluation keywords. */
80 static void
81 init_kwpos(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data);
82 /** Initializes the \p cog selection method. */
83 static void
84 init_cog(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data);
85 /** Initializes the \p cog selection method. */
86 static void
87 init_com(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data);
88 /** Initializes output for position evaluation selection methods. */
89 static void
90 init_output_pos(t_topology *top, gmx_ana_selvalue_t *out, void *data);
91 /** Frees the data allocated for position evaluation selection methods. */
92 static void
93 free_data_pos(void *data);
94 /** Evaluates position evaluation selection methods. */
95 static void
96 evaluate_pos(t_topology *top, t_trxframe *fr, t_pbc *pbc,
97              gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
98
99 /** Parameters for position keyword evaluation. */
100 static gmx_ana_selparam_t smparams_keyword_pos[] = {
101     {NULL,   {GROUP_VALUE, 1, {NULL}}, NULL, SPAR_DYNAMIC},
102 };
103
104 /** Parameters for the \p cog and \p com selection methods. */
105 static gmx_ana_selparam_t smparams_com[] = {
106     {"of",   {GROUP_VALUE, 1, {NULL}}, NULL, SPAR_DYNAMIC},
107     {"pbc",  {NO_VALUE,    0, {NULL}}, NULL, 0},
108 };
109
110 /** \internal Selection method data for position keyword evaluation. */
111 gmx_ana_selmethod_t sm_keyword_pos = {
112     "kw_pos", POS_VALUE, SMETH_DYNAMIC | SMETH_VARNUMVAL,
113     asize(smparams_keyword_pos), smparams_keyword_pos,
114     &init_data_pos,
115     &set_poscoll_pos,
116     &init_kwpos,
117     &init_output_pos,
118     &free_data_pos,
119      NULL,
120     &evaluate_pos,
121      NULL,
122     {NULL, 0, NULL},
123 };
124
125 /** \internal Selection method data for the \p cog method. */
126 gmx_ana_selmethod_t sm_cog = {
127     "cog", POS_VALUE, SMETH_DYNAMIC | SMETH_SINGLEVAL,
128     asize(smparams_com), smparams_com,
129     &init_data_pos,
130     &set_poscoll_pos,
131     &init_cog,
132     &init_output_pos,
133     &free_data_pos,
134      NULL,
135     &evaluate_pos,
136      NULL,
137     {"cog of ATOM_EXPR [pbc]", 0, NULL},
138 };
139
140 /** \internal Selection method data for the \p com method. */
141 gmx_ana_selmethod_t sm_com = {
142     "com", POS_VALUE, SMETH_REQTOP | SMETH_DYNAMIC | SMETH_SINGLEVAL,
143     asize(smparams_com), smparams_com,
144     &init_data_pos,
145     &set_poscoll_pos,
146     &init_com,
147     &init_output_pos,
148     &free_data_pos,
149      NULL,
150     &evaluate_pos,
151      NULL,
152     {"com of ATOM_EXPR [pbc]", 0, NULL},
153 };
154
155 /*!
156  * \param[in]     npar  Should be 1 or 2.
157  * \param[in,out] param Method parameters (should point to
158  *   \ref smparams_keyword_pos or \ref smparams_com).
159  * \returns       Pointer to the allocated data (\c t_methoddata_pos).
160  *
161  * Allocates memory for a \c t_methoddata_pos structure and initializes
162  * the first parameter to define the value for \c t_methoddata_pos::g.
163  * If a second parameter is present, it is used for setting the
164  * \c t_methoddata_pos::bPBC flag.
165  */
166 static void *
167 init_data_pos(int npar, gmx_ana_selparam_t *param)
168 {
169     t_methoddata_pos *data;
170
171     snew(data, 1);
172     param[0].val.u.g = &data->g;
173     if (npar > 1)
174     {
175         param[1].val.u.b = &data->bPBC;
176     }
177     data->pc       = NULL;
178     data->bPBC     = false;
179     data->type     = NULL;
180     data->flags    = -1;
181     return data;
182 }
183
184 /*!
185  * \param[in]     pcc   Position calculation collection to use.
186  * \param[in,out] data  Should point to \c t_methoddata_pos.
187  */
188 static void
189 set_poscoll_pos(gmx::PositionCalculationCollection *pcc, void *data)
190 {
191     ((t_methoddata_pos *)data)->pcc = pcc;
192 }
193
194 /*!
195  * \param[in,out] sel   Selection element to initialize.
196  * \param[in]     type  One of the enum values acceptable for
197  *     PositionCalculationCollection::typeFromEnum().
198  *
199  * Initializes the reference position type for position evaluation.
200  * If called multiple times, the first setting takes effect, and later calls
201  * are neglected.
202  */
203 void
204 _gmx_selelem_set_kwpos_type(t_selelem *sel, const char *type)
205 {
206     t_methoddata_pos *d = (t_methoddata_pos *)sel->u.expr.mdata;
207
208     if (sel->type != SEL_EXPRESSION || !sel->u.expr.method
209         || sel->u.expr.method->name != sm_keyword_pos.name)
210     {
211         return;
212     }
213     if (!d->type && type)
214     {
215         d->type  = strdup(type);
216         /* FIXME: It would be better not to have the string here hardcoded. */
217         if (type[0] != 'a')
218         {
219             sel->u.expr.method->flags |= SMETH_REQTOP;
220         }
221     }
222 }
223
224 /*!
225  * \param[in,out] sel   Selection element to initialize.
226  * \param[in]     flags Default completion flags
227  *     (see PositionCalculationCollection::typeFromEnum()).
228  *
229  * Initializes the flags for position evaluation.
230  * If called multiple times, the first setting takes effect, and later calls
231  * are neglected.
232  */
233 void
234 _gmx_selelem_set_kwpos_flags(t_selelem *sel, int flags)
235 {
236     t_methoddata_pos *d = (t_methoddata_pos *)sel->u.expr.mdata;
237
238     if (sel->type != SEL_EXPRESSION || !sel->u.expr.method
239         || sel->u.expr.method->name != sm_keyword_pos.name)
240     {
241         return;
242     }
243     if (d->flags == -1)
244     {
245         d->flags = flags;
246     }
247 }
248
249 /*!
250  * \param[in] top   Not used.
251  * \param[in] npar  Not used.
252  * \param[in] param Not used.
253  * \param[in,out] data  Should point to \c t_methoddata_pos.
254  * \returns       0 on success, a non-zero error code on error.
255  *
256  * The \c t_methoddata_pos::type field should have been initialized
257  * externally using _gmx_selelem_set_kwpos_type().
258  */
259 static void
260 init_kwpos(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data)
261 {
262     t_methoddata_pos *d = (t_methoddata_pos *)data;
263
264     if (!(param[0].flags & SPAR_DYNAMIC))
265     {
266         d->flags &= ~(POS_DYNAMIC | POS_MASKONLY);
267     }
268     else if (!(d->flags & POS_MASKONLY))
269     {
270         d->flags |= POS_DYNAMIC;
271     }
272     d->pc = d->pcc->createCalculationFromEnum(d->type, d->flags);
273     gmx_ana_poscalc_set_maxindex(d->pc, &d->g);
274 }
275
276 /*!
277  * \param[in]     top   Topology data structure.
278  * \param[in]     npar  Not used.
279  * \param[in]     param Not used.
280  * \param[in,out] data  Should point to \c t_methoddata_pos.
281  * \returns       0 on success, a non-zero error code on error.
282  */
283 static void
284 init_cog(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data)
285 {
286     t_methoddata_pos *d = (t_methoddata_pos *)data;
287
288     d->flags = (param[0].flags & SPAR_DYNAMIC) ? POS_DYNAMIC : 0;
289     d->pc = d->pcc->createCalculation(d->bPBC ? POS_ALL_PBC : POS_ALL, d->flags);
290     gmx_ana_poscalc_set_maxindex(d->pc, &d->g);
291 }
292
293 /*!
294  * \param[in]     top   Topology data structure.
295  * \param[in]     npar  Not used.
296  * \param[in]     param Not used.
297  * \param[in,out] data  Should point to \c t_methoddata_pos.
298  * \returns       0 on success, a non-zero error code on error.
299  */
300 static void
301 init_com(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data)
302 {
303     t_methoddata_pos *d = (t_methoddata_pos *)data;
304
305     d->flags  = (param[0].flags & SPAR_DYNAMIC) ? POS_DYNAMIC : 0;
306     d->flags |= POS_MASS;
307     d->pc = d->pcc->createCalculation(d->bPBC ? POS_ALL_PBC : POS_ALL, d->flags);
308     gmx_ana_poscalc_set_maxindex(d->pc, &d->g);
309 }
310
311 /*!
312  * \param[in]     top   Topology data structure.
313  * \param[in,out] out   Pointer to output data structure.
314  * \param[in,out] data  Should point to \c t_methoddata_pos.
315  * \returns       0 for success.
316  */
317 static void
318 init_output_pos(t_topology *top, gmx_ana_selvalue_t *out, void *data)
319 {
320     t_methoddata_pos *d = (t_methoddata_pos *)data;
321
322     gmx_ana_poscalc_init_pos(d->pc, out->u.p);
323     gmx_ana_pos_set_evalgrp(out->u.p, &d->g);
324 }
325
326 /*!
327  * \param data Data to free (should point to a \c t_methoddata_pos).
328  *
329  * Frees the memory allocated for \c t_methoddata_pos::g and
330  * \c t_methoddata_pos::pc.
331  */
332 static void
333 free_data_pos(void *data)
334 {
335     t_methoddata_pos *d = (t_methoddata_pos *)data;
336
337     sfree(d->type);
338     gmx_ana_poscalc_free(d->pc);
339 }
340
341 /*!
342  * See sel_updatefunc() for description of the parameters.
343  * \p data should point to a \c t_methoddata_pos.
344  *
345  * Calculates the positions using \c t_methoddata_pos::pc for the index group
346  * in \c t_methoddata_pos::g and stores the results in \p out->u.p.
347  */
348 static void
349 evaluate_pos(t_topology *top, t_trxframe *fr, t_pbc *pbc,
350              gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
351 {
352     t_methoddata_pos *d = (t_methoddata_pos *)data;
353
354     gmx_ana_poscalc_update(d->pc, out->u.p, &d->g, fr, pbc);
355 }