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