Merge "Merge release-4-6 into master"
[alexxy/gromacs.git] / src / gromacs / selection / selelem.cpp
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
4  * Copyright (c) 2009,2010,2011,2012, by the GROMACS development team, led by
5  * David van der Spoel, Berk Hess, Erik Lindahl, and including many
6  * others, as listed in the AUTHORS file in the top-level source
7  * directory and at http://www.gromacs.org.
8  *
9  * GROMACS is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public License
11  * as published by the Free Software Foundation; either version 2.1
12  * of the License, or (at your option) any later version.
13  *
14  * GROMACS is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with GROMACS; if not, see
21  * http://www.gnu.org/licenses, or write to the Free Software Foundation,
22  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
23  *
24  * If you want to redistribute modifications to GROMACS, please
25  * consider that scientific software is very special. Version
26  * control is crucial - bugs must be traceable. We will be happy to
27  * consider code for inclusion in the official distribution, but
28  * derived work must not be called official GROMACS. Details are found
29  * in the README & COPYING files - if they are missing, get the
30  * official version at http://www.gromacs.org.
31  *
32  * To help us fund GROMACS development, we humbly ask that you cite
33  * the research papers on the package. Check out http://www.gromacs.org.
34  */
35 /*! \internal \file
36  * \brief
37  * Implements functions in selelem.h.
38  *
39  * \author Teemu Murtola <teemu.murtola@gmail.com>
40  * \ingroup module_selection
41  */
42 #include <cstring>
43
44 #include "gromacs/legacyheaders/smalloc.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 #include "gromacs/utility/exceptions.h"
51 #include "gromacs/utility/gmxassert.h"
52
53 #include "keywords.h"
54 #include "mempool.h"
55 #include "selelem.h"
56
57 /*!
58  * \param[in] sel Selection for which the string is requested
59  * \returns   Pointer to a string that corresponds to \p sel->type.
60  *
61  * The return value points to a string constant and should not be \p free'd.
62  *
63  * The function returns NULL if \p sel->type is not one of the valid values.
64  */
65 const char *
66 _gmx_selelem_type_str(const gmx::SelectionTreeElement &sel)
67 {
68     switch (sel.type)
69     {
70         case SEL_CONST:      return "CONST";
71         case SEL_EXPRESSION: return "EXPR";
72         case SEL_BOOLEAN:    return "BOOL";
73         case SEL_ARITHMETIC: return "ARITH";
74         case SEL_ROOT:       return "ROOT";
75         case SEL_SUBEXPR:    return "SUBEXPR";
76         case SEL_SUBEXPRREF: return "REF";
77         case SEL_GROUPREF:   return "GROUPREF";
78         case SEL_MODIFIER:   return "MODIFIER";
79     }
80     return NULL;
81 }
82
83 /*!
84  * \param[in] val Value structore for which the string is requested.
85  * \returns   Pointer to a string that corresponds to \p val->type,
86  *   NULL if the type value is invalid.
87  *
88  * The return value points to a string constant and should not be \p free'd.
89  */
90 const char *
91 _gmx_sel_value_type_str(const gmx_ana_selvalue_t *val)
92 {
93     switch (val->type)
94     {
95         case NO_VALUE:       return "NONE";
96         case INT_VALUE:      return "INT";
97         case REAL_VALUE:     return "REAL";
98         case STR_VALUE:      return "STR";
99         case POS_VALUE:      return "VEC";
100         case GROUP_VALUE:    return "GROUP";
101     }
102     return NULL;
103 }
104
105 /*! \copydoc _gmx_selelem_type_str() */
106 const char *
107 _gmx_selelem_boolean_type_str(const gmx::SelectionTreeElement &sel)
108 {
109     switch (sel.u.boolt)
110     {
111         case BOOL_NOT:  return "NOT"; break;
112         case BOOL_AND:  return "AND"; break;
113         case BOOL_OR:   return "OR";  break;
114         case BOOL_XOR:  return "XOR"; break;
115     }
116     return NULL;
117 }
118
119
120 namespace gmx
121 {
122
123 SelectionTreeElement::SelectionTreeElement(e_selelem_t type)
124 {
125     this->type       = type;
126     this->flags      = (type != SEL_ROOT) ? SEL_ALLOCVAL : 0;
127     if (type == SEL_BOOLEAN)
128     {
129         this->v.type = GROUP_VALUE;
130         this->flags |= SEL_ALLOCDATA;
131     }
132     else
133     {
134         this->v.type = NO_VALUE;
135     }
136     _gmx_selvalue_clear(&this->v);
137     std::memset(&this->u, 0, sizeof(this->u));
138     this->evaluate   = NULL;
139     this->mempool    = NULL;
140     this->cdata      = NULL;
141 }
142
143 SelectionTreeElement::~SelectionTreeElement()
144 {
145     /* Free the children.
146      * Must be done before freeing other data, because the children may hold
147      * references to data in this element. */
148     child.reset();
149
150     freeValues();
151     freeExpressionData();
152     freeCompilerData();
153 }
154
155 void SelectionTreeElement::freeValues()
156 {
157     mempoolRelease();
158     if ((flags & SEL_ALLOCDATA) && v.u.ptr)
159     {
160         /* The number of position/group structures is constant, so the
161          * backup of using sel->v.nr should work for them.
162          * For strings, we report an error if we don't know the allocation
163          * size here. */
164         int n = (v.nalloc > 0) ? v.nalloc : v.nr;
165         switch (v.type)
166         {
167             case STR_VALUE:
168                 GMX_RELEASE_ASSERT(v.nalloc != 0,
169                                    "SEL_ALLOCDATA should only be set for allocated "
170                                    "STR_VALUE values");
171                 for (int i = 0; i < n; ++i)
172                 {
173                     sfree(v.u.s[i]);
174                 }
175                 break;
176             case POS_VALUE:
177                 for (int i = 0; i < n; ++i)
178                 {
179                     gmx_ana_pos_deinit(&v.u.p[i]);
180                 }
181                 break;
182             case GROUP_VALUE:
183                 for (int i = 0; i < n; ++i)
184                 {
185                     gmx_ana_index_deinit(&v.u.g[i]);
186                 }
187                 break;
188             default: /* No special handling for other types */
189                 break;
190         }
191     }
192     if (flags & SEL_ALLOCVAL)
193     {
194         sfree(v.u.ptr);
195     }
196     _gmx_selvalue_setstore(&v, NULL);
197     if (type == SEL_SUBEXPRREF && u.param)
198     {
199         u.param->val.u.ptr = NULL;
200     }
201 }
202
203 void
204 SelectionTreeElement::freeExpressionData()
205 {
206     if (type == SEL_EXPRESSION || type == SEL_MODIFIER)
207     {
208         _gmx_selelem_free_method(u.expr.method, u.expr.mdata);
209         u.expr.mdata  = NULL;
210         u.expr.method = NULL;
211         /* Free position data */
212         if (u.expr.pos)
213         {
214             gmx_ana_pos_free(u.expr.pos);
215             u.expr.pos = NULL;
216         }
217         /* Free position calculation data */
218         if (u.expr.pc)
219         {
220             gmx_ana_poscalc_free(u.expr.pc);
221             u.expr.pc = NULL;
222         }
223     }
224     if (type == SEL_ARITHMETIC)
225     {
226         sfree(u.arith.opstr);
227         u.arith.opstr = NULL;
228     }
229     if (type == SEL_SUBEXPR || type == SEL_ROOT
230         || (type == SEL_CONST && v.type == GROUP_VALUE))
231     {
232         gmx_ana_index_deinit(&u.cgrp);
233     }
234     if (type == SEL_GROUPREF)
235     {
236         sfree(u.gref.name);
237     }
238 }
239
240 void SelectionTreeElement::mempoolReserve(int count)
241 {
242     if (!mempool)
243     {
244         return;
245     }
246     switch (v.type)
247     {
248         case INT_VALUE:
249             v.u.i = static_cast<int *>(
250                     _gmx_sel_mempool_alloc(mempool, sizeof(*v.u.i)*count));
251             break;
252
253         case REAL_VALUE:
254             v.u.r = static_cast<real *>(
255                     _gmx_sel_mempool_alloc(mempool, sizeof(*v.u.r)*count));
256             break;
257
258         case GROUP_VALUE:
259             _gmx_sel_mempool_alloc_group(mempool, v.u.g, count);
260             break;
261
262         default:
263             GMX_THROW(gmx::InternalError("Memory pooling not implemented for requested type"));
264     }
265 }
266
267 void SelectionTreeElement::mempoolRelease()
268 {
269     if (!mempool)
270     {
271         return;
272     }
273     switch (v.type)
274     {
275         case INT_VALUE:
276         case REAL_VALUE:
277             _gmx_sel_mempool_free(mempool, v.u.ptr);
278             _gmx_selvalue_setstore(&v, NULL);
279             break;
280
281         case GROUP_VALUE:
282             if (v.u.g)
283             {
284                 _gmx_sel_mempool_free_group(mempool, v.u.g);
285             }
286             break;
287
288         default:
289             GMX_THROW(gmx::InternalError("Memory pooling not implemented for requested type"));
290     }
291 }
292
293 } // namespace gmx
294
295 /*!
296  * \param[in,out] sel   Selection element to set the type for.
297  * \param[in]     vtype Value type for the selection element.
298  *
299  * If the new type is \ref GROUP_VALUE or \ref POS_VALUE, the
300  * \ref SEL_ALLOCDATA flag is also set.
301  *
302  * This function should only be called at most once for each element,
303  * preferably right after calling _gmx_selelem_create().
304  */
305 void
306 _gmx_selelem_set_vtype(const gmx::SelectionTreeElementPointer &sel,
307                        e_selvalue_t                            vtype)
308 {
309     GMX_RELEASE_ASSERT(sel->type != SEL_BOOLEAN || vtype == GROUP_VALUE,
310                        "Boolean elements must have a group value");
311     GMX_RELEASE_ASSERT(sel->v.type == NO_VALUE || vtype == sel->v.type,
312                        "_gmx_selelem_set_vtype() called more than once");
313     sel->v.type = vtype;
314     if (vtype == GROUP_VALUE || vtype == POS_VALUE)
315     {
316         sel->flags |= SEL_ALLOCDATA;
317     }
318 }
319
320 /*!
321  * \param[in] method Method to free.
322  * \param[in] mdata  Method data to free.
323  */
324 void
325 _gmx_selelem_free_method(gmx_ana_selmethod_t *method, void *mdata)
326 {
327     sel_freefunc free_func = NULL;
328
329     /* Save the pointer to the free function. */
330     if (method && method->free)
331     {
332         free_func = method->free;
333     }
334
335     /* Free the method itself.
336      * Has to be done before freeing the method data, because parameter
337      * values are typically stored in the method data, and here we may
338      * access them. */
339     if (method)
340     {
341         int  i, j;
342
343         /* Free the memory allocated for the parameters that are not managed
344          * by the selection method itself. */
345         for (i = 0; i < method->nparams; ++i)
346         {
347             gmx_ana_selparam_t *param = &method->param[i];
348
349             if (param->val.u.ptr)
350             {
351                 if (param->val.type == GROUP_VALUE)
352                 {
353                     for (j = 0; j < param->val.nr; ++j)
354                     {
355                         gmx_ana_index_deinit(&param->val.u.g[j]);
356                     }
357                 }
358                 else if (param->val.type == POS_VALUE)
359                 {
360                     for (j = 0; j < param->val.nr; ++j)
361                     {
362                         gmx_ana_pos_deinit(&param->val.u.p[j]);
363                     }
364                 }
365
366                 if (param->val.nalloc > 0)
367                 {
368                     sfree(param->val.u.ptr);
369                 }
370             }
371         }
372         sfree(method->param);
373         sfree(method);
374     }
375     /* Free method data. */
376     if (mdata)
377     {
378         if (free_func)
379         {
380             free_func(mdata);
381         }
382         else
383         {
384             sfree(mdata);
385         }
386     }
387 }
388
389 /*!
390  * \param[in] fp      File handle to receive the output.
391  * \param[in] sel     Root of the selection subtree to print.
392  * \param[in] bValues If true, the evaluated values of selection elements
393  *   are printed as well.
394  * \param[in] level   Indentation level, starting from zero.
395  */
396 void
397 _gmx_selelem_print_tree(FILE *fp, const gmx::SelectionTreeElement &sel,
398                         bool bValues, int level)
399 {
400     int          i;
401
402     fprintf(fp, "%*c %s %s", level*2+1, '*',
403             _gmx_selelem_type_str(sel), _gmx_sel_value_type_str(&sel.v));
404     if (!sel.name().empty())
405     {
406         fprintf(fp, " \"%s\"", sel.name().c_str());
407     }
408     fprintf(fp, " flg=");
409     if (sel.flags & SEL_FLAGSSET)
410     {
411         fprintf(fp, "s");
412     }
413     if (sel.flags & SEL_SINGLEVAL)
414     {
415         fprintf(fp, "S");
416     }
417     if (sel.flags & SEL_ATOMVAL)
418     {
419         fprintf(fp, "A");
420     }
421     if (sel.flags & SEL_VARNUMVAL)
422     {
423         fprintf(fp, "V");
424     }
425     if (sel.flags & SEL_DYNAMIC)
426     {
427         fprintf(fp, "D");
428     }
429     if (!(sel.flags & SEL_VALFLAGMASK))
430     {
431         fprintf(fp, "0");
432     }
433     if (sel.flags & SEL_ALLOCVAL)
434     {
435         fprintf(fp, "Av");
436     }
437     if (sel.flags & SEL_ALLOCDATA)
438     {
439         fprintf(fp, "Ad");
440     }
441     if (sel.mempool)
442     {
443         fprintf(fp, "P");
444     }
445     if (sel.type == SEL_CONST)
446     {
447         if (sel.v.type == INT_VALUE)
448         {
449             fprintf(fp, " %d", sel.v.u.i[0]);
450         }
451         else if (sel.v.type == REAL_VALUE)
452         {
453             fprintf(fp, " %f", sel.v.u.r[0]);
454         }
455         else if (sel.v.type == GROUP_VALUE)
456         {
457             const gmx_ana_index_t *g = sel.v.u.g;
458             if (!g || g->isize == 0)
459             {
460                 g = &sel.u.cgrp;
461             }
462             fprintf(fp, " (%d atoms)", g->isize);
463         }
464     }
465     else if (sel.type == SEL_BOOLEAN)
466     {
467         fprintf(fp, " %s", _gmx_selelem_boolean_type_str(sel));
468     }
469     else if (sel.type == SEL_EXPRESSION
470              && sel.u.expr.method->name == sm_compare.name)
471     {
472         _gmx_selelem_print_compare_info(fp, sel.u.expr.mdata);
473     }
474     if (sel.evaluate)
475     {
476         fprintf(fp, " eval=");
477         _gmx_sel_print_evalfunc_name(fp, sel.evaluate);
478     }
479     if (!(sel.flags & SEL_ALLOCVAL))
480     {
481         fprintf(fp, " (ext)");
482     }
483     fprintf(fp, "\n");
484
485     if ((sel.type == SEL_CONST && sel.v.type == GROUP_VALUE) || sel.type == SEL_ROOT)
486     {
487         const gmx_ana_index_t *g = sel.v.u.g;
488         if (!g || g->isize == 0 || sel.evaluate != NULL)
489         {
490             g = &sel.u.cgrp;
491         }
492         if (g->isize < 0)
493         {
494             fprintf(fp, "%*c group: (null)\n", level*2+1, ' ');
495         }
496         else if (g->isize > 0)
497         {
498             fprintf(fp, "%*c group:", level*2+1, ' ');
499             if (g->isize <= 20)
500             {
501                 for (i = 0; i < g->isize; ++i)
502                 {
503                     fprintf(fp, " %d", g->index[i] + 1);
504                 }
505             }
506             else
507             {
508                 fprintf(fp, " %d atoms", g->isize);
509             }
510             fprintf(fp, "\n");
511         }
512     }
513     else if (sel.type == SEL_EXPRESSION)
514     {
515         if (sel.u.expr.pc)
516         {
517             fprintf(fp, "%*c COM", level*2+3, '*');
518             fprintf(fp, "\n");
519         }
520     }
521
522     if (sel.cdata)
523     {
524         _gmx_selelem_print_compiler_info(fp, sel, level);
525     }
526
527     if (bValues && sel.type != SEL_CONST && sel.type != SEL_ROOT && sel.v.u.ptr)
528     {
529         fprintf(fp, "%*c value: ", level*2+1, ' ');
530         switch (sel.v.type)
531         {
532             case POS_VALUE:
533                 /* In normal use, the pointer should never be NULL, but it's
534                  * useful to have the check for debugging to avoid accidental
535                  * segfaults when printing the selection tree. */
536                 if (sel.v.u.p->x)
537                 {
538                     fprintf(fp, "(%f, %f, %f)",
539                             sel.v.u.p->x[0][XX], sel.v.u.p->x[0][YY],
540                             sel.v.u.p->x[0][ZZ]);
541                 }
542                 else
543                 {
544                     fprintf(fp, "(null)");
545                 }
546                 break;
547             case GROUP_VALUE:
548                 fprintf(fp, "%d atoms", sel.v.u.g->isize);
549                 if (sel.v.u.g->isize < 20)
550                 {
551                     if (sel.v.u.g->isize > 0)
552                     {
553                         fprintf(fp, ":");
554                     }
555                     for (i = 0; i < sel.v.u.g->isize; ++i)
556                     {
557                         fprintf(fp, " %d", sel.v.u.g->index[i] + 1);
558                     }
559                 }
560                 break;
561             default:
562                 fprintf(fp, "???");
563                 break;
564         }
565         fprintf(fp, "\n");
566     }
567
568     /* Print the subexpressions with one more level of indentation */
569     gmx::SelectionTreeElementPointer child = sel.child;
570     while (child)
571     {
572         if (!(sel.type == SEL_SUBEXPRREF && child->type == SEL_SUBEXPR))
573         {
574             _gmx_selelem_print_tree(fp, *child, bValues, level+1);
575         }
576         child = child->next;
577     }
578 }
579
580 /*!
581  * \param[in] root Root of the subtree to query.
582  * \returns true if \p root or any any of its elements require topology
583  *   information, false otherwise.
584  */
585 bool
586 _gmx_selelem_requires_top(const gmx::SelectionTreeElement &root)
587 {
588     if (root.type == SEL_EXPRESSION || root.type == SEL_MODIFIER)
589     {
590         if (root.u.expr.method && (root.u.expr.method->flags & SMETH_REQTOP))
591         {
592             return true;
593         }
594         if (root.u.expr.pc && gmx_ana_poscalc_requires_top(root.u.expr.pc))
595         {
596             return true;
597         }
598     }
599     gmx::SelectionTreeElementPointer child = root.child;
600     while (child)
601     {
602         if (_gmx_selelem_requires_top(*child))
603         {
604             return true;
605         }
606         child = child->next;
607     }
608     return false;
609 }