Sort all includes in src/gromacs
[alexxy/gromacs.git] / src / gromacs / selection / selelem.cpp
index bc9d99388abb889c551f902b593a37ff7ec4334a..76f65be97163fdfe2d6db303ef3eda0297ed12fc 100644 (file)
@@ -1,10 +1,10 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2009,2010,2011,2012, by the GROMACS development team, led by
- * David van der Spoel, Berk Hess, Erik Lindahl, and including many
- * others, as listed in the AUTHORS file in the top-level source
- * directory and at http://www.gromacs.org.
+ * Copyright (c) 2009,2010,2011,2012,2013,2014, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
  *
  * GROMACS is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public License
  * \author Teemu Murtola <teemu.murtola@gmail.com>
  * \ingroup module_selection
  */
-#include <cstring>
+#include "gmxpre.h"
 
-#include "gromacs/legacyheaders/smalloc.h"
+#include "selelem.h"
+
+#include <cstring>
 
 #include "gromacs/selection/indexutil.h"
-#include "gromacs/selection/poscalc.h"
 #include "gromacs/selection/position.h"
-#include "gromacs/selection/selmethod.h"
 #include "gromacs/utility/exceptions.h"
 #include "gromacs/utility/gmxassert.h"
+#include "gromacs/utility/smalloc.h"
+#include "gromacs/utility/stringutil.h"
 
 #include "keywords.h"
 #include "mempool.h"
-#include "selelem.h"
+#include "poscalc.h"
+#include "selmethod.h"
 
 /*!
  * \param[in] sel Selection for which the string is requested
 const char *
 _gmx_selelem_type_str(const gmx::SelectionTreeElement &sel)
 {
+    const char *p = NULL;
     switch (sel.type)
     {
-        case SEL_CONST:      return "CONST";
-        case SEL_EXPRESSION: return "EXPR";
-        case SEL_BOOLEAN:    return "BOOL";
-        case SEL_ARITHMETIC: return "ARITH";
-        case SEL_ROOT:       return "ROOT";
-        case SEL_SUBEXPR:    return "SUBEXPR";
-        case SEL_SUBEXPRREF: return "REF";
-        case SEL_GROUPREF:   return "GROUPREF";
-        case SEL_MODIFIER:   return "MODIFIER";
-    }
-    return NULL;
+        case SEL_CONST:      p = "CONST";    break;
+        case SEL_EXPRESSION: p = "EXPR";     break;
+        case SEL_BOOLEAN:    p = "BOOL";     break;
+        case SEL_ARITHMETIC: p = "ARITH";    break;
+        case SEL_ROOT:       p = "ROOT";     break;
+        case SEL_SUBEXPR:    p = "SUBEXPR";  break;
+        case SEL_SUBEXPRREF: p = "REF";      break;
+        case SEL_GROUPREF:   p = "GROUPREF"; break;
+        case SEL_MODIFIER:   p = "MODIFIER"; break;
+            // No default clause so we intentionally get compiler errors
+            // if new selection choices are added later.
+    }
+    return p;
 }
 
 /*!
@@ -90,30 +96,36 @@ _gmx_selelem_type_str(const gmx::SelectionTreeElement &sel)
 const char *
 _gmx_sel_value_type_str(const gmx_ana_selvalue_t *val)
 {
+    const char *p = NULL;
     switch (val->type)
     {
-        case NO_VALUE:       return "NONE";
-        case INT_VALUE:      return "INT";
-        case REAL_VALUE:     return "REAL";
-        case STR_VALUE:      return "STR";
-        case POS_VALUE:      return "VEC";
-        case GROUP_VALUE:    return "GROUP";
+        case NO_VALUE:       p = "NONE";  break;
+        case INT_VALUE:      p = "INT";   break;
+        case REAL_VALUE:     p = "REAL";  break;
+        case STR_VALUE:      p = "STR";   break;
+        case POS_VALUE:      p = "VEC";   break;
+        case GROUP_VALUE:    p = "GROUP"; break;
+            // No default clause so we intentionally get compiler errors
+            // if new selection choices are added later.
     }
-    return NULL;
+    return p;
 }
 
 /*! \copydoc _gmx_selelem_type_str() */
 const char *
 _gmx_selelem_boolean_type_str(const gmx::SelectionTreeElement &sel)
 {
+    const char *p = NULL;
     switch (sel.u.boolt)
     {
-        case BOOL_NOT:  return "NOT"; break;
-        case BOOL_AND:  return "AND"; break;
-        case BOOL_OR:   return "OR";  break;
-        case BOOL_XOR:  return "XOR"; break;
+        case BOOL_NOT:  p = "NOT"; break;
+        case BOOL_AND:  p = "AND"; break;
+        case BOOL_OR:   p = "OR";  break;
+        case BOOL_XOR:  p = "XOR"; break;
+            // No default clause so we intentionally get compiler errors
+            // if new selection choices are added later.
     }
-    return NULL;
+    return p;
 }
 
 
