Merge branch 'cpp-analysis'
authorTeemu Murtola <teemu.murtola@cbr.su.se>
Sun, 26 Dec 2010 16:58:28 +0000 (18:58 +0200)
committerTeemu Murtola <teemu.murtola@cbr.su.se>
Sun, 26 Dec 2010 16:58:28 +0000 (18:58 +0200)
Header installation does not yet work.

Conflicts:
src/gromacs/CMakeLists.txt
src/gromacs/options/tests/CMakeLists.txt
src/gromacs/selection/CMakeLists.txt
src/gromacs/selection/params.cpp
src/gromacs/selection/regenerate_parser.sh
src/gromacs/selection/selcollection.h
src/gromacs/selection/selection.cpp
src/gromacs/selection/selhelp.cpp
src/gromacs/selection/sm_keywords.cpp
src/gromacs/trajana/trajana.cpp
src/gromacs/trajana/trajana.h
src/tools/CMakeLists.txt

53 files changed:
1  2 
CMakeLists.txt
src/CMakeLists.txt
src/config.h.cmakein
src/gromacs/CMakeLists.txt
src/gromacs/analysisdata/CMakeLists.txt
src/gromacs/legacyheaders/gmxfio.h
src/gromacs/options/tests/CMakeLists.txt
src/gromacs/selection/CMakeLists.txt
src/gromacs/selection/centerofmass.cpp
src/gromacs/selection/centerofmass.h
src/gromacs/selection/compiler.cpp
src/gromacs/selection/evaluate.cpp
src/gromacs/selection/evaluate.h
src/gromacs/selection/indexutil.cpp
src/gromacs/selection/indexutil.h
src/gromacs/selection/mempool.cpp
src/gromacs/selection/nbsearch.cpp
src/gromacs/selection/nbsearch.h
src/gromacs/selection/params.cpp
src/gromacs/selection/parsetree.cpp
src/gromacs/selection/parsetree.h
src/gromacs/selection/poscalc.cpp
src/gromacs/selection/poscalc.h
src/gromacs/selection/position.cpp
src/gromacs/selection/position.h
src/gromacs/selection/scanner_internal.cpp
src/gromacs/selection/selection.cpp
src/gromacs/selection/selelem.cpp
src/gromacs/selection/selelem.h
src/gromacs/selection/selhelp.cpp
src/gromacs/selection/selmethod.cpp
src/gromacs/selection/selmethod.h
src/gromacs/selection/selparam.h
src/gromacs/selection/selvalue.cpp
src/gromacs/selection/selvalue.h
src/gromacs/selection/sm_compare.cpp
src/gromacs/selection/sm_distance.cpp
src/gromacs/selection/sm_insolidangle.cpp
src/gromacs/selection/sm_keywords.cpp
src/gromacs/selection/sm_merge.cpp
src/gromacs/selection/sm_permute.cpp
src/gromacs/selection/sm_position.cpp
src/gromacs/selection/sm_same.cpp
src/gromacs/selection/sm_simple.cpp
src/gromacs/selection/symrec.cpp
src/gromacs/selection/tests/CMakeLists.txt
src/gromacs/trajectoryanalysis/CMakeLists.txt
src/gromacs/trajectoryanalysis/analysismodule-impl.h
src/gromacs/trajectoryanalysis/runnercommon.cpp
src/gromacs/trajectoryanalysis/tests/CMakeLists.txt
src/programs/CMakeLists.txt
src/programs/g_ana/CMakeLists.txt
src/tools/CMakeLists.txt

diff --cc CMakeLists.txt
Simple merge
index 22065465344ed28f8ee302071ba6e2291a899a1e,e5b19f01e1038877d27845eeeaa22de6d7f7adca..d89435364ee004385ec5dfa783140efcb839b3ce
@@@ -1,7 -1,10 +1,8 @@@
  configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.cmakein ${CMAKE_CURRENT_BINARY_DIR}/config.h)
  
 -add_subdirectory(gmxlib)
 -add_subdirectory(mdlib)
  add_subdirectory(gromacs)
  add_subdirectory(kernel)
+ add_subdirectory(programs)
  
  if(NOT GMX_FAHCORE)
    add_subdirectory(tools)
Simple merge
index 51d7c5fb03881549159adbaf1f4ec569a81ab814,c7203e3097915dc1c276effd735174dc9719c4af..4ca221309da7066d8132b6941e57d70da7cb804f
@@@ -1,84 -1,15 +1,85 @@@
 -include_directories(${CMAKE_CURRENT_SOURCE_DIR}/..)
 +set(LIBGROMACS_SOURCES)
  
 +add_subdirectory(legacyheaders)
 +add_subdirectory(gmxlib)
 +add_subdirectory(mdlib)
++add_subdirectory(analysisdata)
 +add_subdirectory(errorreporting)
 +add_subdirectory(fatalerror)
  add_subdirectory(options)
  add_subdirectory(selection)
