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