@@ -173,12 +185,6 @@ void SelectionTreeElement::freeValues()
                     sfree(v.u.s[i]);
                 }
                 break;
-            case POS_VALUE:
-                for (int i = 0; i < n; ++i)
-                {
-                    gmx_ana_pos_deinit(&v.u.p[i]);
-                }
-                break;
             case GROUP_VALUE:
                 for (int i = 0; i < n; ++i)
                 {
@@ -189,9 +195,16 @@ void SelectionTreeElement::freeValues()
                 break;
         }
     }
-    if (flags & SEL_ALLOCVAL)
+    if (v.nalloc > 0)
     {
-        sfree(v.u.ptr);
+        if (v.type == POS_VALUE)
+        {
+            delete [] v.u.p;
+        }
+        else
+        {
+            sfree(v.u.ptr);
+        }
     }
     _gmx_selvalue_setstore(&v, NULL);
     if (type == SEL_SUBEXPRREF && u.param)
@@ -209,11 +222,8 @@ SelectionTreeElement::freeExpressionData()
         u.expr.mdata  = NULL;
         u.expr.method = NULL;
         /* Free position data */
-        if (u.expr.pos)
-        {
-            gmx_ana_pos_free(u.expr.pos);
-            u.expr.pos = NULL;
-        }
+        delete u.expr.pos;
+        u.expr.pos = NULL;
         /* Free position calculation data */
         if (u.expr.pc)
         {
@@ -290,6 +300,151 @@ void SelectionTreeElement::mempoolRelease()
     }
 }
 
