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