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