a58d1854cfbec52c4c176ceef626bac3ee261a5e
[alexxy/gromacs.git] / src / gmxlib / selection / sm_position.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 position evaluation selection methods.
33  */
34 #ifdef HAVE_CONFIG_H
35 #include <config.h>
36 #endif
37
38 #include <macros.h>
39 #include <smalloc.h>
40 #include <string2.h>
41
42 #include <indexutil.h>
43 #include <poscalc.h>
44 #include <position.h>
45 #include <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_ana_poscalc_coll_t *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_ana_poscalc_coll_t *pcc, void *data);
75 /** Initializes position evaluation keywords. */
76 static int
77 init_kwpos(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data);
78 /** Initializes the \p cog selection method. */
79 static int
80 init_cog(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data);
81 /** Initializes the \p cog selection method. */
82 static int
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 int
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 int
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_ana_poscalc_coll_t *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  *   gmx_ana_poscalc_type_from_enum().
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(t_selelem *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 gmx_ana_poscalc_type_from_enum()).
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(t_selelem *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 int
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     int               rc;
260
261     if (!(param[0].flags & SPAR_DYNAMIC))
262     {
263         d->flags &= ~(POS_DYNAMIC | POS_MASKONLY);
264     }
265     else if (!(d->flags & POS_MASKONLY))
266     {
267         d->flags |= POS_DYNAMIC;
268     }
269     rc = gmx_ana_poscalc_create_enum(&d->pc, d->pcc, d->type, d->flags);
270     if (rc != 0)
271     {
272         return rc;
273     }
274     gmx_ana_poscalc_set_maxindex(d->pc, &d->g);
275     return 0;
276 }
277
278 /*!
279  * \param[in]     top   Topology data structure.
280  * \param[in]     npar  Not used.
281  * \param[in]     param Not used.
282  * \param[in,out] data  Should point to \c t_methoddata_pos.
283  * \returns       0 on success, a non-zero error code on error.
284  */
285 static int
286 init_cog(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data)
287 {
288     t_methoddata_pos *d = (t_methoddata_pos *)data;
289     int               rc;
290
291     d->flags = (param[0].flags & SPAR_DYNAMIC) ? POS_DYNAMIC : 0;
292     rc = gmx_ana_poscalc_create(&d->pc, d->pcc, d->bPBC ? POS_ALL_PBC : POS_ALL,
293                                 d->flags);
294     if (rc != 0)
295     {
296         return rc;
297     }
298     gmx_ana_poscalc_set_maxindex(d->pc, &d->g);
299     return 0;
300 }
301
302 /*!
303  * \param[in]     top   Topology data structure.
304  * \param[in]     npar  Not used.
305  * \param[in]     param Not used.
306  * \param[in,out] data  Should point to \c t_methoddata_pos.
307  * \returns       0 on success, a non-zero error code on error.
308  */
309 static int
310 init_com(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data)
311 {
312     t_methoddata_pos *d = (t_methoddata_pos *)data;
313     int               rc;
314
315     d->flags  = (param[0].flags & SPAR_DYNAMIC) ? POS_DYNAMIC : 0;
316     d->flags |= POS_MASS;
317     rc = gmx_ana_poscalc_create(&d->pc, d->pcc, d->bPBC ? POS_ALL_PBC : POS_ALL,
318                                 d->flags);
319     if (rc != 0)
320     {
321         return rc;
322     }
323     gmx_ana_poscalc_set_maxindex(d->pc, &d->g);
324     return 0;
325 }
326
327 /*!
328  * \param[in]     top   Topology data structure.
329  * \param[in,out] out   Pointer to output data structure.
330  * \param[in,out] data  Should point to \c t_methoddata_pos.
331  * \returns       0 for success.
332  */
333 static int
334 init_output_pos(t_topology *top, gmx_ana_selvalue_t *out, void *data)
335 {
336     t_methoddata_pos *d = (t_methoddata_pos *)data;
337
338     gmx_ana_poscalc_init_pos(d->pc, out->u.p);
339     gmx_ana_pos_set_evalgrp(out->u.p, &d->g);
340     return 0;
341 }
342
343 /*!
344  * \param data Data to free (should point to a \c t_methoddata_pos).
345  *
346  * Frees the memory allocated for \c t_methoddata_pos::g and
347  * \c t_methoddata_pos::pc.
348  */
349 static void
350 free_data_pos(void *data)
351 {
352     t_methoddata_pos *d = (t_methoddata_pos *)data;
353
354     sfree(d->type);
355     gmx_ana_poscalc_free(d->pc);
356 }
357
358 /*!
359  * See sel_updatefunc() for description of the parameters.
360  * \p data should point to a \c t_methoddata_pos.
361  *
362  * Calculates the positions using \c t_methoddata_pos::pc for the index group
363  * in \c t_methoddata_pos::g and stores the results in \p out->u.p.
364  */
365 static int
366 evaluate_pos(t_topology *top, t_trxframe *fr, t_pbc *pbc,
367              gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
368 {
369     t_methoddata_pos *d = (t_methoddata_pos *)data;
370
371     gmx_ana_poscalc_update(d->pc, out->u.p, &d->g, fr, pbc);
372     return 0;
373 }