+void SelectionTreeElement::fillNameIfMissing(const char *selectionText)
+{
+    GMX_RELEASE_ASSERT(type == SEL_ROOT,
+                       "Should not be called for non-root elements");
+    if (name().empty())
+    {
+        // Check whether the actual selection given was from an external group,
+        // and if so, use the name of the external group.
+        SelectionTreeElementPointer child = this->child;
+        while (child->type == SEL_MODIFIER)
+        {
+            if (!child->child || child->child->type != SEL_SUBEXPRREF
+                || !child->child->child)
+            {
+                break;
+            }
+            child = child->child->child;
+        }
+        if (child->type == SEL_EXPRESSION
+            && child->child && child->child->type == SEL_SUBEXPRREF
+            && child->child->child)
+        {
+            if (child->child->child->type == SEL_CONST
+                && child->child->child->v.type == GROUP_VALUE)
+            {
+                setName(child->child->child->name());
+                return;
+            }
+            // If the group reference is still unresolved, leave the name empty
+            // and fill it later.
+            if (child->child->child->type == SEL_GROUPREF)
+            {
+                return;
+            }
+        }
+        // If there still is no name, use the selection string.
+        setName(selectionText);
+    }
+}
+
+void SelectionTreeElement::checkUnsortedAtoms(
+        bool bUnsortedAllowed, ExceptionInitializer *errors) const
+{
+    const bool bUnsortedSupported
+        = (type == SEL_CONST && v.type == GROUP_VALUE)
+            || type == SEL_ROOT || type == SEL_SUBEXPR || type == SEL_SUBEXPRREF
+            // TODO: Consolidate.
+            || type == SEL_MODIFIER
+            || (type == SEL_EXPRESSION && (u.expr.method->flags & SMETH_ALLOW_UNSORTED));
+
+    // TODO: For some complicated selections, this may result in the same
+    // index group reference being flagged as an error multiple times for the
+    // same selection.
+    SelectionTreeElementPointer child = this->child;
+    while (child)
+    {
+        child->checkUnsortedAtoms(bUnsortedAllowed && bUnsortedSupported,
+                                  errors);
+        child = child->next;
+    }
+
+    // The logic here is simplified by the fact that only constant groups can
+    // currently be the root cause of SEL_UNSORTED being set, so only those
+    // need to be considered in triggering the error.
+    if (!bUnsortedAllowed && (flags & SEL_UNSORTED)
+        && type == SEL_CONST && v.type == GROUP_VALUE)
+    {
+        std::string message = formatString(
+                    "Group '%s' cannot be used in selections except "
+                    "as a full value of the selection, "
+                    "because atom indices in it are not sorted and/or "
+                    "it contains duplicate atoms.",
+                    name().c_str());
+        errors->addNested(InconsistentInputError(message));
+    }
+}
+
+void SelectionTreeElement::resolveIndexGroupReference(
+        gmx_ana_indexgrps_t *grps, int natoms)
+{
+    GMX_RELEASE_ASSERT(type == SEL_GROUPREF,
+                       "Should only be called for index group reference elements");
+    if (grps == NULL)
+    {
+        std::string message = formatString(
+                    "Cannot match '%s', because index groups are not available.",
+                    name().c_str());
+        GMX_THROW(InconsistentInputError(message));
+    }
+
+    gmx_ana_index_t foundGroup;
+    std::string     foundName;
+    if (u.gref.name != NULL)
+    {
+        if (!gmx_ana_indexgrps_find(&foundGroup, &foundName, grps, u.gref.name))
+        {
+            std::string message = formatString(
+                        "Cannot match '%s', because no such index group can be found.",
+                        name().c_str());
+            GMX_THROW(InconsistentInputError(message));
+        }
+    }
+    else
+    {
+        if (!gmx_ana_indexgrps_extract(&foundGroup, &foundName, grps, u.gref.id))
+        {
+            std::string message = formatString(
+                        "Cannot match '%s', because no such index group can be found.",
+                        name().c_str());
+            GMX_THROW(InconsistentInputError(message));
+        }
+    }
+
+    if (!gmx_ana_index_check_sorted(&foundGroup))
+    {
+        flags |= SEL_UNSORTED;
+    }
+
+    sfree(u.gref.name);
+    type = SEL_CONST;
+    gmx_ana_index_set(&u.cgrp, foundGroup.isize, foundGroup.index,
+                      foundGroup.nalloc_index);
+    setName(foundName);
+
+    if (natoms > 0)
+    {
+        checkIndexGroup(natoms);
+    }
+}
+
+void SelectionTreeElement::checkIndexGroup(int natoms)
+{
+    GMX_RELEASE_ASSERT(type == SEL_CONST && v.type == GROUP_VALUE,
+                       "Should only be called for index group elements");
+    if (!gmx_ana_index_check_range(&u.cgrp, natoms))
+    {
+        std::string message = formatString(
+                    "Group '%s' cannot be used in selections, because it "
+                    "contains negative atom indices and/or references atoms "
+                    "not present (largest allowed atom index is %d).",
+                    name().c_str(), natoms);
+        GMX_THROW(InconsistentInputError(message));
+    }
+}
+
 } // namespace gmx
 
 /*!
@@ -357,9 +512,10 @@ _gmx_selelem_free_method(gmx_ana_selmethod_t *method, void *mdata)
                 }
                 else if (param->val.type == POS_VALUE)
                 {
-                    for (j = 0; j < param->val.nr; ++j)
+                    if (param->val.nalloc > 0)
                     {
-                        gmx_ana_pos_deinit(&param->val.u.p[j]);
+                        delete[] param->val.u.p;
+                        _gmx_selvalue_setstore(&param->val, NULL);
                     }
                 }