Fix Portland compiler warnings
[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,2013,2014, by the GROMACS development team, led by
5  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
6  * and including many others, as listed in the AUTHORS file in the
7  * top-level source 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/selection/indexutil.h"
45 #include "gromacs/selection/poscalc.h"
46 #include "gromacs/selection/position.h"
47 #include "gromacs/selection/selmethod.h"
48 #include "gromacs/utility/exceptions.h"
49 #include "gromacs/utility/gmxassert.h"
50 #include "gromacs/utility/smalloc.h"
51 #include "gromacs/utility/stringutil.h"
52
53 #include "keywords.h"
54 #include "mempool.h"
55 #include "selelem.h"
56 #include "selmethod.h"
57
58 /*!
59  * \param[in] sel Selection for which the string is requested
60  * \returns   Pointer to a string that corresponds to \p sel->type.
61  *
62  * The return value points to a string constant and should not be \p free'd.
63  *
64  * The function returns NULL if \p sel->type is not one of the valid values.
65  */
66 const char *
67 _gmx_selelem_type_str(const gmx::SelectionTreeElement &sel)
68 {
69     const char *p = NULL;
70     switch (sel.type)
71     {
72         case SEL_CONST:      p = "CONST";    break;
73         case SEL_EXPRESSION: p = "EXPR";     break;
74         case SEL_BOOLEAN:    p = "BOOL";     break;
75         case SEL_ARITHMETIC: p = "ARITH";    break;
76         case SEL_ROOT:       p = "ROOT";     break;
77         case SEL_SUBEXPR:    p = "SUBEXPR";  break;
78         case SEL_SUBEXPRREF: p = "REF";      break;
79         case SEL_GROUPREF:   p = "GROUPREF"; break;
80         case SEL_MODIFIER:   p = "MODIFIER"; break;
81             // No default clause so we intentionally get compiler errors
82             // if new selection choices are added later.
83     }
84     return p;
85 }
86
87 /*!
88  * \param[in] val Value structore for which the string is requested.
89  * \returns   Pointer to a string that corresponds to \p val->type,
90  *   NULL if the type value is invalid.
91  *
92  * The return value points to a string constant and should not be \p free'd.
93  */
94 const char *
95 _gmx_sel_value_type_str(const gmx_ana_selvalue_t *val)
96 {
97     const char *p = NULL;
98     switch (val->type)
99     {
100         case NO_VALUE:       p = "NONE";  break;
101         case INT_VALUE:      p = "INT";   break;
102         case REAL_VALUE:     p = "REAL";  break;
103         case STR_VALUE:      p = "STR";   break;
104         case POS_VALUE:      p = "VEC";   break;
105         case GROUP_VALUE:    p = "GROUP"; break;
106             // No default clause so we intentionally get compiler errors
107             // if new selection choices are added later.
108     }
109     return p;
110 }
111
112 /*! \copydoc _gmx_selelem_type_str() */
113 const char *
114 _gmx_selelem_boolean_type_str(const gmx::SelectionTreeElement &sel)
115 {
116     const char *p = NULL;
117     switch (sel.u.boolt)
118     {
119         case BOOL_NOT:  p = "NOT"; break;
120         case BOOL_AND:  p = "AND"; break;
121         case BOOL_OR:   p = "OR";  break;
122         case BOOL_XOR:  p = "XOR"; break;
123             // No default clause so we intentionally get compiler errors
124             // if new selection choices are added later.
125     }
126     return p;
127 }
128
129
130 namespace gmx
131 {
132
133 SelectionTreeElement::SelectionTreeElement(e_selelem_t type)
134 {
135     this->type       = type;
136     this->flags      = (type != SEL_ROOT) ? SEL_ALLOCVAL : 0;
137     if (type == SEL_BOOLEAN)
138     {
139         this->v.type = GROUP_VALUE;
140         this->flags |= SEL_ALLOCDATA;
141     }
142     else
143     {
144         this->v.type = NO_VALUE;
145     }
146     _gmx_selvalue_clear(&this->v);
147     std::memset(&this->u, 0, sizeof(this->u));
148     this->evaluate   = NULL;
149     this->mempool    = NULL;
150     this->cdata      = NULL;
151 }
152
153 SelectionTreeElement::~SelectionTreeElement()
154 {
155     /* Free the children.
156      * Must be done before freeing other data, because the children may hold
157      * references to data in this element. */
158     child.reset();
159
160     freeValues();
161     freeExpressionData();
162     freeCompilerData();
163 }
164
165 void SelectionTreeElement::freeValues()
166 {
167     mempoolRelease();
168     if ((flags & SEL_ALLOCDATA) && v.u.ptr)
169     {
170         /* The number of position/group structures is constant, so the
171          * backup of using sel->v.nr should work for them.
172          * For strings, we report an error if we don't know the allocation
173          * size here. */
174         int n = (v.nalloc > 0) ? v.nalloc : v.nr;
175         switch (v.type)
176         {
177             case STR_VALUE:
178                 GMX_RELEASE_ASSERT(v.nalloc != 0,
179                                    "SEL_ALLOCDATA should only be set for allocated "
180                                    "STR_VALUE values");
181                 for (int i = 0; i < n; ++i)
182                 {
183                     sfree(v.u.s[i]);
184                 }
185                 break;
186             case GROUP_VALUE:
187                 for (int i = 0; i < n; ++i)
188                 {
189                     gmx_ana_index_deinit(&v.u.g[i]);
190                 }
191                 break;
192             default: /* No special handling for other types */
193                 break;
194         }
195     }
196     if (v.nalloc > 0)
197     {
198         if (v.type == POS_VALUE)
199         {
200             delete [] v.u.p;
201         }
202         else
203         {
204             sfree(v.u.ptr);
205         }
206     }
207     _gmx_selvalue_setstore(&v, NULL);
208     if (type == SEL_SUBEXPRREF && u.param)
209     {
210         u.param->val.u.ptr = NULL;
211     }
212 }
213
214 void
215 SelectionTreeElement::freeExpressionData()
216 {
217     if (type == SEL_EXPRESSION || type == SEL_MODIFIER)
218     {
219         _gmx_selelem_free_method(u.expr.method, u.expr.mdata);
220         u.expr.mdata  = NULL;
221         u.expr.method = NULL;
222         /* Free position data */
223         delete u.expr.pos;
224         u.expr.pos = NULL;
225         /* Free position calculation data */
226         if (u.expr.pc)
227         {
228             gmx_ana_poscalc_free(u.expr.pc);
229             u.expr.pc = NULL;
230         }
231     }
232     if (type == SEL_ARITHMETIC)
233     {
234         sfree(u.arith.opstr);
235         u.arith.opstr = NULL;
236     }
237     if (type == SEL_SUBEXPR || type == SEL_ROOT
238         || (type == SEL_CONST && v.type == GROUP_VALUE))
239     {
240         gmx_ana_index_deinit(&u.cgrp);
241     }
242     if (type == SEL_GROUPREF)
243     {
244         sfree(u.gref.name);
245     }
246 }
247
248 void SelectionTreeElement::mempoolReserve(int count)
249 {
250     if (!mempool)
251     {
252         return;
253     }
254     switch (v.type)
255     {
256         case INT_VALUE:
257             v.u.i = static_cast<int *>(
258                     _gmx_sel_mempool_alloc(mempool, sizeof(*v.u.i)*count));
259             break;
260
261         case REAL_VALUE:
262             v.u.r = static_cast<real *>(
263                     _gmx_sel_mempool_alloc(mempool, sizeof(*v.u.r)*count));
264             break;
265
266         case GROUP_VALUE:
267             _gmx_sel_mempool_alloc_group(mempool, v.u.g, count);
268             break;
269
270         default:
271             GMX_THROW(gmx::InternalError("Memory pooling not implemented for requested type"));
272     }
273 }
274
275 void SelectionTreeElement::mempoolRelease()
276 {
277     if (!mempool)
278     {
279         return;
280     }
281     switch (v.type)
282     {
283         case INT_VALUE:
284         case REAL_VALUE:
285             _gmx_sel_mempool_free(mempool, v.u.ptr);
286             _gmx_selvalue_setstore(&v, NULL);
287             break;
288
289         case GROUP_VALUE:
290             if (v.u.g)
291             {
292                 _gmx_sel_mempool_free_group(mempool, v.u.g);
293             }
294             break;
295
296         default:
297             GMX_THROW(gmx::InternalError("Memory pooling not implemented for requested type"));
298     }
299 }
300
301 void SelectionTreeElement::fillNameIfMissing(const char *selectionText)
302 {
303     GMX_RELEASE_ASSERT(type == SEL_ROOT,
304                        "Should not be called for non-root elements");
305     if (name().empty())
306     {
307         // Check whether the actual selection given was from an external group,
308         // and if so, use the name of the external group.
309         SelectionTreeElementPointer child = this->child;
310         while (child->type == SEL_MODIFIER)
311         {
312             if (!child->child || child->child->type != SEL_SUBEXPRREF
313                 || !child->child->child)
314             {
315                 break;
316             }
317             child = child->child->child;
318         }
319         if (child->type == SEL_EXPRESSION
320             && child->child && child->child->type == SEL_SUBEXPRREF
321             && child->child->child)
322         {
323             if (child->child->child->type == SEL_CONST
324                 && child->child->child->v.type == GROUP_VALUE)
325             {
326                 setName(child->child->child->name());
327                 return;
328             }
329             // If the group reference is still unresolved, leave the name empty
330             // and fill it later.
331             if (child->child->child->type == SEL_GROUPREF)
332             {
333                 return;
334             }
335         }
336         // If there still is no name, use the selection string.
337         setName(selectionText);
338     }
339 }
340
341 void SelectionTreeElement::checkUnsortedAtoms(
342         bool bUnsortedAllowed, ExceptionInitializer *errors) const
343 {
344     const bool bUnsortedSupported
345         = (type == SEL_CONST && v.type == GROUP_VALUE)
346             || type == SEL_ROOT || type == SEL_SUBEXPR || type == SEL_SUBEXPRREF
347             // TODO: Consolidate.
348             || type == SEL_MODIFIER
349             || (type == SEL_EXPRESSION && (u.expr.method->flags & SMETH_ALLOW_UNSORTED));
350
351     // TODO: For some complicated selections, this may result in the same
352     // index group reference being flagged as an error multiple times for the
353     // same selection.
354     SelectionTreeElementPointer child = this->child;
355     while (child)
356     {
357         child->checkUnsortedAtoms(bUnsortedAllowed && bUnsortedSupported,
358                                   errors);
359         child = child->next;
360     }
361
362     // The logic here is simplified by the fact that only constant groups can
363     // currently be the root cause of SEL_UNSORTED being set, so only those
364     // need to be considered in triggering the error.
365     if (!bUnsortedAllowed && (flags & SEL_UNSORTED)
366         && type == SEL_CONST && v.type == GROUP_VALUE)
367     {
368         std::string message = formatString(
369                     "Group '%s' cannot be used in selections except "
370                     "as a full value of the selection, "
371                     "because atom indices in it are not sorted and/or "
372                     "it contains duplicate atoms.",
373                     name().c_str());
374         errors->addNested(InconsistentInputError(message));
375     }
376 }
377
378 void SelectionTreeElement::resolveIndexGroupReference(gmx_ana_indexgrps_t *grps)
379 {
380     GMX_RELEASE_ASSERT(type == SEL_GROUPREF,
381                        "Should only be called for index group reference elements");
382     if (grps == NULL)
383     {
384         std::string message = formatString(
385                     "Cannot match '%s', because index groups are not available.",
386                     name().c_str());
387         GMX_THROW(InconsistentInputError(message));
388     }
389
390     gmx_ana_index_t foundGroup;
391     std::string     foundName;
392     if (u.gref.name != NULL)
393     {
394         if (!gmx_ana_indexgrps_find(&foundGroup, &foundName, grps, u.gref.name))
395         {
396             std::string message = formatString(
397                         "Cannot match '%s', because no such index group can be found.",
398                         name().c_str());
399             GMX_THROW(InconsistentInputError(message));
400         }
401     }
402     else
403     {
404         if (!gmx_ana_indexgrps_extract(&foundGroup, &foundName, grps, u.gref.id))
405         {
406             std::string message = formatString(
407                         "Cannot match '%s', because no such index group can be found.",
408                         name().c_str());
409             GMX_THROW(InconsistentInputError(message));
410         }
411     }
412
413     if (!gmx_ana_index_check_sorted(&foundGroup))
414     {
415         flags |= SEL_UNSORTED;
416     }
417
418     sfree(u.gref.name);
419     type = SEL_CONST;
420     gmx_ana_index_set(&u.cgrp, foundGroup.isize, foundGroup.index,
421                       foundGroup.nalloc_index);
422     setName(foundName);
423 }
424
425 } // namespace gmx
426
427 /*!
428  * \param[in,out] sel   Selection element to set the type for.
429  * \param[in]     vtype Value type for the selection element.
430  *
431  * If the new type is \ref GROUP_VALUE or \ref POS_VALUE, the
432  * \ref SEL_ALLOCDATA flag is also set.
433  *
434  * This function should only be called at most once for each element,
435  * preferably right after calling _gmx_selelem_create().
436  */
437 void
438 _gmx_selelem_set_vtype(const gmx::SelectionTreeElementPointer &sel,
439                        e_selvalue_t                            vtype)
440 {
441     GMX_RELEASE_ASSERT(sel->type != SEL_BOOLEAN || vtype == GROUP_VALUE,
442                        "Boolean elements must have a group value");
443     GMX_RELEASE_ASSERT(sel->v.type == NO_VALUE || vtype == sel->v.type,
444                        "_gmx_selelem_set_vtype() called more than once");
445     sel->v.type = vtype;
446     if (vtype == GROUP_VALUE || vtype == POS_VALUE)
447     {
448         sel->flags |= SEL_ALLOCDATA;
449     }
450 }
451
452 /*!
453  * \param[in] method Method to free.
454  * \param[in] mdata  Method data to free.
455  */
456 void
457 _gmx_selelem_free_method(gmx_ana_selmethod_t *method, void *mdata)
458 {
459     sel_freefunc free_func = NULL;
460
461     /* Save the pointer to the free function. */
462     if (method && method->free)
463     {
464         free_func = method->free;
465     }
466
467     /* Free the method itself.
468      * Has to be done before freeing the method data, because parameter
469      * values are typically stored in the method data, and here we may
470      * access them. */
471     if (method)
472     {
473         int  i, j;
474
475         /* Free the memory allocated for the parameters that are not managed
476          * by the selection method itself. */
477         for (i = 0; i < method->nparams; ++i)
478         {
479             gmx_ana_selparam_t *param = &method->param[i];
480
481             if (param->val.u.ptr)
482             {
483                 if (param->val.type == GROUP_VALUE)
484                 {
485                     for (j = 0; j < param->val.nr; ++j)
486                     {
487                         gmx_ana_index_deinit(&param->val.u.g[j]);
488                     }
489                 }
490                 else if (param->val.type == POS_VALUE)
491                 {
492                     if (param->val.nalloc > 0)
493                     {
494                         delete[] param->val.u.p;
495                         _gmx_selvalue_setstore(&param->val, NULL);
496                     }
497                 }
498
499                 if (param->val.nalloc > 0)
500                 {
501                     sfree(param->val.u.ptr);
502                 }
503             }
504         }
505         sfree(method->param);
506         sfree(method);
507     }
508     /* Free method data. */
509     if (mdata)
510     {
511         if (free_func)
512         {
513             free_func(mdata);
514         }
515         else
516         {
517             sfree(mdata);
518         }
519     }
520 }
521
522 /*!
523  * \param[in] fp      File handle to receive the output.
524  * \param[in] sel     Root of the selection subtree to print.
525  * \param[in] bValues If true, the evaluated values of selection elements
526  *   are printed as well.
527  * \param[in] level   Indentation level, starting from zero.
528  */
529 void
530 _gmx_selelem_print_tree(FILE *fp, const gmx::SelectionTreeElement &sel,
531                         bool bValues, int level)
532 {
533     int          i;
534
535     fprintf(fp, "%*c %s %s", level*2+1, '*',
536             _gmx_selelem_type_str(sel), _gmx_sel_value_type_str(&sel.v));
537     if (!sel.name().empty())
538     {
539         fprintf(fp, " \"%s\"", sel.name().c_str());
540     }
541     fprintf(fp, " flg=");
542     if (sel.flags & SEL_FLAGSSET)
543     {
544         fprintf(fp, "s");
545     }
546     if (sel.flags & SEL_SINGLEVAL)
547     {
548         fprintf(fp, "S");
549     }
550     if (sel.flags & SEL_ATOMVAL)
551     {
552         fprintf(fp, "A");
553     }
554     if (sel.flags & SEL_VARNUMVAL)
555     {
556         fprintf(fp, "V");
557     }
558     if (sel.flags & SEL_DYNAMIC)
559     {
560         fprintf(fp, "D");
561     }
562     if (!(sel.flags & SEL_VALFLAGMASK))
563     {
564         fprintf(fp, "0");
565     }
566     if (sel.flags & SEL_ALLOCVAL)
567     {
568         fprintf(fp, "Av");
569     }
570     if (sel.flags & SEL_ALLOCDATA)
571     {
572         fprintf(fp, "Ad");
573     }
574     if (sel.mempool)
575     {
576         fprintf(fp, "P");
577     }
578     if (sel.type == SEL_CONST)
579     {
580         if (sel.v.type == INT_VALUE)
581         {
582             fprintf(fp, " %d", sel.v.u.i[0]);
583         }
584         else if (sel.v.type == REAL_VALUE)
585         {
586             fprintf(fp, " %f", sel.v.u.r[0]);
587         }
588         else if (sel.v.type == GROUP_VALUE)
589         {
590             const gmx_ana_index_t *g = sel.v.u.g;
591             if (!g || g->isize == 0)
592             {
593                 g = &sel.u.cgrp;
594             }
595             fprintf(fp, " (%d atoms)", g->isize);
596         }
597     }
598     else if (sel.type == SEL_BOOLEAN)
599     {
600         fprintf(fp, " %s", _gmx_selelem_boolean_type_str(sel));
601     }
602     else if (sel.type == SEL_EXPRESSION
603              && sel.u.expr.method->name == sm_compare.name)
604     {
605         _gmx_selelem_print_compare_info(fp, sel.u.expr.mdata);
606     }
607     if (sel.evaluate)
608     {
609         fprintf(fp, " eval=");
610         _gmx_sel_print_evalfunc_name(fp, sel.evaluate);
611     }
612     if (!(sel.flags & SEL_ALLOCVAL))
613     {
614         fprintf(fp, " (ext)");
615     }
616     fprintf(fp, "\n");
617
618     if ((sel.type == SEL_CONST && sel.v.type == GROUP_VALUE) || sel.type == SEL_ROOT)
619     {
620         const gmx_ana_index_t *g = sel.v.u.g;
621         if (!g || g->isize == 0 || sel.evaluate != NULL)
622         {
623             g = &sel.u.cgrp;
624         }
625         if (g->isize < 0)
626         {
627             fprintf(fp, "%*c group: (null)\n", level*2+1, ' ');
628         }
629         else if (g->isize > 0)
630         {
631             fprintf(fp, "%*c group:", level*2+1, ' ');
632             if (g->isize <= 20)
633             {
634                 for (i = 0; i < g->isize; ++i)
635                 {
636                     fprintf(fp, " %d", g->index[i] + 1);
637                 }
638             }
639             else
640             {
641                 fprintf(fp, " %d atoms", g->isize);
642             }
643             fprintf(fp, "\n");
644         }
645     }
646     else if (sel.type == SEL_EXPRESSION)
647     {
648         if (sel.u.expr.pc)
649         {
650             fprintf(fp, "%*c COM", level*2+3, '*');
651             fprintf(fp, "\n");
652         }
653     }
654
655     if (sel.cdata)
656     {
657         _gmx_selelem_print_compiler_info(fp, sel, level);
658     }
659
660     if (bValues && sel.type != SEL_CONST && sel.type != SEL_ROOT && sel.v.u.ptr)
661     {
662         fprintf(fp, "%*c value: ", level*2+1, ' ');
663         switch (sel.v.type)
664         {
665             case POS_VALUE:
666                 /* In normal use, the pointer should never be NULL, but it's
667                  * useful to have the check for debugging to avoid accidental
668                  * segfaults when printing the selection tree. */
669                 if (sel.v.u.p->x)
670                 {
671                     fprintf(fp, "(%f, %f, %f)",
672                             sel.v.u.p->x[0][XX], sel.v.u.p->x[0][YY],
673                             sel.v.u.p->x[0][ZZ]);
674                 }
675                 else
676                 {
677                     fprintf(fp, "(null)");
678                 }
679                 break;
680             case GROUP_VALUE:
681                 fprintf(fp, "%d atoms", sel.v.u.g->isize);
682                 if (sel.v.u.g->isize < 20)
683                 {
684                     if (sel.v.u.g->isize > 0)
685                     {
686                         fprintf(fp, ":");
687                     }
688                     for (i = 0; i < sel.v.u.g->isize; ++i)
689                     {
690                         fprintf(fp, " %d", sel.v.u.g->index[i] + 1);
691                     }
692                 }
693                 break;
694             default:
695                 fprintf(fp, "???");
696                 break;
697         }
698         fprintf(fp, "\n");
699     }
700
701     /* Print the subexpressions with one more level of indentation */
702     gmx::SelectionTreeElementPointer child = sel.child;
703     while (child)
704     {
705         if (!(sel.type == SEL_SUBEXPRREF && child->type == SEL_SUBEXPR))
706         {
707             _gmx_selelem_print_tree(fp, *child, bValues, level+1);
708         }
709         child = child->next;
710     }
711 }
712
713 /*!
714  * \param[in] root Root of the subtree to query.
715  * \returns true if \p root or any any of its elements require topology
716  *   information, false otherwise.
717  */
718 bool
719 _gmx_selelem_requires_top(const gmx::SelectionTreeElement &root)
720 {
721     if (root.type == SEL_EXPRESSION || root.type == SEL_MODIFIER)
722     {
723         if (root.u.expr.method && (root.u.expr.method->flags & SMETH_REQTOP))
724         {
725             return true;
726         }
727         if (root.u.expr.pc && gmx_ana_poscalc_requires_top(root.u.expr.pc))
728         {
729             return true;
730         }
731     }
732     gmx::SelectionTreeElementPointer child = root.child;
733     while (child)
734     {
735         if (_gmx_selelem_requires_top(*child))
736         {
737             return true;
738         }
739         child = child->next;
740     }
741     return false;
742 }