Sort all includes in src/gromacs
[alexxy/gromacs.git] / src / gromacs / selection / selectioncollection.cpp
index 09f24e03c5faf90968ef74b3c38fd6c1801f57a8..f4bfd210a0663e69171982c1769970f3d5a9dc5f 100644 (file)
@@ -39,6 +39,8 @@
  * \author Teemu Murtola <teemu.murtola@gmail.com>
  * \ingroup module_selection
  */
+#include "gmxpre.h"
+
 #include "selectioncollection.h"
 
 #include <cctype>
 
 #include <boost/shared_ptr.hpp>
 
+#include "gromacs/fileio/trx.h"
 #include "gromacs/legacyheaders/oenv.h"
-#include "gromacs/legacyheaders/xvgr.h"
-
 #include "gromacs/onlinehelp/helpmanager.h"
 #include "gromacs/onlinehelp/helpwritercontext.h"
 #include "gromacs/options/basicoptions.h"
 #include "gromacs/options/options.h"
 #include "gromacs/selection/selection.h"
+#include "gromacs/selection/selhelp.h"
+#include "gromacs/topology/topology.h"
 #include "gromacs/utility/exceptions.h"
 #include "gromacs/utility/file.h"
 #include "gromacs/utility/gmxassert.h"
 #include "parser.h"
 #include "poscalc.h"
 #include "scanner.h"
-#include "selection.h"
 #include "selectioncollection-impl.h"
 #include "selelem.h"
-#include "selhelp.h"
 #include "selmethod.h"
 #include "symrec.h"
 
@@ -84,7 +85,7 @@ namespace gmx
  */
 
 SelectionCollection::Impl::Impl()
-    : debugLevel_(0), bExternalGroupsSet_(false), grps_(NULL)
+    : maxAtomIndex_(0), debugLevel_(0), bExternalGroupsSet_(false), grps_(NULL)
 {
     sc_.nvars     = 0;
     sc_.varstrs   = NULL;
@@ -423,6 +424,44 @@ early_termination:
     return result;
 }
 
+/*! \brief
+ * Checks that index groups have valid atom indices.
+ *
+ * \param[in]    root    Root of selection tree to process.
+ * \param[in]    natoms  Maximum number of atoms that the selections are set
+ *     to evaluate.
+ * \param        errors  Object for reporting any error messages.
+ * \throws std::bad_alloc if out of memory.
+ *
+ * Recursively checks the selection tree for index groups.
+ * Each found group is checked that it only contains atom indices that match
+ * the topology/maximum number of atoms set for the selection collection.
+ * Any issues are reported to \p errors.
+ */
+void checkExternalGroups(const SelectionTreeElementPointer &root,
+                         int                                natoms,
+                         ExceptionInitializer              *errors)
+{
+    if (root->type == SEL_CONST && root->v.type == GROUP_VALUE)
+    {
+        try
+        {
+            root->checkIndexGroup(natoms);
+        }
+        catch (const UserInputError &)
+        {
+            errors->addCurrentExceptionAsNested();
+        }
+    }
+
+    SelectionTreeElementPointer child = root->child;
+    while (child)
+    {
+        checkExternalGroups(child, natoms, errors);
+        child = child->next;
+    }
+}
+
 }   // namespace
 
 
@@ -435,7 +474,7 @@ void SelectionCollection::Impl::resolveExternalGroups(
     {
         try
         {
-            root->resolveIndexGroupReference(grps_);
+            root->resolveIndexGroupReference(grps_, sc_.gall.isize);
         }
         catch (const UserInputError &)
         {
@@ -447,7 +486,8 @@ void SelectionCollection::Impl::resolveExternalGroups(
     while (child)
     {
         resolveExternalGroups(child, errors);
-        child = child->next;
+        root->flags |= (child->flags & SEL_UNSORTED);
+        child        = child->next;
     }
 }
 
@@ -551,6 +591,20 @@ SelectionCollection::setTopology(t_topology *top, int natoms)
     {
         natoms = top->atoms.nr;
     }
+    if (impl_->bExternalGroupsSet_)
+    {
+        ExceptionInitializer        errors("Invalid index group references encountered");
+        SelectionTreeElementPointer root = impl_->sc_.root;
+        while (root)
+        {
+            checkExternalGroups(root, natoms, &errors);
+            root = root->next;
+        }
+        if (errors.hasNestedExceptions())
+        {
+            GMX_THROW(InconsistentInputError(errors));
+        }
+    }
     gmx_ana_selcollection_t *sc = &impl_->sc_;
     // Do this first, as it allocates memory, while the others don't throw.
     gmx_ana_index_init_simple(&sc->gall, natoms);
@@ -567,11 +621,12 @@ SelectionCollection::setIndexGroups(gmx_ana_indexgrps_t *grps)
     impl_->grps_               = grps;
     impl_->bExternalGroupsSet_ = true;
 
-    ExceptionInitializer        errors("Unknown index group references encountered");
+    ExceptionInitializer        errors("Invalid index group reference(s)");
     SelectionTreeElementPointer root = impl_->sc_.root;
     while (root)
     {
         impl_->resolveExternalGroups(root, &errors);
+        root->checkUnsortedAtoms(true, &errors);
         root = root->next;
     }
     if (errors.hasNestedExceptions())
@@ -720,7 +775,7 @@ SelectionCollection::compile()
         const internal::SelectionData &sel = **iter;
         if (sel.hasFlag(efSelection_OnlyAtoms))
         {
-            if (sel.type() != INDEX_ATOM)
+            if (!sel.hasOnlyAtoms())
             {
                 std::string message = formatString(
                             "Selection '%s' does not evaluate to individual atoms. "
@@ -746,6 +801,14 @@ SelectionCollection::compile()
 void
 SelectionCollection::evaluate(t_trxframe *fr, t_pbc *pbc)
 {
+    if (fr->natoms <= impl_->maxAtomIndex_)
+    {
+        std::string message = formatString(
+                    "Trajectory has less atoms (%d) than what is required for "
+                    "evaluating the provided selections (atoms up to index %d "
+                    "are required).", fr->natoms, impl_->maxAtomIndex_ + 1);
+        GMX_THROW(InconsistentInputError(message));
+    }
     impl_->sc_.pcc.initFrame();
 
     SelectionEvaluator evaluator;
@@ -798,11 +861,4 @@ SelectionCollection::printXvgrInfo(FILE *out, output_env_t oenv) const
     }
 }
 
-// static
-HelpTopicPointer
-SelectionCollection::createDefaultHelpTopic()
-{
-    return createSelectionHelpTopic();
-}
-
 } // namespace gmx