list(APPEND LIBGROMACS_SOURCES trajana/trajana.cpp)
add_subdirectory(trajectoryanalysis)
  
 -file(GLOB GMXLIB_SOURCES */*.cpp */*/*.cpp)
 -file(GLOB_RECURSE NOT_GMXLIB_SOURCES */tests/*.cpp)
 -list(REMOVE_ITEM GMXLIB_SOURCES ${NOT_GMXLIB_SOURCES})
 +file(GLOB LIBGROMACS_HEADERS *.h)
 +install(FILES ${LIBGROMACS_HEADERS} DESTINATION ${INCL_INSTALL_DIR}/gromacs
 +        COMPONENT development)
  
 -add_library(gromacs ${GMXLIB_SOURCES})
 -target_link_libraries(gromacs gmx ${GMX_EXTRA_LIBRARIES} ${THREAD_LIB})
 -set_target_properties(gromacs PROPERTIES OUTPUT_NAME "gromacs${GMX_LIBS_SUFFIX}" SOVERSION ${SOVERSION} INSTALL_NAME_DIR "${LIB_INSTALL_DIR}")
 +# only fiddle with assembly kernels if we're not doing OpenMM build
 +if(NOT GMX_OPENMM) 
 +if(GMX_ASM_USEASM-NASM)
 +  enable_language(ASM-NASM)
 +  # if NASM is used, we need a special build command for windows...
 +  FOREACH(SRC ${GMX_SSEKERNEL_ASM_SRC})
 +    GET_FILENAME_COMPONENT(FILE_BASE ${SRC} NAME_WE)
 +    SET(OBJ ${CMAKE_CURRENT_BINARY_DIR}/${FILE_BASE}${CMAKE_C_OUTPUT_EXTENSION})
  
 -install(TARGETS gromacs DESTINATION ${LIB_INSTALL_DIR})
 +    ADD_CUSTOM_COMMAND(OUTPUT ${OBJ}
 +                       MAIN_DEPENDENCY ${SRC}
 +                       COMMAND ${CMAKE_ASM-NASM_COMPILER} -f ${CMAKE_ASM-NASM_OBJECT_FORMAT} -o ${OBJ} ${SRC})
 +
 +    SET(ALL_ASM_OBJS ${ALL_ASM_OBJS} ${OBJ})
 +  ENDFOREACH(SRC ${GMX_SSEKERNEL_ASM_SRC})
 +  set(GMX_SSEKERNEL_ASM_SRC ${ALL_ASM_OBJS})
 +else(GMX_ASM_USEASM-NASM)
 +  enable_language(ASM-ATT)
 +  SET(CMAKE_ASM-ATT_COMPILER ${CMAKE_C_COMPILER})
 +  if(GMX_IA32_ASM)
 +    set_source_files_properties(${GMX_SSEKERNEL_ASM_SRC} PROPERTIES COMPILE_FLAGS "-c -m32")
 +  else()
 +    set_source_files_properties(${GMX_SSEKERNEL_ASM_SRC} PROPERTIES COMPILE_FLAGS "-c -m64")
 +  endif()
 +endif(GMX_ASM_USEASM-NASM)
 +endif(NOT GMX_OPENMM)
 +
 +list(APPEND LIBGROMACS_SOURCES ${GMXLIB_SOURCES} ${GMX_SSEKERNEL_ASM_SRC} ${MDLIB_SOURCES})
 +
 +# add target that generates version.c every time a make is run
 +# only do this if we generate the version
 +if (USE_VERSION_H)
 +    add_custom_target(gmx_version ALL
 +            COMMAND ${CMAKE_COMMAND} 
 +                -D Git_EXECUTABLE="${Git_EXECUTABLE}"
 +                -D Git_VERSION="${Git_VERSION}"
 +                -D PROJECT_VERSION="${PROJECT_VERSION}"
 +                -D PROJECT_SOURCE_DIR="${PROJECT_SOURCE_DIR}"
 +                -D VERSION_C_CMAKEIN="${CMAKE_CURRENT_SOURCE_DIR}/version.c.cmakein"
 +                -D VERSION_C_OUT="${CMAKE_CURRENT_BINARY_DIR}/version.c"
 +                -P ${CMAKE_SOURCE_DIR}/cmake/gmxGenerateVersionInfo.cmake 
 +            WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/src/gmxlib 
 +            DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/version.c.cmakein
 +            COMMENT "Generating version information")
 +    list(APPEND LIBGROMACS_SOURCES ${CMAKE_CURRENT_BINARY_DIR}/version.c) # auto-generated
 +    set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/version.c 
 +                                PROPERTIES GENERATED true)
 +endif (USE_VERSION_H)
 +
 +add_library(libgromacs ${LIBGROMACS_SOURCES})
 +if (USE_VERSION_H)
 +    add_dependencies(libgromacs gmx_version)
 +endif (USE_VERSION_H)
 +target_link_libraries(libgromacs
 +                      ${GMX_EXTRA_LIBRARIES} ${FFT_LIBRARIES} ${XML_LIBRARIES}
 +                      ${THREAD_LIB})
 +set_target_properties(libgromacs PROPERTIES
 +                      OUTPUT_NAME "gromacs${GMX_LIBS_SUFFIX}"
 +                      SOVERSION ${SOVERSION}
 +                      INSTALL_NAME_DIR "${LIB_INSTALL_DIR}")
 +
 +install(TARGETS libgromacs DESTINATION ${LIB_INSTALL_DIR} COMPONENT libraries)
 +
 +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/libgromacs.pc.cmakein
 +               ${CMAKE_CURRENT_BINARY_DIR}/libgromacs.pc @ONLY)
 +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libgromacs.pc
 +        DESTINATION ${LIB_INSTALL_DIR}/pkgconfig
 +        RENAME "libgromacs${GMX_LIBS_SUFFIX}.pc"
 +        COMPONENT development)
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..ad4997f95111b48b50636df6f793153d00d9603c
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,2 @@@
++file(GLOB ANALYSISDATA_SOURCES *.cpp modules/*.cpp)
++set(LIBGROMACS_SOURCES ${LIBGROMACS_SOURCES} ${ANALYSISDATA_SOURCES} PARENT_SCOPE)
Simple merge
index bbdcbbc245a57c1f7ec8d1518148be77251adb31,0ce747e38c6ce0ff04fe2ee3504591391e08afb9..18528b1357f1bd32c9386e1a3954dd40d99ff73b
@@@ -1,8 -1,17 +1,17 @@@
  IF (GTEST_FOUND)
-     include_directories(${GTEST_INCLUDE_DIR})
-     add_executable(options-test
-                    cmdlineparser.cpp option.cpp optionsassigner.cpp
-                    test_main.cpp)
+     include_directories(${GTEST_INCLUDE_DIRS})
+     set(UNITTEST_SOURCES cmdlineparser.cpp option.cpp optionsassigner.cpp)
+     IF (GMOCK_FOUND)
+         include_directories(${GMOCK_INCLUDE_DIRS})
+         list(APPEND UNITTEST_SOURCES
+              abstractoptionstorage.cpp test_gmock_main.cpp)
+     ELSE (GMOCK_FOUND)
+         list(APPEND UNITTEST_SOURCES test_main.cpp)
+     ENDIF (GMOCK_FOUND)
+     add_executable(options-test ${UNITTEST_SOURCES})
 -    target_link_libraries(options-test gromacs gmx ${GTEST_LIBRARIES})
 +    target_link_libraries(options-test libgromacs ${GTEST_LIBRARIES})
+     IF (GMOCK_FOUND)
+         target_link_libraries(options-test ${GMOCK_LIBRARIES})
+     ENDIF (GMOCK_FOUND)
      add_test(OptionsUnitTests options-test)
  ENDIF (GTEST_FOUND)
index 12cdbcc9da20a3e79512148e62dffc27b2a40853,50955f7fc925f5a338291f57177e0d67c8f34216..9bf9cf888374dd82a1347b3ca2503ae44a2d4f57
@@@ -1,16 -1,3 +1,20 @@@
 +file(GLOB SELECTION_SOURCES *.cpp)
 +set(LIBGROMACS_SOURCES ${LIBGROMACS_SOURCES} ${SELECTION_SOURCES} PARENT_SCOPE)
 +
 +set(SELECTION_PUBLIC_HEADERS
 +    centerofmass.h
 +    indexutil.h
 +    nbsearch.h
 +    poscalc.h
 +    position.h
 +    selection.h
 +    selparam.h
 +    selmethod.h
 +    selvalue.h)
 +install(FILES ${SELECTION_PUBLIC_HEADERS}
 +        DESTINATION ${INCL_INSTALL_DIR}/gromacs/selection
 +        COMPONENT development)
++
+ if (BUILD_TESTING)
+     add_subdirectory(tests)
+ endif (BUILD_TESTING)
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
index 2f59faed68cbdeeb1abb32c0f772ab528c3a4ade,5b235c37c0ca4d213b480f262f6e438a36d6f98b..fabbc0ba33505f30c5254c23c385a6d92bb66670
  #include <string2.h>
  #include <vec.h>
  
 -
 -#include "position.h"
 -#include "selmethod.h"
 -#include "selparam.h"
+ #include "gromacs/errorreporting/errorcontext.h"
+ #include "gromacs/fatalerror/fatalerror.h"
 +#include "gromacs/selection/position.h"
 +#include "gromacs/selection/selmethod.h"
 +#include "gromacs/selection/selparam.h"
  
  #include "parsetree.h"
  #include "position.h"
index 65b17b10c062b2cff4420f18b20284ccaafee280,d0d8ae08069ca1b332197cd0fd8203880233d52c..4597b193aab6165c513d590de75a50e3dc84141a
  #include <futil.h>
  #include <smalloc.h>
  #include <string2.h>
- #include <gmx_fatal.h>
+ #include "gromacs/errorreporting/abstracterrorreporter.h"
+ #include "gromacs/errorreporting/errorcontext.h"
+ #include "gromacs/fatalerror/fatalerror.h"
  
 -#include "poscalc.h"
 -#include "selection.h"
 -#include "selmethod.h"
 +#include "gromacs/selection/poscalc.h"
 +#include "gromacs/selection/selection.h"
 +#include "gromacs/selection/selmethod.h"
  
  #include "keywords.h"
  #include "parsetree.h"
Simple merge
Simple merge
index 5503766a76fd6d162c78feaee0a7ef245649f66c,80045288feba9f1292d13a494b1604dc77ebada3..1ebd5c0afcc79b379d7d2caf1d149e49112c2276
   * need. Instead, one should write an analysis tool such that it gets all
   * positions through selections.
   *
-  * \internal
-  *
   * The API is documented in more detail on a separate page:
   * \ref poscalcengine.
+  *
+  * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+  * \ingroup module_selection
   */
 -#ifndef POSCALC_H
 -#define POSCALC_H
 +#ifndef GMX_SELECTION_POSCALC_H
 +#define GMX_SELECTION_POSCALC_H
  
 -#include "typedefs.h"
 +#include "../legacyheaders/typedefs.h"
  
  #ifdef __cplusplus
  extern "C" {
Simple merge
index b0b9858057af65f9b3faef1a4a46afe5e29f3906,9427f8832cd481909f15e6f53e1693f5bf477b9f..8b5adca7f2ab3da3b37cf16e27250976959bbb7c
   */
  /*! \file
   * \brief API for handling positions.
+  *
+  * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+  * \ingroup module_selection
   */
 -#ifndef POSITION_H
 -#define POSITION_H
 +#ifndef GMX_SELECTION_POSITION_H
 +#define GMX_SELECTION_POSITION_H
  
 -#include "typedefs.h"
 +#include "../legacyheaders/types/simple.h"
  
  #include "indexutil.h"
  
index 0e2311d2a51dbe827d9c728694ec42a1055e9a4c,e27a55bdc5309498a680fd36a0f7a6fc752b50a2..6753680487be04245a9ff0b4b42358ad631aa73b
  #include <string.h>
  
  #include "string2.h"
- #include "gmx_fatal.h"
+ #include "gromacs/fatalerror/fatalerror.h"
  
 -#include "selmethod.h"
 +#include "gromacs/selection/selmethod.h"
  
  #include "parsetree.h"
- #include "selcollection.h"
+ #include "selectioncollection-impl.h"
  #include "selelem.h"
  #include "symrec.h"
  
index 8163aed65e16a8e042e008bd71f6c74f84883bc7,9972ea4b7118b7aa97aadf3b76ee67156d26a84a..7b7a137e1d1053c29f4679fc12ed31dca352edbc
  #include <statutil.h>
  #include <string2.h>
  #include <xvgr.h>
- #include <gmx_fatal.h>
  
- #include "gromacs/selection/poscalc.h"
++#include "gromacs/selection/position.h"
  #include "gromacs/selection/selection.h"
- #include "gromacs/selection/selmethod.h"
 -#include "position.h"
++#include "gromacs/selection/selvalue.h"
 +
- #include "mempool.h"
- #include "selcollection.h"
  #include "selelem.h"
- #include "symrec.h"
 -#include "selvalue.h"
  
- /*!
-  * \param[out] scp Pointer to a newly allocated empty selection collection.
-  * \param[in]  pcc Position calculation data structure to use for selection
-  *   position evaluation.
-  * \returns    0 on success.
-  */
- int
- gmx_ana_selcollection_create(gmx_ana_selcollection_t **scp,
-                              gmx_ana_poscalc_coll_t *pcc)
+ namespace gmx
  {
-     gmx_ana_selcollection_t *sc;
-     
-     snew(sc, 1);
-     sc->rpost     = NULL;
-     sc->spost     = NULL;
-     sc->bMaskOnly = FALSE;
-     sc->bVelocities = FALSE;
-     sc->bForces   = FALSE;
-     sc->bDebugCompile = FALSE;
-     sc->root      = NULL;
-     sc->nr        = 0;
-     sc->sel       = NULL;
-     sc->nvars     = 0;
-     sc->varstrs   = NULL;
-     sc->top       = NULL;
-     gmx_ana_index_clear(&sc->gall);
-     sc->pcc       = pcc;
-     sc->mempool   = NULL;
-     _gmx_sel_symtab_create(&sc->symtab);
-     *scp = sc;
-     return 0;
- }
  
- /*!
-  * \param[in,out] sc Selection collection to free.
-  *
-  * The pointer \p sc is invalid after the call.
-  */
- void
- gmx_ana_selcollection_free(gmx_ana_selcollection_t *sc)
+ Selection::Selection(t_selelem *elem, const char *selstr)
  {
-     int  i;
-     _gmx_selelem_free_chain(sc->root);
-     if (sc->sel)
-     {
-         for (i = 0; i < sc->nr; ++i)
-         {
-             gmx_ana_selection_free(sc->sel[i]);
-         }
-     }
-     sfree(sc->sel);
-     for (i = 0; i < sc->nvars; ++i)
-     {
-         sfree(sc->varstrs[i]);
-     }
-     sfree(sc->varstrs);
-     gmx_ana_index_deinit(&sc->gall);
-     if (sc->mempool)
-     {
-         _gmx_sel_mempool_destroy(sc->mempool);
-     }
-     _gmx_selcollection_clear_symtab(sc);
-     sfree(sc);
- }
+     _sel.name = strdup(elem->name);
+     _sel.selstr = strdup(selstr);
+     gmx_ana_pos_clear(&_sel.p);
  
- /*!
-  * \param[in,out] sc Selection collection.
-  */
- void
- _gmx_selcollection_clear_symtab(gmx_ana_selcollection_t *sc)
- {
-     if (sc->symtab)
+     if (elem->child->type == SEL_CONST)
      {
-         _gmx_sel_symtab_free(sc->symtab);
-         sc->symtab = NULL;
+         gmx_ana_pos_copy(&_sel.p, elem->child->v.u.p, TRUE);
+         _sel.bDynamic = FALSE;
      }
- }
- /*!
-  * \param[in,out] sc        Selection collection to modify.
-  * \param[in]     type      Default selection reference position type
-  *   (one of the strings acceptable for gmx_ana_poscalc_type_from_enum()).
-  *
-  * Should be called before calling gmx_ana_selcollection_requires_top() or
-  * gmx_ana_selcollection_parse_*().
-  */
- void
- gmx_ana_selcollection_set_refpostype(gmx_ana_selcollection_t *sc,
-                                      const char *type)
- {
-     sc->rpost     = type;
- }
- /*!
-  * \param[in,out] sc        Selection collection to modify.
-  * \param[in]     type      Default selection output position type
-  *   (one of the strings acceptable for gmx_ana_poslcalc_type_from_enum()).
-  * \param[in]     bMaskOnly If TRUE, the output positions are initialized
-  *   using \ref POS_MASKONLY.
-  *
-  * If \p type is NULL, the default type is not modified.
-  * Should be called before calling gmx_ana_selcollection_requires_top() or
-  * gmx_ana_selcollection_parse_*().
-  */
- void
- gmx_ana_selcollection_set_outpostype(gmx_ana_selcollection_t *sc,
-                                      const char *type, gmx_bool bMaskOnly)
- {
-     if (type)
+     else
      {
-         sc->spost     = type;
-     }
-     sc->bMaskOnly = bMaskOnly;
- }
- /*!
-  * \param[in,out] sc        Selection collection to modify.
-  * \param[in]     bVelOut   If TRUE, selections will also evaluate
-  *      velocities.
-  */
- void
- gmx_ana_selcollection_set_veloutput(gmx_ana_selcollection_t *sc,
-                                     gmx_bool bVelOut)
- {
-     sc->bVelocities = bVelOut;
- }
- /*!
-  * \param[in,out] sc        Selection collection to modify.
-  * \param[in]     bForceOut If TRUE, selections will also evaluate
-  *      forces.
-  */
- void
- gmx_ana_selcollection_set_forceoutput(gmx_ana_selcollection_t *sc,
-                                       gmx_bool bForceOut)
- {
-     sc->bForces = bForceOut;
- }
+         t_selelem *child;
  
- /*!
-  * \param[in,out] sc        Selection collection to set the topology for.
-  * \param[in]     top       Topology data.
-  * \param[in]     natoms    Number of atoms. If <=0, the number of atoms in the
-  *   topology is used.
-  * \returns       0 on success, EINVAL if \p top is NULL and \p natoms <= 0.
-  *
-  * The topology is also set for the position calculation collection
-  * associated with \p sc.
-  *
-  * \p natoms determines the largest atom index that can be selected by the
-  * selection: even if the topology contains more atoms, they will not be
-  * selected.
-  */
- int
- gmx_ana_selcollection_set_topology(gmx_ana_selcollection_t *sc, t_topology *top,
-                                    int natoms)
- {
-     gmx_ana_poscalc_coll_set_topology(sc->pcc, top);
-     sc->top = top;
-     /* Get the number of atoms from the topology if it is not given */
-     if (natoms <= 0)
-     {
-         if (!sc->top)
+         child = elem->child;
+         child->flags     &= ~SEL_ALLOCVAL;
+         _gmx_selvalue_setstore(&child->v, &_sel.p);
+         /* We should also skip any modifiers to determine the dynamic
+          * status. */
+         while (child->type == SEL_MODIFIER)
          {
-             gmx_incons("selections need either the topology or the number of atoms");
-             return EINVAL;
+             child = child->child;
+             if (child->type == SEL_SUBEXPRREF)
+             {
+                 child = child->child;
+                 /* Because most subexpression elements are created
+                  * during compilation, we need to check for them
+                  * explicitly here.
+                  */
+                 if (child->type == SEL_SUBEXPR)
+                 {
+                     child = child->child;
+                 }
+             }
          }
-         natoms = sc->top->atoms.nr;
-     }
-     gmx_ana_index_init_simple(&sc->gall, natoms, NULL);
-     return 0;
- }
- /*!
-  * \param[in]  sc  Selection collection to query.
-  * \returns    Number of selections in \p sc.
-  *
-  * If gmx_ana_selcollection_parse_*() has not been called, returns 0.
-  *
-  * \see gmx_ana_selcollection_get_selection()
-  */
- int
- gmx_ana_selcollection_get_count(gmx_ana_selcollection_t *sc)
- {
-     return sc->nr;
- }
- /*!
-  * \param[in]  sc  Selection collection to query.
-  * \param[in]  i   Number of the selection.
-  * \returns    Pointer to the \p i'th selection in \p sc,
-  *   or NULL if there is no such selection.
-  *
-  * \p i should be between 0 and the value returned by
-  * gmx_ana_selcollection_get_count().
-  * The returned pointer should not be freed.
-  * If gmx_ana_selcollection_compile() has not been called, the returned
-  * selection is not completely initialized (but the returned pointer will be
-  * valid even after compilation, and will point to the initialized selection).
-  *
-  * \see gmx_ana_selcollection_get_count()
-  */
- gmx_ana_selection_t *
- gmx_ana_selcollection_get_selection(gmx_ana_selcollection_t *sc, int i)
- {
-     if (i < 0 || i >= sc->nr || !sc->sel)
-         return NULL;
-     return sc->sel[i];
- }
- /*!
-  * \param[in]  sc  Selection collection to query.
-  * \returns    TRUE if any selection in \p sc requires topology information,
-  *   FALSE otherwise.
-  *
-  * Before gmx_ana_selcollection_parse_*(), the return value is based just on
-  * the position types set.
-  * After gmx_ana_selcollection_parse_*(), the return value also takes into account the
-  * selection keywords used.
-  */
- gmx_bool
- gmx_ana_selcollection_requires_top(gmx_ana_selcollection_t *sc)
- {
-     t_selelem   *sel;
-     e_poscalc_t  type;
-     int          flags;
-     int          rc;
-     if (sc->rpost)
-     {
-         flags = 0;
-         rc = gmx_ana_poscalc_type_from_enum(sc->rpost, &type, &flags);
-         if (rc == 0 && type != POS_ATOM)
-         {
-             return TRUE;
-         }
-     }
-     if (sc->spost)
-     {
-         flags = 0;
-         rc = gmx_ana_poscalc_type_from_enum(sc->spost, &type, &flags);
-         if (rc == 0 && type != POS_ATOM)
+         /* For variable references, we should skip the
+          * SEL_SUBEXPRREF and SEL_SUBEXPR elements. */
+         if (child->type == SEL_SUBEXPRREF)
          {
-             return TRUE;
+             child = child->child->child;
          }
+         _sel.bDynamic = (child->child->flags & SEL_DYNAMIC);
      }
-     sel = sc->root;
-     while (sel)
-     {
-         if (_gmx_selelem_requires_top(sel))
-         {
-             return TRUE;
-         }
-         sel = sel->next;
-     }
-     return FALSE;
+     /* The group will be set after compilation */
+     _sel.m        = NULL;
+     _sel.q        = NULL;
+     _sel.g        = NULL;
+     _sel.orgm     = NULL;
+     _sel.orgq     = NULL;
+     _sel.selelem  = elem;
+     initCoveredFraction(CFRAC_NONE);
  }
  
- /*!
-  * \param[in] fp      File handle to receive the output.
-  * \param[in] sc      Selection collection to print.
-  * \param[in] bValues If TRUE, the evaluated values of selection elements
-  *   are printed as well.
-  */
- void
- gmx_ana_selcollection_print_tree(FILE *fp, gmx_ana_selcollection_t *sc, gmx_bool bValues)
- {
-     t_selelem *sel;
  
-     sel = sc->root;
-     while (sel)
-     {
-         _gmx_selelem_print_tree(fp, sel, bValues, 0);
-         sel = sel->next;
-     }
- }
- /*!
-  * \param[in] sel  Selection to free.
-  *
-  * After the call, the pointer \p sel is invalid.
-  */
- void
- gmx_ana_selection_free(gmx_ana_selection_t *sel)
+ Selection::~Selection()
  {
-     sfree(sel->name);
-     sfree(sel->selstr);
-     gmx_ana_pos_deinit(&sel->p);
-     if (sel->m != sel->orgm)
+     sfree(_sel.name);
+     sfree(_sel.selstr);
+     gmx_ana_pos_deinit(&_sel.p);
+     if (_sel.m != _sel.orgm)
      {
-         sfree(sel->m);
+         sfree(_sel.m);
      }
-     if (sel->q != sel->orgq)
+     if (_sel.q != _sel.orgq)
      {
-         sfree(sel->q);
+         sfree(_sel.q);
      }
-     sfree(sel->orgm);
-     sfree(sel->orgq);
-     sfree(sel);
+     sfree(_sel.orgm);
+     sfree(_sel.orgq);
  }
  
- /*!
-  * \param[in] sel  Selection whose name is needed.
-  * \returns   Pointer to the name of the selection.
-  *
-  * The return value should not be freed by the caller.
-  */
- char *
- gmx_ana_selection_name(gmx_ana_selection_t *sel)
- {
-     return sel->name;
- }
  
- /*!
-  * \param[in] sel  Selection for which information should be printed.
-  */
  void
- gmx_ana_selection_print_info(gmx_ana_selection_t *sel)
+ Selection::printInfo() const
  {
-     fprintf(stderr, "\"%s\" (%d position%s, %d atom%s%s)", sel->name,
-             sel->p.nr,     sel->p.nr     == 1 ? "" : "s",
-             sel->g->isize, sel->g->isize == 1 ? "" : "s",
-             sel->bDynamic ? ", dynamic" : "");
+     fprintf(stderr, "\"%s\" (%d position%s, %d atom%s%s)", _sel.name,
+             _sel.p.nr,     _sel.p.nr     == 1 ? "" : "s",
+             _sel.g->isize, _sel.g->isize == 1 ? "" : "s",
+             _sel.bDynamic ? ", dynamic" : "");
      fprintf(stderr, "\n");
  }
  
Simple merge
Simple merge
index 640c51512b8534fff934b7288f76fd1d62c3a26b,2b6019122cf3b737cc63f5e37cdb8ff139e4f3a1..d7e7a699357cfaf09a6ca8210991644a6dd12e4c
@@@ -39,9 -43,7 +43,8 @@@
  #include <string2.h>
  #include <wman.h>
  
 -#include "selmethod.h"
 +#include "gromacs/selection/selmethod.h"
 +
- #include "selcollection.h"
  #include "selhelp.h"
  #include "symrec.h"
  
index 56eeb6a507d3377da3250bfe0ea76cd23bb62ce8,6b9cadab55dff4a6cdc60590d976bb3d8c0e7f59..6e10315184715604c1a25511816b7e1e5c5c7d0a
@@@ -41,9 -45,8 +45,8 @@@
  #include <macros.h>
  #include <string2.h>
  
 -#include "selmethod.h"
 +#include "gromacs/selection/selmethod.h"
  
- #include "selcollection.h"
  #include "symrec.h"
  
  /*
Simple merge
index 2b03aa46b4750da7e4e65caad3903cb9a8125b1a,7c6d41f3cd879a417e249aa069f796dc7407c75a..507d0fce7f383ae555b94387f31e20c7ded61132
   * method.
   *
   * More details can be found on the page discussing
-  * \ref selmethods "custom selection methods".
+  * \ref page_module_selection_custom "custom selection methods".
+  *
+  * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+  * \ingroup module_selection
   */
 -#ifndef SELPARAM_H
 -#define SELPARAM_H
 -
 -#include "typedefs.h"
 +#ifndef GMX_SELECTION_SELPARAM_H
 +#define GMX_SELECTION_SELPARAM_H
  
  #include "indexutil.h"
  #include "selvalue.h"
Simple merge
index 63a928513b2bd7da983735d6118078ba4d952e7a,8fe133e4a0fc4427dc66a5398a6eb2839d265811..e789ef596721e13414982ed53722e3d515098d5a
   *
   * There should be no need to use the data structures in this file directly
   * unless implementing a custom selection routine.
+  *
+  * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+  * \ingroup module_selection
   */
 -#ifndef SELVALUE_H
 -#define SELVALUE_H
 +#ifndef GMX_SELECTION_SELVALUE_H
 +#define GMX_SELECTION_SELVALUE_H
  
 -#include "types/simple.h"
 +#include "../legacyheaders/types/simple.h"
  
  #ifdef __cplusplus
  extern "C"
Simple merge
Simple merge
index 55d212a1d311eba1c6bbf08853a5bc1e123fdfb1,322ec62c3aec96fdc3a7859b1dc5bbc68e7fbce9..eeaff1ff95f3e2d9ac22deba2834d654ee06521a
  #include <smalloc.h>
  #include <string2.h>
  
 -
 -#include "selmethod.h"
+ #include "gromacs/errorreporting/errorcontext.h"
+ #include "gromacs/fatalerror/fatalerror.h"
 +#include "gromacs/selection/selmethod.h"
  
  #include "keywords.h"
  #include "parsetree.h"
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
index 0000000000000000000000000000000000000000,3e3f491ee7ac7596105631c1df45739cf6ce3fb6..6b02bbaa1a95b6df732ad5d74018f13da306af80
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,8 +1,8 @@@
 -    target_link_libraries(selection-test gromacs gmx ${GTEST_LIBRARIES})
+ IF (GTEST_FOUND)
+     include_directories(${GTEST_INCLUDE_DIRS})
+     add_executable(selection-test
+                    selectioncollection.cpp selectionoption.cpp
+                    test_main.cpp)
++    target_link_libraries(selection-test libgromacs ${GTEST_LIBRARIES})
+     add_test(SelectionUnitTests selection-test)
+ ENDIF (GTEST_FOUND)
index 0000000000000000000000000000000000000000,50955f7fc925f5a338291f57177e0d67c8f34216..c865ecf58cb41d6a81b1df047efbd7b8d1b31cde
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,3 +1,6 @@@
++file(GLOB TRAJECTORYANALYSIS_SOURCES *.cpp modules/*.cpp)
++set(LIBGROMACS_SOURCES ${LIBGROMACS_SOURCES} ${TRAJECTORYANALYSIS_SOURCES} PARENT_SCOPE)
++
+ if (BUILD_TESTING)
+     add_subdirectory(tests)
+ endif (BUILD_TESTING)
index 0000000000000000000000000000000000000000,4029a3af6c4d9caee0421538d8a5508be166614d..f87d457d7b66f55b50cab71125dc1ac146777f74
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,94 +1,94 @@@
 -        SelectionCollection    *_selections;
+ /*
+  *
+  *                This source code is part of
+  *
+  *                 G   R   O   M   A   C   S
+  *
+  *          GROningen MAchine for Chemical Simulations
+  *
+  * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+  * Copyright (c) 2001-2009, The GROMACS development team,
+  * check out http://www.gromacs.org for more information.
+  * This program is free software; you can redistribute it and/or
+  * modify it under the terms of the GNU General Public License
+  * as published by the Free Software Foundation; either version 2
+  * of the License, or (at your option) any later version.
+  *
+  * If you want to redistribute modifications, please consider that
+  * scientific software is very special. Version control is crucial -
+  * bugs must be traceable. We will be happy to consider code for
+  * inclusion in the official distribution, but derived work must not
+  * be called official GROMACS. Details are found in the README & COPYING
+  * files - if they are missing, get the official version at www.gromacs.org.
+  *
+  * To help us fund GROMACS development, we humbly ask that you cite
+  * the papers on the package - you can find them in the top README file.
+  *
+  * For more info, check our website at http://www.gromacs.org
+  */
+ /*! \internal \file
+  * \brief
+  * Declares private implementation classes for gmx::TrajectoryAnalysisModule
+  * and gmx::TrajectoryAnalysisModuleData.
+  *
+  * \ingroup module_trajectoryanalysis
+  * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+  */
+ #ifndef GMX_TRAJECTORYANALYSIS_ANALYSISMODULE_IMPL_H
+ #define GMX_TRAJECTORYANALYSIS_ANALYSISMODULE_IMPL_H
+ #include <map>
+ #include <string>
+ #include <vector>
+ #include "analysismodule.h"
+ namespace gmx
+ {
+ class AbstractAnalysisData;
+ class AnalysisData;
+ class AnalysisDataHandle;
+ class TrajectoryAnalysisModuleData::Impl
+ {
+     public:
+         typedef std::map<std::string, AnalysisDataHandle *> HandleContainer;
+         Impl() : _selections(NULL) {}
+         ~Impl();
+         int finishHandles();
+         HandleContainer         _handles;
++        const SelectionCollection *_selections;
+ };
+ class TrajectoryAnalysisModule::Impl
+ {
+     public:
+         typedef std::map<std::string, AbstractAnalysisData *> DatasetContainer;
+         typedef std::map<std::string, AnalysisData *> AnalysisDatasetContainer;
+         std::vector<std::string>        _datasetNames;
+         DatasetContainer                _datasets;
+         AnalysisDatasetContainer        _analysisDatasets;
+ };
+ /*! \internal \brief
+  * Basic thread-local trajectory analysis data storage class.
+  *
+  * Most simple tools should only require data handles and selections to be
+  * thread-local, so this class implements just that.
+  */
+ class TrajectoryAnalysisModuleDataBasic : public TrajectoryAnalysisModuleData
+ {
+     public:
+         virtual int finish();
+ };
+ } // namespace gmx
+ #endif
index 0000000000000000000000000000000000000000,ffec5ec3a37d5de650529b509102a5cdfb064174..038424e5311a2427971366cee8d74cdcb1e083e8
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,478 +1,479 @@@
+ /*
+  *
+  *                This source code is part of
+  *
+  *                 G   R   O   M   A   C   S
+  *
+  *          GROningen MAchine for Chemical Simulations
+  *
+  * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+  * Copyright (c) 2001-2009, The GROMACS development team,
+  * check out http://www.gromacs.org for more information.
+  * This program is free software; you can redistribute it and/or
+  * modify it under the terms of the GNU General Public License
+  * as published by the Free Software Foundation; either version 2
+  * of the License, or (at your option) any later version.
+  *
+  * If you want to redistribute modifications, please consider that
+  * scientific software is very special. Version control is crucial -
+  * bugs must be traceable. We will be happy to consider code for
+  * inclusion in the official distribution, but derived work must not
+  * be called official GROMACS. Details are found in the README & COPYING
+  * files - if they are missing, get the official version at www.gromacs.org.
+  *
+  * To help us fund GROMACS development, we humbly ask that you cite
+  * the papers on the package - you can find them in the top README file.
+  *
+  * For more info, check our website at http://www.gromacs.org
+  */
+ /*! \internal \file
+  * \brief
+  * Implements gmx::TrajectoryAnalysisRunnerCommon.
+  *
+  * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+  */
+ #ifdef HAVE_CONFIG_H
+ #include <config.h>
+ #endif
+ #include <cassert>
++#include <string.h>
+ #include <rmpbc.h>
+ #include <smalloc.h>
+ #include <statutil.h>
+ #include <tpxio.h>
+ #include <vec.h>
+ #include "gromacs/fatalerror/fatalerror.h"
+ #include "gromacs/options/basicoptions.h"
+ #include "gromacs/options/globalproperties.h"
+ #include "gromacs/options/options.h"
+ #include "gromacs/selection/indexutil.h"
+ #include "gromacs/selection/selectioncollection.h"
+ #include "gromacs/trajectoryanalysis/analysissettings.h"
+ #include "gromacs/trajectoryanalysis/runnercommon.h"
+ #include "analysissettings-impl.h"
+ namespace gmx
+ {
+ class TrajectoryAnalysisRunnerCommon::Impl
+ {
+     public:
+         Impl(TrajectoryAnalysisSettings *settings);
+         ~Impl();
+         void finishTrajectory();
+         TrajectoryAnalysisSettings &_settings;
+         Options                 _options;
+         TopologyInformation     _topInfo;
+         bool                    _bHelp;
+         bool                    _bShowHidden;
+         bool                    _bQuiet;
+         //! Name of the trajectory file (empty if not provided).
+         std::string             _trjfile;
+         //! Name of the topology file (empty if no topology provided).
+         std::string             _topfile;
+         //! Name of the index file (empty if no index file provided).
+         std::string             _ndxfile;
+         double                  _startTime;
+         double                  _endTime;
+         double                  _deltaTime;
+         gmx_ana_indexgrps_t    *_grps;
+         bool                    _bTrajOpen;
+         //! The current frame, or \p NULL if no frame loaded yet.
+         t_trxframe          *fr;
+         gmx_rmpbc_t             _gpbc;
+         //! Used to store the status variable from read_first_frame().
+         t_trxstatus            *_status;
+         output_env_t            _oenv;
+ };
+ TrajectoryAnalysisRunnerCommon::Impl::Impl(TrajectoryAnalysisSettings *settings)
+     : _settings(*settings), _options("common", "Common analysis control"),
+       _bHelp(false), _bShowHidden(false), _bQuiet(false),
+       _startTime(0.0), _endTime(0.0), _deltaTime(0.0),
+       _grps(NULL),
+       _bTrajOpen(false), fr(NULL), _gpbc(NULL), _status(NULL), _oenv(NULL)
+ {
+ }
+ TrajectoryAnalysisRunnerCommon::Impl::~Impl()
+ {
+     if (_grps != NULL)
+     {
+         gmx_ana_indexgrps_free(_grps);
+     }
+     finishTrajectory();
+     if (fr)
+     {
+         // There doesn't seem to be a function for freeing frame data
+         sfree(fr->x);
+         sfree(fr->v);
+         sfree(fr->f);
+         sfree(fr);
+     }
+ }
+ void
+ TrajectoryAnalysisRunnerCommon::Impl::finishTrajectory()
+ {
+     if (_bTrajOpen)
+     {
+         close_trx(_status);
+         _bTrajOpen = false;
+     }
+     if (_gpbc != NULL)
+     {
+         gmx_rmpbc_done(_gpbc);
+         _gpbc = NULL;
+     }
+ }
+ /*********************************************************************
+  * TrajectoryAnalysisRunnerCommon
+  */
+ TrajectoryAnalysisRunnerCommon::TrajectoryAnalysisRunnerCommon(
+         TrajectoryAnalysisSettings *settings)
+     : _impl(new Impl(settings))
+ {
+ }
+ TrajectoryAnalysisRunnerCommon::~TrajectoryAnalysisRunnerCommon()
+ {
+     delete _impl;
+ }
+ Options *
+ TrajectoryAnalysisRunnerCommon::initOptions()
+ {
+     TrajectoryAnalysisSettings &settings = _impl->_settings;
+     Options &options = _impl->_options;
+     // Add options for help.
+     options.addOption(BooleanOption("h").store(&_impl->_bHelp)
+                           .description("Print help and quit"));
+     options.addOption(BooleanOption("hidden").store(&_impl->_bShowHidden)
+                           .hidden()
+                           .description("Show hidden options"));
+     options.addOption(BooleanOption("quiet").store(&_impl->_bQuiet)
+                           .hidden()
+                           .description("Hide options in normal run"));
+     // Add common file name arguments.
+     options.addOption(FileNameOption("f")
+                           .filetype(eftTrajectory).readOnly()
+                           .store(&_impl->_trjfile)
+                           .description("Input trajectory"));
+     options.addOption(FileNameOption("s")
+                           .filetype(eftTopology).readOnly()
+                           .store(&_impl->_topfile)
+                           .description("Input topology"));
+     options.addOption(FileNameOption("n")
+                           .filetype(eftIndex).readOnly()
+                           .store(&_impl->_ndxfile)
+                           .description("Extra index groups"));
+     // Add options for trajectory time control.
+     options.addOption(DoubleOption("b").store(&_impl->_startTime).timeValue()
+                           .description("First frame (%t) to read from trajectory"));
+     options.addOption(DoubleOption("e").store(&_impl->_endTime).timeValue()
+                           .description("Last frame (%t) to read from trajectory"));
+     options.addOption(DoubleOption("dt").store(&_impl->_deltaTime).timeValue()
+                           .description("Only use frame if t MOD dt == first time (%t)"));
+     // Add common options for trajectory processing.
+     if (!settings.hasFlag(TrajectoryAnalysisSettings::efNoUserRmPBC))
+     {
+         options.addOption(BooleanOption("rmpbc").store(&settings._impl->bRmPBC)
+                               .description("Make molecules whole for each frame"));
+     }
+     if (!settings.hasFlag(TrajectoryAnalysisSettings::efNoUserPBC))
+     {
+         options.addOption(BooleanOption("pbc").store(&settings._impl->bPBC)
+                               .description("Use periodic boundary conditions for distance calculation"));
+     }
+     return &_impl->_options;
+ }
+ int
+ TrajectoryAnalysisRunnerCommon::initOptionsDone()
+ {
+     if (_impl->_bHelp)
+     {
+         // TODO: Proper error code for graceful exit
+         return -1;
+     }
+     if (_impl->_trjfile.empty() && _impl->_topfile.empty())
+     {
+         GMX_ERROR(eeInconsistentInput,
+                   "No trajectory or topology provided, nothing to do!");
+     }
+     if (_impl->_options.isSet("b"))
+         setTimeValue(TBEGIN, _impl->_startTime);
+     if (_impl->_options.isSet("e"))
+         setTimeValue(TEND, _impl->_endTime);
+     if (_impl->_options.isSet("dt"))
+         setTimeValue(TDELTA, _impl->_deltaTime);
+     return 0;
+ }
+ int
+ TrajectoryAnalysisRunnerCommon::initIndexGroups(SelectionCollection *selections)
+ {
+     int rc = 0;
+     if (_impl->_ndxfile.empty())
+     {
+         // TODO: Initialize default selections
+         selections->setIndexGroups(NULL);
+     }
+     else
+     {
+         gmx_ana_indexgrps_init(&_impl->_grps, NULL, _impl->_ndxfile.c_str());
+         rc = selections->setIndexGroups(_impl->_grps);
+     }
+     return rc;
+ }
+ void
+ TrajectoryAnalysisRunnerCommon::doneIndexGroups(SelectionCollection *selections)
+ {
+     if (_impl->_grps != NULL)
+     {
+         selections->setIndexGroups(NULL);
+         gmx_ana_indexgrps_free(_impl->_grps);
+         _impl->_grps = NULL;
+     }
+ }
+ int
+ TrajectoryAnalysisRunnerCommon::initTopology(SelectionCollection *selections)
+ {
+     const TrajectoryAnalysisSettings &settings = _impl->_settings;
+     bool bRequireTop
+         = settings.hasFlag(TrajectoryAnalysisSettings::efRequireTop)
+           || selections->requiresTopology();
+     if (bRequireTop && _impl->_topfile.empty())
+     {
+         GMX_ERROR(eeInconsistentInput,
+                   "No topology provided, but one is required for analysis");
+     }
+     // Load the topology if requested.
+     if (!_impl->_topfile.empty())
+     {
+         char  title[STRLEN];
+         snew(_impl->_topInfo._top, 1);
+         _impl->_topInfo._bTop = read_tps_conf(_impl->_topfile.c_str(), title,
+                 _impl->_topInfo._top, &_impl->_topInfo._ePBC,
+                 &_impl->_topInfo._xtop, NULL, _impl->_topInfo._boxtop, TRUE);
+         if (hasTrajectory()
+             && !settings.hasFlag(TrajectoryAnalysisSettings::efUseTopX))
+         {
+             sfree(_impl->_topInfo._xtop);
+             _impl->_topInfo._xtop = NULL;
+         }
+     }
+     // Read the first frame if we don't know the maximum number of atoms
+     // otherwise.
+     int  natoms = -1;
+     if (!_impl->_topInfo.hasTopology())
+     {
+         int rc = initFirstFrame();
+         if (rc != 0)
+         {
+             return rc;
+         }
+         natoms = _impl->fr->natoms;
+     }
+     int rc = selections->setTopology(_impl->_topInfo.topology(), natoms);
+     if (rc != 0)
+     {
+         return rc;
+     }
+     /*
+     if (_impl->bSelDump)
+     {
+         gmx_ana_poscalc_coll_print_tree(stderr, _impl->pcc);
+         fprintf(stderr, "\n");
+     }
+     */
+     return 0;
+ }
+ int
+ TrajectoryAnalysisRunnerCommon::initFirstFrame()
+ {
+     // Return if we have already initialized the trajectory.
+     if (_impl->fr)
+     {
+         return 0;
+     }
+     _impl->_oenv = _impl->_options.globalProperties().output_env();
+     int frflags = _impl->_settings.frflags();
+     frflags |= TRX_NEED_X;
+     snew(_impl->fr, 1);
+     const TopologyInformation &top = _impl->_topInfo;
+     if (hasTrajectory())
+     {
+         if (!read_first_frame(_impl->_oenv, &_impl->_status,
+                               _impl->_trjfile.c_str(), _impl->fr, frflags))
+         {
+             GMX_ERROR(eeFileNotFound,
+                       "Could not read coordinates from trajectory");
+         }
+         _impl->_bTrajOpen = true;
+         if (top.hasTopology() && _impl->fr->natoms > top.topology()->atoms.nr)
+         {
+             fatalErrorFormatted(eeInconsistentInput, GMX_ERRORLOC,
+                 "Trajectory (%d atoms) does not match topology (%d atoms)",
+                 _impl->fr->natoms, top.topology()->atoms.nr);
+             return eeInconsistentInput;
+         }
+         // Check index groups if they have been initialized based on the topology.
+         /*
+         if (top)
+         {
+             for (int i = 0; i < _impl->sel->nr(); ++i)
+             {
+                 gmx_ana_index_check(_impl->sel->sel(i)->indexGroup(),
+                                     _impl->fr->natoms);
+             }
+         }
+         */
+     }
+     else
+     {
+         // Prepare a frame from topology information.
+         // TODO: Initialize more of the fields.
+         if (frflags & (TRX_NEED_V))
+         {
+             GMX_ERROR(eeNotImplemented,
+                       "Velocity reading from a topology not implemented");
+         }
+         if (frflags & (TRX_NEED_F))
+         {
+             GMX_ERROR(eeInvalidInput,
+                       "Forces cannot be read from a topology");
+         }
+         _impl->fr->flags  = frflags;
+         _impl->fr->natoms = top.topology()->atoms.nr;
+         _impl->fr->bX     = TRUE;
+         snew(_impl->fr->x, _impl->fr->natoms);
+         memcpy(_impl->fr->x, top._xtop,
+                sizeof(*_impl->fr->x) * _impl->fr->natoms);
+         _impl->fr->bBox   = TRUE;
+         copy_mat(const_cast<rvec *>(top._boxtop), _impl->fr->box);
+     }
+     set_trxframe_ePBC(_impl->fr, top.ePBC());
+     if (top.hasTopology() && _impl->_settings.hasRmPBC())
+     {
+         _impl->_gpbc = gmx_rmpbc_init(&top.topology()->idef, top.ePBC(),
+                                       _impl->fr->natoms, _impl->fr->box);
+     }
+     return 0;
+ }
+ bool
+ TrajectoryAnalysisRunnerCommon::readNextFrame()
+ {
+     bool bContinue = FALSE;
+     if (hasTrajectory())
+     {
+         bContinue = read_next_frame(_impl->_oenv, _impl->_status, _impl->fr);
+     }
+     if (!bContinue)
+     {
+         _impl->finishTrajectory();
+     }
+     return bContinue;
+ }
+ int
+ TrajectoryAnalysisRunnerCommon::initFrame()
+ {
+     if (_impl->_gpbc != NULL)
+     {
+         gmx_rmpbc_trxfr(_impl->_gpbc, _impl->fr);
+     }
+     return 0;
+ }
+ TrajectoryAnalysisRunnerCommon::HelpFlags
+ TrajectoryAnalysisRunnerCommon::helpFlags() const
+ {
+     HelpFlags flags = 0;
+     if (!_impl->_bQuiet)
+     {
+         flags |= efHelpShowOptions;
+         if (_impl->_bHelp)
+         {
+             flags |= efHelpShowDescriptions;
+         }
+         if (_impl->_bShowHidden)
+         {
+             flags |= efHelpShowHidden;
+         }
+     }
+     return flags;
+ }
+ bool
+ TrajectoryAnalysisRunnerCommon::hasTrajectory() const
+ {
+     return !_impl->_trjfile.empty();
+ }
+ const TopologyInformation &
+ TrajectoryAnalysisRunnerCommon::topologyInformation() const
+ {
+     return _impl->_topInfo;
+ }
+ t_trxframe &
+ TrajectoryAnalysisRunnerCommon::frame() const
+ {
+     assert(_impl->fr != NULL);
+     return *_impl->fr;
+ }
+ } // namespace gmx
index 0000000000000000000000000000000000000000,d289e0627de13a1655db5968292ed85aa52ecbdb..6e6a858be7b1ab0fc2b74e42f446cee6355cb757
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,2 +1,2 @@@
 -target_link_libraries(test_selection gromacs gmx)
+ add_executable(test_selection test_selection.cpp)
++target_link_libraries(test_selection libgromacs)
index 0000000000000000000000000000000000000000,89193dddc38911be702b6a68fff9618387a59ce1..07e32ba6b6a9a4ead5cbb041d99fbc2426198032
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,3 +1,1 @@@
 -include_directories(${CMAKE_CURRENT_SOURCE_DIR}/..)
 -
+ add_subdirectory(g_ana)
index 0000000000000000000000000000000000000000,5e8b48bb1b6128e7c738d6ad58b89bccc77e1e2f..7491acaf2c8332ab3678539289fd4a3f4091b0a1
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,6 +1,6 @@@
 -target_link_libraries(g_ana gromacs)
+ add_executable(g_ana g_ana.cpp)
++target_link_libraries(g_ana libgromacs)
+ set_target_properties(g_ana PROPERTIES OUTPUT_NAME "g_ana${GMX_BINARY_SUFFIX}")
+ install(TARGETS g_ana
+         RUNTIME DESTINATION ${BIN_INSTALL_DIR})
index 45f7671e95e9fe0c1102074adb4241276330ed63,79c1c7b3f9d69eb4cea21b39b350a474d886b8f9..cf1dda43c06dc8ac0688ba3ec71af5f75a7cc090
@@@ -47,8 -46,8 +46,8 @@@ set(GMX_TOOLS_PROGRAM
      g_helixorient g_principal g_dipoles g_disre g_dist
      g_dyndom g_enemat g_energy g_lie g_filter g_gyrate
      g_h2order g_hbond g_helix g_mindist g_msd g_morph g_nmeig
 -    g_nmens g_order g_polystat g_potential g_rama g_rdf g_rms
 +    g_nmens g_order g_kinetics g_polystat g_potential g_rama g_rdf g_rms
-     g_rmsf g_rotacf g_saltbr g_sas g_select g_sgangle g_sham g_sorient
+     g_rmsf g_rotacf g_saltbr g_sas g_sgangle g_sham g_sorient
      g_spol g_spatial g_tcaf g_traj g_tune_pme g_vanhove
      g_velacc g_clustsize g_mdmat g_wham g_sigeps g_bar
      g_pme_error g_rmsdist g_rotmat)