2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 2010,2011,2012,2013,2014,2015,2016, 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.
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.
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.
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.
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.
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.
37 * Implements gmx::SelectionCollection.
39 * \author Teemu Murtola <teemu.murtola@gmail.com>
40 * \ingroup module_selection
44 #include "selectioncollection.h"
53 #include "gromacs/onlinehelp/helpmanager.h"
54 #include "gromacs/onlinehelp/helpwritercontext.h"
55 #include "gromacs/options/basicoptions.h"
56 #include "gromacs/options/ioptionscontainer.h"
57 #include "gromacs/selection/selection.h"
58 #include "gromacs/selection/selhelp.h"
59 #include "gromacs/topology/mtop_util.h"
60 #include "gromacs/topology/topology.h"
61 #include "gromacs/trajectory/trajectoryframe.h"
62 #include "gromacs/utility/exceptions.h"
63 #include "gromacs/utility/filestream.h"
64 #include "gromacs/utility/gmxassert.h"
65 #include "gromacs/utility/smalloc.h"
66 #include "gromacs/utility/stringutil.h"
67 #include "gromacs/utility/textwriter.h"
74 #include "selectioncollection-impl.h"
76 #include "selmethod.h"
82 /********************************************************************
83 * SelectionCollection::Impl
86 SelectionCollection::Impl::Impl()
87 : debugLevel_(0), bExternalGroupsSet_(false), grps_(NULL
)
92 gmx_ana_index_clear(&sc_
.gall
);
94 sc_
.symtab
.reset(new SelectionParserSymbolTable
);
95 gmx_ana_index_clear(&requiredAtoms_
);
96 gmx_ana_selmethod_register_defaults(sc_
.symtab
.get());
100 SelectionCollection::Impl::~Impl()
103 // The tree must be freed before the SelectionData objects, since the
104 // tree may hold references to the position data in SelectionData.
107 for (int i
= 0; i
< sc_
.nvars
; ++i
)
109 sfree(sc_
.varstrs
[i
]);
112 gmx_ana_index_deinit(&sc_
.gall
);
115 _gmx_sel_mempool_destroy(sc_
.mempool
);
117 gmx_ana_index_deinit(&requiredAtoms_
);
122 SelectionCollection::Impl::clearSymbolTable()
132 * Reads a single selection line from stdin.
134 * \param[in] inputStream Stream to read from (typically the StandardInputStream).
135 * \param[in] statusWriter Stream to print prompts to (if NULL, no output is done).
136 * \param[out] line The read line in stored here.
137 * \returns true if something was read, false if at end of input.
139 * Handles line continuation, reading also the continuing line(s) in one call.
141 bool promptLine(TextInputStream
*inputStream
, TextWriter
*statusWriter
,
144 if (statusWriter
!= NULL
)
146 statusWriter
->writeString("> ");
148 if (!inputStream
->readLine(line
))
152 while (endsWith(*line
, "\\\n"))
154 line
->resize(line
->length() - 2);
155 if (statusWriter
!= NULL
)
157 statusWriter
->writeString("... ");
160 // Return value ignored, buffer remains empty and works correctly
161 // if there is nothing to read.
162 inputStream
->readLine(&buffer
);
163 line
->append(buffer
);
165 if (endsWith(*line
, "\n"))
167 line
->resize(line
->length() - 1);
169 else if (statusWriter
!= NULL
)
171 statusWriter
->writeLine();
177 * Helper function for tokenizing the input and pushing them to the parser.
179 * \param scanner Tokenizer data structure.
180 * \param parserState Parser data structure.
181 * \param[in] bInteractive Whether to operate in interactive mode.
183 * Repeatedly reads tokens using \p scanner and pushes them to the parser with
184 * \p parserState until there is no more input, or until enough input is given
185 * (only in interactive mode).
187 int runParserLoop(yyscan_t scanner
, _gmx_sel_yypstate
*parserState
,
190 int status
= YYPUSH_MORE
;
195 int token
= _gmx_sel_yylex(&value
, &location
, scanner
);
196 if (bInteractive
&& token
== 0)
200 status
= _gmx_sel_yypush_parse(parserState
, token
, &value
, &location
, scanner
);
202 while (status
== YYPUSH_MORE
);
203 _gmx_sel_lexer_rethrow_exception_if_occurred(scanner
);
208 * Print current status in response to empty line in interactive input.
210 * \param[in] writer Writer to use for the output.
211 * \param[in] sc Selection collection data structure.
212 * \param[in] grps Available index groups.
213 * \param[in] firstSelection Index of first selection from this interactive
215 * \param[in] maxCount Maximum number of selections.
216 * \param[in] context Context to print for what the selections are for.
217 * \param[in] bFirst Whether this is the header that is printed before
220 * Prints the available index groups and currently provided selections.
222 void printCurrentStatus(TextWriter
*writer
, gmx_ana_selcollection_t
*sc
,
223 gmx_ana_indexgrps_t
*grps
, size_t firstSelection
,
224 int maxCount
, const std::string
&context
, bool bFirst
)
228 writer
->writeLine("Available static index groups:");
229 gmx_ana_indexgrps_print(writer
, grps
, 0);
231 writer
->writeString("Specify ");
234 writer
->writeString("any number of selections");
236 else if (maxCount
== 1)
238 writer
->writeString("a selection");
242 writer
->writeString(formatString("%d selections", maxCount
));
244 writer
->writeString(formatString("%s%s:\n",
245 context
.empty() ? "" : " ", context
.c_str()));
246 writer
->writeString(formatString(
247 "(one per line, <enter> for status/groups, 'help' for help%s)\n",
248 maxCount
< 0 ? ", Ctrl-D to end" : ""));
249 if (!bFirst
&& (sc
->nvars
> 0 || sc
->sel
.size() > firstSelection
))
251 writer
->writeLine("Currently provided selections:");
252 for (int i
= 0; i
< sc
->nvars
; ++i
)
254 writer
->writeString(formatString(" %s\n", sc
->varstrs
[i
]));
256 for (size_t i
= firstSelection
; i
< sc
->sel
.size(); ++i
)
258 writer
->writeString(formatString(
260 static_cast<int>(i
- firstSelection
+ 1),
261 sc
->sel
[i
]->selectionText()));
266 = maxCount
- static_cast<int>(sc
->sel
.size() - firstSelection
);
267 writer
->writeString(formatString(
268 "(%d more selection%s required)\n",
269 remaining
, remaining
> 1 ? "s" : ""));
275 * Prints selection help in interactive selection input.
277 * \param[in] writer Writer to use for the output.
278 * \param[in] sc Selection collection data structure.
279 * \param[in] line Line of user input requesting help (starting with `help`).
281 * Initializes the selection help if not yet initialized, and finds the help
282 * topic based on words on the input line.
284 void printHelp(TextWriter
*writer
, gmx_ana_selcollection_t
*sc
,
285 const std::string
&line
)
287 if (sc
->rootHelp
.get() == NULL
)
289 sc
->rootHelp
= createSelectionHelpTopic();
291 HelpWriterContext
context(writer
, eHelpOutputFormat_Console
);
292 HelpManager
manager(*sc
->rootHelp
, context
);
295 std::vector
<std::string
> topic
= splitString(line
);
296 std::vector
<std::string
>::const_iterator value
;
297 // First item in the list is the 'help' token.
298 for (value
= topic
.begin() + 1; value
!= topic
.end(); ++value
)
300 manager
.enterTopic(*value
);
303 catch (const InvalidInputError
&ex
)
305 writer
->writeLine(ex
.what());
308 manager
.writeCurrentTopic();
312 * Helper function that runs the parser once the tokenizer has been
315 * \param[in,out] scanner Scanner data structure.
316 * \param[in] inputStream Stream to use for input (currently only with
317 * `bInteractive==true`).
318 * \param[in] bInteractive Whether to use a line-based reading
319 * algorithm designed for interactive input.
320 * \param[in] maxnr Maximum number of selections to parse
321 * (if -1, parse as many as provided by the user).
322 * \param[in] context Context to print for what the selections are for.
323 * \returns Vector of parsed selections.
324 * \throws std::bad_alloc if out of memory.
325 * \throws InvalidInputError if there is a parsing error.
327 * Used internally to implement parseInteractive(), parseFromFile() and
330 SelectionList
runParser(yyscan_t scanner
, TextInputStream
*inputStream
,
331 bool bInteractive
, int maxnr
, const std::string
&context
)
333 std::shared_ptr
<void> scannerGuard(scanner
, &_gmx_sel_free_lexer
);
334 gmx_ana_selcollection_t
*sc
= _gmx_sel_lexer_selcollection(scanner
);
335 gmx_ana_indexgrps_t
*grps
= _gmx_sel_lexer_indexgrps(scanner
);
337 size_t oldCount
= sc
->sel
.size();
339 std::shared_ptr
<_gmx_sel_yypstate
> parserState(
340 _gmx_sel_yypstate_new(), &_gmx_sel_yypstate_delete
);
343 TextWriter
*statusWriter
= _gmx_sel_lexer_get_status_writer(scanner
);
344 if (statusWriter
!= NULL
)
346 printCurrentStatus(statusWriter
, sc
, grps
, oldCount
, maxnr
, context
, true);
350 while (promptLine(inputStream
, statusWriter
, &line
))
352 if (statusWriter
!= NULL
)
354 line
= stripString(line
);
357 printCurrentStatus(statusWriter
, sc
, grps
, oldCount
, maxnr
, context
, false);
360 if (startsWith(line
, "help")
361 && (line
[4] == 0 || std::isspace(line
[4])))
363 printHelp(statusWriter
, sc
, line
);
368 _gmx_sel_set_lex_input_str(scanner
, line
.c_str());
369 status
= runParserLoop(scanner
, parserState
.get(), true);
370 if (status
!= YYPUSH_MORE
)
372 // TODO: Check if there is more input, and issue an
373 // error/warning if some input was ignored.
374 goto early_termination
;
379 status
= _gmx_sel_yypush_parse(parserState
.get(), 0, NULL
,
382 // TODO: Remove added selections from the collection if parsing failed?
383 _gmx_sel_lexer_rethrow_exception_if_occurred(scanner
);
385 GMX_RELEASE_ASSERT(status
== 0,
386 "Parser errors should have resulted in an exception");
390 int status
= runParserLoop(scanner
, parserState
.get(), false);
391 GMX_RELEASE_ASSERT(status
== 0,
392 "Parser errors should have resulted in an exception");
395 scannerGuard
.reset();
396 int nr
= sc
->sel
.size() - oldCount
;
397 if (maxnr
> 0 && nr
!= maxnr
)
400 = formatString("Too few selections provided; got %d, expected %d",
402 GMX_THROW(InvalidInputError(message
));
405 SelectionList result
;
406 SelectionDataList::const_iterator i
;
408 for (i
= sc
->sel
.begin() + oldCount
; i
!= sc
->sel
.end(); ++i
)
410 result
.emplace_back(i
->get());
416 * Checks that index groups have valid atom indices.
418 * \param[in] root Root of selection tree to process.
419 * \param[in] natoms Maximum number of atoms that the selections are set
421 * \param errors Object for reporting any error messages.
422 * \throws std::bad_alloc if out of memory.
424 * Recursively checks the selection tree for index groups.
425 * Each found group is checked that it only contains atom indices that match
426 * the topology/maximum number of atoms set for the selection collection.
427 * Any issues are reported to \p errors.
429 void checkExternalGroups(const SelectionTreeElementPointer
&root
,
431 ExceptionInitializer
*errors
)
433 if (root
->type
== SEL_CONST
&& root
->v
.type
== GROUP_VALUE
)
437 root
->checkIndexGroup(natoms
);
439 catch (const UserInputError
&)
441 errors
->addCurrentExceptionAsNested();
445 SelectionTreeElementPointer child
= root
->child
;
448 checkExternalGroups(child
, natoms
, errors
);
453 //! Checks whether the given topology properties are available.
454 void checkTopologyProperties(const gmx_mtop_t
*top
,
455 const SelectionTopologyProperties
&props
)
461 GMX_THROW(InconsistentInputError("Selection requires topology information, but none provided"));
465 if (props
.needsMasses
&& !gmx_mtop_has_masses(top
))
467 GMX_THROW(InconsistentInputError("Selection requires mass information, but it is not available in the topology"));
474 void SelectionCollection::Impl::resolveExternalGroups(
475 const SelectionTreeElementPointer
&root
,
476 ExceptionInitializer
*errors
)
479 if (root
->type
== SEL_GROUPREF
)
483 root
->resolveIndexGroupReference(grps_
, sc_
.gall
.isize
);
485 catch (const UserInputError
&)
487 errors
->addCurrentExceptionAsNested();
491 SelectionTreeElementPointer child
= root
->child
;
494 resolveExternalGroups(child
, errors
);
495 root
->flags
|= (child
->flags
& SEL_UNSORTED
);
501 bool SelectionCollection::Impl::areForcesRequested() const
503 for (const auto &sel
: sc_
.sel
)
505 if (sel
->hasFlag(gmx::efSelection_EvaluateForces
))
514 SelectionTopologyProperties
515 SelectionCollection::Impl::requiredTopologyPropertiesForPositionType(
516 const std::string
&post
, bool forces
) const
518 SelectionTopologyProperties props
;
521 switch (PositionCalculationCollection::requiredTopologyInfoForType(post
.c_str(), forces
))
523 case PositionCalculationCollection::RequiredTopologyInfo::None
:
525 case PositionCalculationCollection::RequiredTopologyInfo::Topology
:
526 props
.merge(SelectionTopologyProperties::topology());
528 case PositionCalculationCollection::RequiredTopologyInfo::TopologyAndMasses
:
529 props
.merge(SelectionTopologyProperties::masses());
537 /********************************************************************
538 * SelectionCollection
541 SelectionCollection::SelectionCollection()
547 SelectionCollection::~SelectionCollection()
553 SelectionCollection::initOptions(IOptionsContainer
*options
,
554 SelectionTypeOption selectionTypeOption
)
556 const char * const debug_levels
[]
557 = { "no", "basic", "compile", "eval", "full" };
559 const char *const *postypes
= PositionCalculationCollection::typeEnumValues
;
560 options
->addOption(StringOption("selrpos")
561 .enumValueFromNullTerminatedArray(postypes
)
562 .store(&impl_
->rpost_
).defaultValue(postypes
[0])
563 .description("Selection reference positions"));
564 if (selectionTypeOption
== IncludeSelectionTypeOption
)
566 options
->addOption(StringOption("seltype")
567 .enumValueFromNullTerminatedArray(postypes
)
568 .store(&impl_
->spost_
).defaultValue(postypes
[0])
569 .description("Default selection output positions"));
573 impl_
->spost_
= postypes
[0];
575 GMX_RELEASE_ASSERT(impl_
->debugLevel_
>= 0 && impl_
->debugLevel_
<= 4,
576 "Debug level out of range");
577 options
->addOption(EnumIntOption("seldebug").hidden(impl_
->debugLevel_
== 0)
578 .enumValue(debug_levels
).store(&impl_
->debugLevel_
)
579 .description("Print out selection trees for debugging"));
584 SelectionCollection::setReferencePosType(const char *type
)
586 GMX_RELEASE_ASSERT(type
!= NULL
, "Cannot assign NULL position type");
587 // Check that the type is valid, throw if it is not.
588 e_poscalc_t dummytype
;
590 PositionCalculationCollection::typeFromEnum(type
, &dummytype
, &dummyflags
);
591 impl_
->rpost_
= type
;
596 SelectionCollection::setOutputPosType(const char *type
)
598 GMX_RELEASE_ASSERT(type
!= NULL
, "Cannot assign NULL position type");
599 // Check that the type is valid, throw if it is not.
600 e_poscalc_t dummytype
;
602 PositionCalculationCollection::typeFromEnum(type
, &dummytype
, &dummyflags
);
603 impl_
->spost_
= type
;
608 SelectionCollection::setDebugLevel(int debugLevel
)
610 impl_
->debugLevel_
= debugLevel
;
615 SelectionCollection::setTopology(gmx_mtop_t
*top
, int natoms
)
617 GMX_RELEASE_ASSERT(natoms
> 0 || top
!= NULL
,
618 "The number of atoms must be given if there is no topology");
619 checkTopologyProperties(top
, requiredTopologyProperties());
620 // Get the number of atoms from the topology if it is not given.
623 natoms
= top
->natoms
;
625 if (impl_
->bExternalGroupsSet_
)
627 ExceptionInitializer
errors("Invalid index group references encountered");
628 SelectionTreeElementPointer root
= impl_
->sc_
.root
;
631 checkExternalGroups(root
, natoms
, &errors
);
634 if (errors
.hasNestedExceptions())
636 GMX_THROW(InconsistentInputError(errors
));
639 gmx_ana_selcollection_t
*sc
= &impl_
->sc_
;
640 // Do this first, as it allocates memory, while the others don't throw.
641 gmx_ana_index_init_simple(&sc
->gall
, natoms
);
643 sc
->pcc
.setTopology(top
);
648 SelectionCollection::setIndexGroups(gmx_ana_indexgrps_t
*grps
)
650 GMX_RELEASE_ASSERT(grps
== NULL
|| !impl_
->bExternalGroupsSet_
,
651 "Can only set external groups once or clear them afterwards");
653 impl_
->bExternalGroupsSet_
= true;
655 ExceptionInitializer
errors("Invalid index group reference(s)");
656 SelectionTreeElementPointer root
= impl_
->sc_
.root
;
659 impl_
->resolveExternalGroups(root
, &errors
);
660 root
->checkUnsortedAtoms(true, &errors
);
663 if (errors
.hasNestedExceptions())
665 GMX_THROW(InconsistentInputError(errors
));
667 for (size_t i
= 0; i
< impl_
->sc_
.sel
.size(); ++i
)
669 impl_
->sc_
.sel
[i
]->refreshName();
673 SelectionTopologyProperties
674 SelectionCollection::requiredTopologyProperties() const
676 SelectionTopologyProperties props
;
678 // These should not throw, because has been checked earlier.
679 props
.merge(impl_
->requiredTopologyPropertiesForPositionType(impl_
->rpost_
, false));
680 const bool forcesRequested
= impl_
->areForcesRequested();
681 props
.merge(impl_
->requiredTopologyPropertiesForPositionType(impl_
->spost_
,
684 SelectionTreeElementPointer sel
= impl_
->sc_
.root
;
685 while (sel
&& !props
.hasAll())
687 props
.merge(sel
->requiredTopologyProperties());
695 SelectionCollection::requiresIndexGroups() const
697 SelectionTreeElementPointer sel
= impl_
->sc_
.root
;
700 if (sel
->requiresIndexGroups())
711 SelectionCollection::parseFromStdin(int count
, bool bInteractive
,
712 const std::string
&context
)
714 return parseInteractive(count
, &StandardInputStream::instance(),
715 bInteractive
? &TextOutputFile::standardError() : NULL
,
722 //! Helper function to initialize status writer for interactive selection parsing.
723 std::unique_ptr
<TextWriter
> initStatusWriter(TextOutputStream
*statusStream
)
725 std::unique_ptr
<TextWriter
> statusWriter
;
726 if (statusStream
!= NULL
)
728 statusWriter
.reset(new TextWriter(statusStream
));
729 statusWriter
->wrapperSettings().setLineLength(78);
737 SelectionCollection::parseInteractive(int count
,
738 TextInputStream
*inputStream
,
739 TextOutputStream
*statusStream
,
740 const std::string
&context
)
744 const std::unique_ptr
<TextWriter
> statusWriter(
745 initStatusWriter(statusStream
));
746 _gmx_sel_init_lexer(&scanner
, &impl_
->sc_
, statusWriter
.get(),
747 count
, impl_
->bExternalGroupsSet_
, impl_
->grps_
);
748 return runParser(scanner
, inputStream
, true, count
, context
);
753 SelectionCollection::parseFromFile(const std::string
&filename
)
759 TextInputFile
file(filename
);
760 // TODO: Exception-safe way of using the lexer.
761 _gmx_sel_init_lexer(&scanner
, &impl_
->sc_
, NULL
, -1,
762 impl_
->bExternalGroupsSet_
,
764 _gmx_sel_set_lex_input_file(scanner
, file
.handle());
765 return runParser(scanner
, NULL
, false, -1, std::string());
767 catch (GromacsException
&ex
)
769 ex
.prependContext(formatString(
770 "Error in parsing selections from file '%s'",
778 SelectionCollection::parseFromString(const std::string
&str
)
782 _gmx_sel_init_lexer(&scanner
, &impl_
->sc_
, NULL
, -1,
783 impl_
->bExternalGroupsSet_
,
785 _gmx_sel_set_lex_input_str(scanner
, str
.c_str());
786 return runParser(scanner
, NULL
, false, -1, std::string());
791 SelectionCollection::compile()
793 checkTopologyProperties(impl_
->sc_
.top
, requiredTopologyProperties());
794 if (!impl_
->bExternalGroupsSet_
)
796 setIndexGroups(NULL
);
798 if (impl_
->debugLevel_
>= 1)
800 printTree(stderr
, false);
803 SelectionCompiler compiler
;
804 compiler
.compile(this);
806 if (impl_
->debugLevel_
>= 1)
808 std::fprintf(stderr
, "\n");
809 printTree(stderr
, false);
810 std::fprintf(stderr
, "\n");
811 impl_
->sc_
.pcc
.printTree(stderr
);
812 std::fprintf(stderr
, "\n");
814 impl_
->sc_
.pcc
.initEvaluation();
815 if (impl_
->debugLevel_
>= 1)
817 impl_
->sc_
.pcc
.printTree(stderr
);
818 std::fprintf(stderr
, "\n");
821 // TODO: It would be nicer to associate the name of the selection option
822 // (if available) to the error message.
823 SelectionDataList::const_iterator iter
;
824 for (iter
= impl_
->sc_
.sel
.begin(); iter
!= impl_
->sc_
.sel
.end(); ++iter
)
826 const internal::SelectionData
&sel
= **iter
;
827 if (sel
.hasFlag(efSelection_OnlyAtoms
))
829 if (!sel
.hasOnlyAtoms())
831 std::string message
= formatString(
832 "Selection '%s' does not evaluate to individual atoms. "
833 "This is not allowed in this context.",
834 sel
.selectionText());
835 GMX_THROW(InvalidInputError(message
));
837 if (sel
.hasFlag(efSelection_OnlySorted
))
839 if (!sel
.hasSortedAtomIndices())
841 const std::string message
= formatString(
842 "Selection '%s' does not evaluate to atoms in an "
843 "ascending (sorted) order. "
844 "This is not allowed in this context.",
845 sel
.selectionText());
846 GMX_THROW(InvalidInputError(message
));
850 if (sel
.hasFlag(efSelection_DisallowEmpty
))
852 if (sel
.posCount() == 0)
854 std::string message
= formatString(
855 "Selection '%s' never matches any atoms.",
856 sel
.selectionText());
857 GMX_THROW(InvalidInputError(message
));
861 impl_
->rpost_
.clear();
862 impl_
->spost_
.clear();
867 SelectionCollection::evaluate(t_trxframe
*fr
, t_pbc
*pbc
)
869 checkTopologyProperties(impl_
->sc_
.top
, requiredTopologyProperties());
873 gmx_ana_index_set(&g
, fr
->natoms
, fr
->index
, 0);
874 GMX_RELEASE_ASSERT(gmx_ana_index_check_sorted(&g
),
875 "Only trajectories with atoms in ascending order "
876 "are currently supported");
877 if (!gmx_ana_index_contains(&g
, &impl_
->requiredAtoms_
))
879 const std::string message
= formatString(
880 "Trajectory does not contain all atoms required for "
881 "evaluating the provided selections.");
882 GMX_THROW(InconsistentInputError(message
));
887 const int maxAtomIndex
= gmx_ana_index_get_max_index(&impl_
->requiredAtoms_
);
888 if (fr
->natoms
<= maxAtomIndex
)
890 const std::string message
= formatString(
891 "Trajectory has less atoms (%d) than what is required for "
892 "evaluating the provided selections (atoms up to index %d "
893 "are required).", fr
->natoms
, maxAtomIndex
+ 1);
894 GMX_THROW(InconsistentInputError(message
));
897 impl_
->sc_
.pcc
.initFrame(fr
);
899 SelectionEvaluator evaluator
;
900 evaluator
.evaluate(this, fr
, pbc
);
902 if (impl_
->debugLevel_
>= 3)
904 std::fprintf(stderr
, "\n");
905 printTree(stderr
, true);
911 SelectionCollection::evaluateFinal(int nframes
)
913 SelectionEvaluator evaluator
;
914 evaluator
.evaluateFinal(this, nframes
);
919 SelectionCollection::printTree(FILE *fp
, bool bValues
) const
921 SelectionTreeElementPointer sel
= impl_
->sc_
.root
;
924 _gmx_selelem_print_tree(fp
, *sel
, bValues
, 0);
931 SelectionCollection::printXvgrInfo(FILE *out
) const
933 const gmx_ana_selcollection_t
&sc
= impl_
->sc_
;
934 std::fprintf(out
, "# Selections:\n");
935 for (int i
= 0; i
< sc
.nvars
; ++i
)
937 std::fprintf(out
, "# %s\n", sc
.varstrs
[i
]);
939 for (size_t i
= 0; i
< sc
.sel
.size(); ++i
)
941 std::fprintf(out
, "# %s\n", sc
.sel
[i
]->selectionText());
943 std::fprintf(out
, "#\n");