Merge "Merge branch release-4-6 into master"
authorTeemu Murtola <teemu.murtola@gmail.com>
Sun, 1 Sep 2013 09:39:18 +0000 (11:39 +0200)
committerGerrit Code Review <gerrit@gerrit.gromacs.org>
Sun, 1 Sep 2013 09:39:18 +0000 (11:39 +0200)
226 files changed:
CMakeLists.txt
admin/installguide/installguide.tex
cmake/legacy_and_external.supp
doxygen/Doxyfile-common.cmakein
share/template/template.cpp
share/top/gurgle.dat
src/CMakeLists.txt
src/contrib/BuildMdrunOpenMM.cmake [deleted file]
src/contrib/CMakeLists.txt
src/contrib/FindOpenMM.cmake [deleted file]
src/contrib/md_openmm.c [deleted file]
src/contrib/md_openmm.h [deleted file]
src/contrib/mdrun_openmm.c [deleted file]
src/contrib/openmm_gpu_utils.cu [deleted file]
src/contrib/openmm_gpu_utils.h [deleted file]
src/contrib/openmm_wrapper.cpp [deleted file]
src/contrib/openmm_wrapper.h [deleted file]
src/contrib/runner_openmm.c [deleted file]
src/gromacs/analysisdata/abstractdata.cpp
src/gromacs/analysisdata/abstractdata.h
src/gromacs/analysisdata/analysisdata.cpp
src/gromacs/analysisdata/analysisdata.h
src/gromacs/analysisdata/arraydata.cpp
src/gromacs/analysisdata/arraydata.h
src/gromacs/analysisdata/dataframe.cpp
src/gromacs/analysisdata/dataframe.h
src/gromacs/analysisdata/datamodule.h
src/gromacs/analysisdata/dataproxy.cpp
src/gromacs/analysisdata/datastorage.cpp
src/gromacs/analysisdata/datastorage.h
src/gromacs/analysisdata/modules/average.cpp
src/gromacs/analysisdata/modules/average.h
src/gromacs/analysisdata/modules/displacement.cpp
src/gromacs/analysisdata/modules/frameaverager.h
src/gromacs/analysisdata/modules/histogram.cpp
src/gromacs/analysisdata/modules/histogram.h
src/gromacs/analysisdata/modules/lifetime.cpp [new file with mode: 0644]
src/gromacs/analysisdata/modules/lifetime.h [new file with mode: 0644]
src/gromacs/analysisdata/modules/plot.cpp
src/gromacs/analysisdata/modules/plot.h
src/gromacs/analysisdata/tests/CMakeLists.txt
src/gromacs/analysisdata/tests/analysisdata.cpp
src/gromacs/analysisdata/tests/arraydata.cpp
src/gromacs/analysisdata/tests/average.cpp
src/gromacs/analysisdata/tests/histogram.cpp
src/gromacs/analysisdata/tests/lifetime.cpp [new file with mode: 0644]
src/gromacs/analysisdata/tests/refdata/AbstractAverageHistogramTest_ResamplesAtDoubleBinWidth.xml
src/gromacs/analysisdata/tests/refdata/AbstractAverageHistogramTest_ResamplesAtDoubleBinWidthWithIntegerBins.xml
src/gromacs/analysisdata/tests/refdata/AverageModuleTest_BasicTest.xml
src/gromacs/analysisdata/tests/refdata/AverageModuleTest_CanCustomizeXAxis.xml
src/gromacs/analysisdata/tests/refdata/AverageModuleTest_HandlesDataSetAveraging.xml [new file with mode: 0644]
src/gromacs/analysisdata/tests/refdata/AverageModuleTest_HandlesMultipleDataSets.xml [new file with mode: 0644]
src/gromacs/analysisdata/tests/refdata/AverageModuleTest_HandlesMultipointData.xml
src/gromacs/analysisdata/tests/refdata/BinAverageModuleTest_ComputesCorrectly.xml
src/gromacs/analysisdata/tests/refdata/BinAverageModuleTest_ComputesCorrectlyWithAll.xml
src/gromacs/analysisdata/tests/refdata/BinAverageModuleTest_HandlesMultipleDataSets.xml [new file with mode: 0644]
src/gromacs/analysisdata/tests/refdata/FrameAverageModuleTest_BasicTest.xml
src/gromacs/analysisdata/tests/refdata/FrameAverageModuleTest_HandlesMultipleDataSets.xml [new file with mode: 0644]
src/gromacs/analysisdata/tests/refdata/LifetimeModuleTest_BasicTest.xml [new file with mode: 0644]
src/gromacs/analysisdata/tests/refdata/LifetimeModuleTest_CumulativeTest.xml [new file with mode: 0644]
src/gromacs/analysisdata/tests/refdata/LifetimeModuleTest_HandlesMultipleDataSets.xml [new file with mode: 0644]
src/gromacs/analysisdata/tests/refdata/SimpleHistogramModuleTest_ComputesCorrectly.xml
src/gromacs/analysisdata/tests/refdata/SimpleHistogramModuleTest_ComputesCorrectlyWithAll.xml
src/gromacs/analysisdata/tests/refdata/WeightedHistogramModuleTest_ComputesCorrectly.xml
src/gromacs/analysisdata/tests/refdata/WeightedHistogramModuleTest_ComputesCorrectlyWithAll.xml
src/gromacs/analysisdata/tests/refdata/WeightedHistogramModuleTest_HandlesMultipleDataSets.xml [new file with mode: 0644]
src/gromacs/analysisdata/tests/refdata/analysisdata-referencedata.xsl
src/gromacs/commandline/cmdlinemodulemanager.cpp
src/gromacs/commandline/cmdlinemodulemanager.h
src/gromacs/commandline/cmdlineparser.cpp
src/gromacs/commandline/cmdlineparser.h
src/gromacs/commandline/tests/cmdlineparser.cpp
src/gromacs/gmxana/cmat.c
src/gromacs/gmxana/cmat.h
src/gromacs/gmxana/gmx_cluster.c
src/gromacs/gmxana/gmx_disre.c
src/gromacs/gmxana/gmx_pme_error.cpp
src/gromacs/gmxlib/copyrite.cpp
src/gromacs/gmxlib/futil.cpp [moved from src/gromacs/gmxlib/futil.c with 99% similarity]
src/gromacs/gmxlib/main.cpp
src/gromacs/gmxlib/network.c
src/gromacs/gmxlib/statutil.cpp
src/gromacs/gmxlib/typedefs.c
src/gromacs/gmxpreprocess/fflibutil.cpp [moved from src/gromacs/gmxpreprocess/fflibutil.c with 99% similarity]
src/gromacs/legacyheaders/gmx_math_x86_avx_256_double.h
src/gromacs/legacyheaders/gmx_math_x86_avx_256_single.h
src/gromacs/legacyheaders/gmx_math_x86_sse2_double.h
src/gromacs/legacyheaders/gmx_math_x86_sse2_single.h
src/gromacs/legacyheaders/main.h
src/gromacs/legacyheaders/network.h
src/gromacs/legacyheaders/statutil.h
src/gromacs/mdlib/mdebin.c
src/gromacs/mdlib/nbnxn_cuda/nbnxn_cuda_kernel_utils.cuh
src/gromacs/options/optionsassigner.cpp
src/gromacs/options/optionsassigner.h
src/gromacs/selection/indexutil.cpp
src/gromacs/selection/parser.cpp
src/gromacs/selection/parser.y
src/gromacs/selection/parsetree.cpp
src/gromacs/selection/selection.cpp
src/gromacs/selection/selection.h
src/gromacs/selection/selectioncollection-impl.h
src/gromacs/selection/selectioncollection.cpp
src/gromacs/selection/selectioncollection.h
src/gromacs/selection/selelem.cpp
src/gromacs/selection/selelem.h
src/gromacs/selection/sm_simple.cpp
src/gromacs/selection/tests/refdata/SelectionCollectionDataTest_ComputesMassesAndCharges.xml
src/gromacs/selection/tests/refdata/SelectionCollectionDataTest_ComputesMassesAndChargesWithoutTopology.xml
src/gromacs/selection/tests/refdata/SelectionCollectionDataTest_HandlesAllNone.xml
src/gromacs/selection/tests/refdata/SelectionCollectionDataTest_HandlesAltLoc.xml
src/gromacs/selection/tests/refdata/SelectionCollectionDataTest_HandlesArithmeticExpressions.xml
src/gromacs/selection/tests/refdata/SelectionCollectionDataTest_HandlesAtomname.xml
src/gromacs/selection/tests/refdata/SelectionCollectionDataTest_HandlesAtomnr.xml
src/gromacs/selection/tests/refdata/SelectionCollectionDataTest_HandlesAtomtype.xml [new file with mode: 0644]
src/gromacs/selection/tests/refdata/SelectionCollectionDataTest_HandlesBasicBoolean.xml
src/gromacs/selection/tests/refdata/SelectionCollectionDataTest_HandlesBeta.xml
src/gromacs/selection/tests/refdata/SelectionCollectionDataTest_HandlesBooleanStaticAnalysis.xml
src/gromacs/selection/tests/refdata/SelectionCollectionDataTest_HandlesBooleanStaticAnalysisWithMoreVariables.xml
src/gromacs/selection/tests/refdata/SelectionCollectionDataTest_HandlesBooleanStaticAnalysisWithVariables.xml
src/gromacs/selection/tests/refdata/SelectionCollectionDataTest_HandlesChain.xml
src/gromacs/selection/tests/refdata/SelectionCollectionDataTest_HandlesCharge.xml
src/gromacs/selection/tests/refdata/SelectionCollectionDataTest_HandlesComplexNumericVariables.xml
src/gromacs/selection/tests/refdata/SelectionCollectionDataTest_HandlesConstantPositionInVariable.xml
src/gromacs/selection/tests/refdata/SelectionCollectionDataTest_HandlesConstantPositions.xml
src/gromacs/selection/tests/refdata/SelectionCollectionDataTest_HandlesCoordinateKeywords.xml
src/gromacs/selection/tests/refdata/SelectionCollectionDataTest_HandlesDistanceKeyword.xml
src/gromacs/selection/tests/refdata/SelectionCollectionDataTest_HandlesDynamicAtomValuedParameters.xml
src/gromacs/selection/tests/refdata/SelectionCollectionDataTest_HandlesForcedStringMatchingMode.xml
src/gromacs/selection/tests/refdata/SelectionCollectionDataTest_HandlesInSolidAngleKeyword.xml
src/gromacs/selection/tests/refdata/SelectionCollectionDataTest_HandlesIndexGroupsInSelections.xml [new file with mode: 0644]
src/gromacs/selection/tests/refdata/SelectionCollectionDataTest_HandlesIndexGroupsInSelectionsDelayed.xml [new file with mode: 0644]
src/gromacs/selection/tests/refdata/SelectionCollectionDataTest_HandlesInsertCode.xml
src/gromacs/selection/tests/refdata/SelectionCollectionDataTest_HandlesMass.xml
src/gromacs/selection/tests/refdata/SelectionCollectionDataTest_HandlesMergeModifier.xml
src/gromacs/selection/tests/refdata/SelectionCollectionDataTest_HandlesMinDistanceKeyword.xml
src/gromacs/selection/tests/refdata/SelectionCollectionDataTest_HandlesMolIndex.xml [new file with mode: 0644]
src/gromacs/selection/tests/refdata/SelectionCollectionDataTest_HandlesNumericComparisons.xml
src/gromacs/selection/tests/refdata/SelectionCollectionDataTest_HandlesNumericConstantsInVariables.xml
src/gromacs/selection/tests/refdata/SelectionCollectionDataTest_HandlesNumericVariables.xml
src/gromacs/selection/tests/refdata/SelectionCollectionDataTest_HandlesOccupancy.xml
src/gromacs/selection/tests/refdata/SelectionCollectionDataTest_HandlesPdbAtomname.xml
src/gromacs/selection/tests/refdata/SelectionCollectionDataTest_HandlesPermuteModifier.xml
src/gromacs/selection/tests/refdata/SelectionCollectionDataTest_HandlesPlusModifier.xml
src/gromacs/selection/tests/refdata/SelectionCollectionDataTest_HandlesPositionKeywords.xml
src/gromacs/selection/tests/refdata/SelectionCollectionDataTest_HandlesPositionVariables.xml
src/gromacs/selection/tests/refdata/SelectionCollectionDataTest_HandlesRegexMatching.xml
src/gromacs/selection/tests/refdata/SelectionCollectionDataTest_HandlesResIndex.xml
src/gromacs/selection/tests/refdata/SelectionCollectionDataTest_HandlesResname.xml
src/gromacs/selection/tests/refdata/SelectionCollectionDataTest_HandlesResnr.xml
src/gromacs/selection/tests/refdata/SelectionCollectionDataTest_HandlesSameResidue.xml
src/gromacs/selection/tests/refdata/SelectionCollectionDataTest_HandlesSameResidueName.xml
src/gromacs/selection/tests/refdata/SelectionCollectionDataTest_HandlesSelectionNames.xml [new file with mode: 0644]
src/gromacs/selection/tests/refdata/SelectionCollectionDataTest_HandlesUnusedVariables.xml
src/gromacs/selection/tests/refdata/SelectionCollectionDataTest_HandlesVariablesWithMixedEvaluationGroups.xml
src/gromacs/selection/tests/refdata/SelectionCollectionDataTest_HandlesVariablesWithMixedEvaluationGroups2.xml
src/gromacs/selection/tests/refdata/SelectionCollectionDataTest_HandlesVariablesWithStaticEvaluationGroups.xml
src/gromacs/selection/tests/refdata/SelectionCollectionDataTest_HandlesWildcardMatching.xml
src/gromacs/selection/tests/refdata/SelectionCollectionDataTest_HandlesWithinConstantPositions.xml
src/gromacs/selection/tests/refdata/SelectionCollectionDataTest_HandlesWithinKeyword.xml
src/gromacs/selection/tests/refdata/referencedata.xsl
src/gromacs/selection/tests/selectioncollection.cpp
src/gromacs/selection/tests/simple.ndx [new file with mode: 0644]
src/gromacs/selection/tests/toputils.cpp
src/gromacs/selection/tests/toputils.h
src/gromacs/trajectoryanalysis/analysismodule.cpp
src/gromacs/trajectoryanalysis/modules/angle.cpp
src/gromacs/trajectoryanalysis/modules/distance.cpp
src/gromacs/trajectoryanalysis/modules/distance.h
src/gromacs/trajectoryanalysis/modules/freevolume.cpp
src/gromacs/trajectoryanalysis/modules/select.cpp
src/gromacs/trajectoryanalysis/modules/select.h
src/gromacs/trajectoryanalysis/tests/CMakeLists.txt
src/gromacs/trajectoryanalysis/tests/angle.cpp
src/gromacs/trajectoryanalysis/tests/distance.cpp [new file with mode: 0644]
src/gromacs/trajectoryanalysis/tests/refdata/AngleModuleTest_ComputesDihedrals.xml
src/gromacs/trajectoryanalysis/tests/refdata/AngleModuleTest_ComputesMultipleAngles.xml [new file with mode: 0644]
src/gromacs/trajectoryanalysis/tests/refdata/AngleModuleTest_ComputesPlaneZAxisAngles.xml
src/gromacs/trajectoryanalysis/tests/refdata/AngleModuleTest_ComputesSimpleAngles.xml
src/gromacs/trajectoryanalysis/tests/refdata/AngleModuleTest_ComputesVectorPairAngles.xml
src/gromacs/trajectoryanalysis/tests/refdata/AngleModuleTest_ComputesVectorPlanePairAngles.xml
src/gromacs/trajectoryanalysis/tests/refdata/AngleModuleTest_ComputesVectorSphereNormalZAxisAngles.xml
src/gromacs/trajectoryanalysis/tests/refdata/AngleModuleTest_ComputesVectorTimeZeroAngles.xml
src/gromacs/trajectoryanalysis/tests/refdata/AngleModuleTest_HandlesDynamicSelections.xml [new file with mode: 0644]
src/gromacs/trajectoryanalysis/tests/refdata/DistanceModuleTest_ComputesDistances.xml [new file with mode: 0644]
src/gromacs/trajectoryanalysis/tests/refdata/DistanceModuleTest_ComputesMultipleDistances.xml [new file with mode: 0644]
src/gromacs/trajectoryanalysis/tests/refdata/DistanceModuleTest_HandlesDynamicSelections.xml [new file with mode: 0644]
src/gromacs/trajectoryanalysis/tests/refdata/SelectModuleTest_BasicTest.xml
src/gromacs/trajectoryanalysis/tests/refdata/SelectModuleTest_HandlesDumpOption.xml [deleted file]
src/gromacs/trajectoryanalysis/tests/refdata/SelectModuleTest_HandlesMaxPDBOutput.xml
src/gromacs/trajectoryanalysis/tests/refdata/SelectModuleTest_HandlesPDBOutputWithNonPDBInput.xml
src/gromacs/trajectoryanalysis/tests/refdata/SelectModuleTest_HandlesPDBOutputWithPDBInput.xml
src/gromacs/trajectoryanalysis/tests/refdata/SelectModuleTest_HandlesSelectedPDBOutput.xml
src/gromacs/trajectoryanalysis/tests/refdata/analysisdata-referencedata.xsl
src/gromacs/trajectoryanalysis/tests/select.cpp
src/gromacs/utility/CMakeLists.txt
src/gromacs/utility/common.h
src/gromacs/utility/exceptions.cpp
src/gromacs/utility/exceptions.h
src/gromacs/utility/gmxassert.h
src/gromacs/utility/init.cpp [new file with mode: 0644]
src/gromacs/utility/init.h [new file with mode: 0644]
src/gromacs/utility/programinfo.cpp
src/ngmx/g_xrama.cpp
src/ngmx/ngmx.cpp
src/programs/gmx/CreateLinks.cmake.cmakein
src/programs/gmx/gmx.cpp
src/programs/gmx/legacymodules.cpp
src/programs/mdrun/CMakeLists.txt
src/programs/mdrun/mdrun.cpp
src/testutils/analysisdata-referencedata.xsl
src/testutils/cmdlinetest.cpp
src/testutils/cmdlinetest.h
src/testutils/datatest.cpp
src/testutils/datatest.h
src/testutils/mock_datamodule.cpp
src/testutils/refdata.cpp
src/testutils/refdata.h
src/testutils/stringtest.cpp
src/testutils/stringtest.h
src/testutils/testasserts.h
src/testutils/testoptions.cpp
src/testutils/testoptions.h
src/testutils/unittest_main.cpp
src/tools/CMakeLists.txt [deleted file]
src/tools/g_pme_error.c [deleted file]

index dea2ac5e65783a0bc4902156e8b9f30b086bfb92..2e57adef754b198b515b2ff5dd52b79448e66fc4 100644 (file)
@@ -127,10 +127,6 @@ mark_as_advanced(GMX_FAHCORE)
 # decide on GPU settings based on user-settings and GPU/CUDA detection
 include(gmxManageGPU)
 
-# TODO: move OpenMM to contrib
-option(GMX_OPENMM "Accelerated execution on GPUs through the OpenMM library (rerun cmake after changing to see relevant options)" OFF)
-mark_as_advanced(GMX_OPENMM)
-
 include(gmxDetectAcceleration)
 if(NOT DEFINED GMX_CPU_ACCELERATION)
     if(CMAKE_CROSSCOMPILING)
@@ -185,6 +181,11 @@ mark_as_advanced(GMX_CYCLE_SUBCOUNTERS)
 option(GMX_SKIP_DEFAULT_CFLAGS "Don't automatically add suggested/required Compiler flags." OFF)
 mark_as_advanced(GMX_SKIP_DEFAULT_CFLAGS)
 
+option(GMX_BUILD_FOR_COVERAGE
+       "Tune build for better code coverage metrics (e.g., disable asserts)"
+       OFF)
+mark_as_advanced(GMX_BUILD_FOR_COVERAGE)
+
 ######################################################################
 # Compiler tests
 # These need to be done early (before further tests).
@@ -1186,6 +1187,15 @@ else()
             COMPONENT development)
 endif()
 
+if (GMX_BUILD_FOR_COVERAGE)
+    # Code heavy with asserts makes conditional coverage close to useless metric,
+    # as by design most of the false branches are impossible to trigger in
+    # correctly functioning code.  And the benefit of testing those that could
+    # be triggered by using an API against its specification isn't usually
+    # worth the effort.
+    add_definitions(-DNDEBUG -DBOOST_DISABLE_ASSERTS -DGMX_DISABLE_ASSERTS)
+endif ()
+
 add_subdirectory(doxygen)
 add_subdirectory(share)
 add_subdirectory(src)
index b5ede9a4d840e5dff8dd94a33d0a8707646b084f..e890e46f921b8dad3286826543d7d0f9101de47e 100644 (file)
@@ -28,7 +28,6 @@
 \newcommand{\threadmpi}{ThreadMPI}
 \newcommand{\openmpi}{OpenMPI}
 \newcommand{\openmp}{OpenMP}
-\newcommand{\openmm}{OpenMM}
 \newcommand{\lammpi}{LAM/MPI}
 \newcommand{\mpich}{MPICH}
 \newcommand{\cmake}{CMake}
@@ -145,17 +144,6 @@ If you wish to use the excellent new native GPU support in \gromacs,
 version is strongly encouraged. \nvidia{} GPUs with at least \nvidia{} compute
 capability 2.0 are required, e.g. Fermi or Kepler cards.
 
-The GPU support from \gromacs{} version 4.5 using \openmm{}
-\url{https://simtk.org/home/openmm} is still contained in the code,
-but in the ``user contributions'' section (\verb+src/contrib+). You
-will need to set
-\verb+-DGMX_OPENMM=on -DGMX_GPU=off -DGMX_MPI=off
--DGMX_THREAD_MPI=off\+ in order to build it. It also requires \cuda{},
-and remains the only hardware-based acceleration available for
-implicit solvent simulations in \gromacs{} at the moment. However, the
-long-term plan is to enable this functionality in core Gromacs, and
-not have the OpenMM interface supported by the \gromacs team.
-
 If you wish to run in parallel on multiple machines across a network,
 you will need to have
 \begin{itemize}
index e8d794f9fd2df88ea788c56c6f0f25f8c4600228..4a40100eef0c6d3f21a464c9ad8b995b2725ce83 100644 (file)
    fun:inflateInit2_
 }
 
+# OpenMPI
+{
+   MPI_Init/Leak
+   Memcheck:Leak
+   ...
+   fun:PMPI_Init
+}
+{
+   MPI_Finalize/Leak
+   Memcheck:Leak
+   fun:malloc
+   fun:ompi_proc_all
+   ...
+   fun:gmx_finalize_par
+}
+{
+   MPI_Init/Addr4
+   Memcheck:Addr4
+   ...
+   fun:PMPI_Init
+}
+{
+   MPI_Init/sched_setaffinity
+   Memcheck:Param
+   sched_setaffinity(mask)
+   ...
+   fun:PMPI_Init
+}
+{
+   MPI_Init/writev
+   Memcheck:Param
+   writev(vector[...])
+   ...
+   fun:PMPI_Init
+}
+
 {
    gmx_fio_fopen
    Memcheck:Leak
    obj:*/mdrun*
 }
 
+{
+   strdup/strtod
+   Memcheck:Addr8
+   fun:__GI___strncasecmp_l
+   fun:____strtod_l_internal
+}
+
 
 #MacOS rules
 {
index 91f48d75a981bb8939fe8768d74d71315d461f85..852bcfd65c8163a71ecdcd7054fb8d34246b9bd5 100644 (file)
@@ -12,6 +12,7 @@ EXCLUDE                = @CMAKE_SOURCE_DIR@/src/contrib \
 EXCLUDE_SYMBOLS        = YY* yy* _gmx_sel_yy*
 EXCLUDE_SYMBOLS       += TEST TEST_F TEST_P TYPED_TEST_CASE TYPED_TEST INSTANTIATE_TEST_CASE_P
 EXCLUDE_SYMBOLS       += MOCK_METHOD* MOCK_CONST_METHOD*
+EXCLUDE_SYMBOLS       += GMX_TEST_OPTIONS
 FULL_PATH_NAMES        = YES
 STRIP_FROM_PATH        = @CMAKE_SOURCE_DIR@
 STRIP_FROM_INC_PATH    = @CMAKE_SOURCE_DIR@/src
index 7d0a833ab1f81b80fb8045a8fca8d0c703a388b4..0dbedce4b1999e6cc96c58c826f09f3276edb5c3 100644 (file)
@@ -128,7 +128,7 @@ AnalysisTemplate::initAnalysis(const TrajectoryAnalysisSettings &settings,
 {
     nb_.setCutoff(cutoff_);
 
-    data_.setColumnCount(sel_.size());
+    data_.setColumnCount(0, sel_.size());
 
     avem_.reset(new AnalysisDataAverageModule());
     data_.addModule(avem_);
@@ -185,7 +185,7 @@ AnalysisTemplate::writeOutput()
     for (size_t g = 0; g < sel_.size(); ++g)
     {
         fprintf(stderr, "Average mean distance for '%s': %.3f nm\n",
-                sel_[g].name(), avem_->average(g));
+                sel_[g].name(), avem_->average(0, g));
     }
 }
 
index bf5782ae3c995f4175e7e12b898fd29ef5ac009c..2123d3d2fc840b7b8ffff432cd2c335c9f634040 100644 (file)
@@ -1,4 +1,4 @@
-367
+370
 If You Want Something Done You Have to Do It Yourself_(Highlander II)
 I Live the Life They Wish They Did_(Tricky)
 Jesus Built My Hotrod_(Ministry)
@@ -365,3 +365,6 @@ Science Won't Change You_(The Talking Heads)
 It Doesn't Seem Right, No Computers in Sight_(Faun Fables)
 Some People Say Not to Worry About the Air_(The Talking Heads)
 It seemed a good idea at first_(Gerrit Groenhof)
+There's no kill like overkill, right?_(Erik Lindahl)
+I removed all the lambda defaults so that users have to think!_(Berk Hess)
+I originally implemented PME to prove that you didn't need it..._(Erik Lindahl)
index b8c10d6d82a8f92d02f0bb54602c8e22da742104..a18a3a3894f1f09f31f8987d8178b4fd7b1be70c 100644 (file)
@@ -17,7 +17,6 @@ add_subdirectory(gromacs)
 add_subdirectory(programs)
 
 if(NOT GMX_FAHCORE)
-  add_subdirectory(tools)
   add_subdirectory(ngmx)
   add_subdirectory(contrib)
 endif(NOT GMX_FAHCORE)
diff --git a/src/contrib/BuildMdrunOpenMM.cmake b/src/contrib/BuildMdrunOpenMM.cmake
deleted file mode 100644 (file)
index 4f82c34..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-#
-# This file is part of the GROMACS molecular simulation package.
-#
-# Copyright (c) 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.
-#
-# GROMACS is free software; you can redistribute it and/or
-# modify it under the terms of the GNU Lesser General Public License
-# as published by the Free Software Foundation; either version 2.1
-# of the License, or (at your option) any later version.
-#
-# GROMACS is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-# Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with GROMACS; if not, see
-# http://www.gnu.org/licenses, or write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
-#
-# If you want to redistribute modifications to GROMACS, 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 http://www.gromacs.org.
-#
-# To help us fund GROMACS development, we humbly ask that you cite
-# the research papers on the package. Check out http://www.gromacs.org.
-#
-
-include_directories(${OpenMM_INCLUDE_DIR})
-link_directories(${OpenMM_LIBRARY_DIR}) 
-# with this define no evn.var. is needed with OPENMM_PLUGIN_DIR
-# if the same OpenMM installation is used for running and building 
-add_definitions( -DOPENMM_PLUGIN_DIR="${OpenMM_PLUGIN_DIR}" ) 
-file(TO_CMAKE_PATH ${OpenMM_PLUGIN_DIR} _path)
-add_library(openmm_api_wrapper STATIC ${CMAKE_SOURCE_DIR}/src/contrib/openmm_wrapper.cpp)
-target_link_libraries(openmm_api_wrapper ${OpenMM_LIBRARIES})
-
-list(REMOVE_ITEM MDRUN_SOURCES mdrun.c runner.c)
-list(APPEND MDRUN_SOURCES
-    ${CMAKE_SOURCE_DIR}/src/contrib/md_openmm.c
-    ${CMAKE_SOURCE_DIR}/src/contrib/mdrun_openmm.c
-    ${CMAKE_SOURCE_DIR}/src/contrib/runner_openmm.c
-    )
-
-# this is to circumvent the following MSVC error: 
-# warning LNK4098: defaultlib 'LIBCMT' conflicts with use of other libs
-# fatal error LNK1169: one or more multiply defined symbols found
-if(GMX_OPENMM AND MSVC)
-    set_target_properties(mdrun PROPERTIES LINK_FLAGS "/NODEFAULTLIB:LIBCMT")
-endif()
-
-include_directories(${CMAKE_SOURCE_DIR}/src/gmxlib/gpu_utils)
-
-set_source_files_properties(main.c PROPERTIES LANGUAGE CXX)
-if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
-    set_source_files_properties(main.c PROPERTIES COMPILE_FLAGS "-x c++")
-endif()
index 3dff35583d6196be25ed899c58fac3dcd42cca05..32cb46f44ff8b4ebe4c8e03ca2c1567733d309f9 100644 (file)
@@ -3,82 +3,6 @@ set(CONTRIB_PROGRAMS
 
 )
 
-# Uncomment the next line to build OpenMM:
-#option(GMX_OPENMM "Accelerated execution on GPUs through the OpenMM library (no longer supported" ON)
-
-# At run time, you may need to set the environment variable
-# OPENMM_PLUGIN_DIR=PATH_TO_GROMACS/openmm/lib/plugins
-# to make things work
-
-if(GMX_OPENMM)
-    if(GMX_GPU)
-        message(FATAL_ERROR "The OpenMM build is not compatible with the native GPU build")
-    endif()
-
-    # These won't actually do anything unless they precede the
-    # definition of these options elsewhere. However, they can't be
-    # FORCE-d either.
-    set(GMX_BINARY_SUFFIX "-openmm" CACHE STRING "Suffix to distinguish OpenMM build from normal")
-    set(GMX_LIBS_SUFFIX "_openmm" CACHE STRING "Suffix to distinguish OpenMM build from normal")
-
-#######################################################################
-# Check for options incompatible with OpenMM build                    #
-#######################################################################
-    # we'll use the built-in fft to avoid unnecessary dependencies
-    string(TOUPPER ${GMX_FFT_LIBRARY} GMX_FFT_LIBRARY)
-    if(NOT ${GMX_FFT_LIBRARY} STREQUAL "FFTPACK")
-        message(STATUS "No external FFT libraries needed for the OpenMM build, switching to fftpack!")
-        set(GMX_FFT_LIBRARY "fftpack" CACHE STRING 
-               "No external FFT libraries needed for the OpenMM build, switching to  fftpack!" FORCE)
-    endif()
-    if(GMX_MPI)
-        message(FATAL_ERROR "The OpenMM build is not compatible with MPI!")
-    endif(GMX_MPI)
-    if(GMX_THREAD_MPI)
-        message(STATUS "Thread-MPI not compatible with OpenMM, disabled!")
-        set(GMX_THREAD_MPI OFF CACHE BOOL
-               "Thread-MPI not compatible with OpenMM build, disabled!" FORCE)
-    endif(GMX_THREAD_MPI)
-    if(GMX_OPENMP)
-        message(STATUS "OpenMP multithreading not compatible with OpenMM, disabled")
-        set(GMX_OPENMP OFF CACHE BOOL
-            "OpenMP multithreading not compatible with OpenMM, disabled!" FORCE)
-    endif()
-    if(GMX_SOFTWARE_INVSQRT)
-        set(GMX_SOFTWARE_INVSQRT OFF CACHE STRING 
-                "The OpenMM build does not need GROMACS software 1/sqrt!" FORCE)
-    endif(GMX_SOFTWARE_INVSQRT)
-    string(TOUPPER ${GMX_CPU_ACCELERATION} GMX_CPU_ACCELERATION)
-    if(NOT GMX_CPU_ACCELERATION STREQUAL "NONE")
-        message(STATUS "Switching off CPU-based acceleration, the OpenMM build does not support/need any!")
-        set(GMX_CPU_ACCELERATION "None" CACHE STRING
-            "Switching off CPU-based acceleration, the OpenMM build does not support/need any!" FORCE)
-    endif()
-    if(GMX_FAHCORE)
-        message(FATAL_ERROR "The OpenMM build does not support FAH build!")
-    endif(GMX_FAHCORE)
-    if(GMX_DOUBLE)
-        message(FATAL_ERROR  "The OpenMM-build does not support double precision calculations!")
-    endif()
-
-    set(CUDA_BUILD_EMULATION OFF)
-    find_package(CUDA 3.1 REQUIRED)
-    add_definitions(-DGMX_OPENMM)
-    if(CMAKE_BUILD_TYPE STREQUAL "DEBUG")    
-        set(CUDA_VERBOSE_BUILD ON)
-    endif()
-
-    # mark as advanced the unused variables
-    mark_as_advanced(FORCE GMX_CPU_ACCELERATION GMX_MPI GMX_FFT_LIBRARY 
-        GMX_QMMM_PROGRAM GMX_THREAD_MPI GMX_DOUBLE)
-
-else(GMX_OPENMM)
-
-     mark_as_advanced(CLEAR GMX_CPU_ACCELERATION GMX_MPI GMX_FFT_LIBRARY 
-        GMX_QMMM_PROGRAM GMX_THREAD_MPI GMX_DOUBLE)
-
-endif(GMX_OPENMM)
-
 foreach(PROG ${CONTRIB_PROGRAMS})
         add_executable(${PROG} ${PROG}.c ${NGMX_COMMON_SOURCE})
        set_target_properties(${PROG} PROPERTIES OUTPUT_NAME "${PROG}${GMX_BINARY_SUFFIX}")
diff --git a/src/contrib/FindOpenMM.cmake b/src/contrib/FindOpenMM.cmake
deleted file mode 100644 (file)
index 541b2a4..0000000
+++ /dev/null
@@ -1,104 +0,0 @@
-# Find OpenMM library.
-#
-# Looks for the OpenMM libraries at the default (/usr/local) location 
-# or custom location found in the OPENMM_ROOT_DIR environment variable. 
-#
-# The script defines defines: 
-#  OpenMM_FOUND     
-#  OpenMM_ROOT_DIR
-#  OpenMM_INCLUDE_DIR
-#  OpenMM_LIBRARY_DIR
-#  OpenMM_LIBRARIES      
-#  OpenMM_LIBRARIES_D   - debug version of libraries 
-#  OpenMM_PLUGIN_DIR
-#
-
-# Author: Szilard Pall (pszilard@cbr.su.se)
-
-if(OpenMM_INCLUDE_DIR AND OpenMM_LIBRARY_DIR AND OpenMM_PLUGIN_DIR)
-    set(OpenMM_FIND_QUIETLY)
-endif()
-
-file(TO_CMAKE_PATH "$ENV{OPENMM_ROOT_DIR}" _env_OPENMM_ROOT_DIR)
-
-if(IS_DIRECTORY ${_env_OPENMM_ROOT_DIR})
-    set(OpenMM_ROOT_DIR "${_env_OPENMM_ROOT_DIR}" CACHE PATH "OpenMM installation directory" FORCE)
-else()
-    if(IS_DIRECTORY "/usr/local/openmm")
-        set(OpenMM_ROOT_DIR "/usr/local/openmm" CACHE PATH "OpenMM installation directory" FORCE)
-    endif()
-endif()
-
-find_library(OpenMM_LIBRARIES
-    NAMES OpenMM
-    PATHS "${OpenMM_ROOT_DIR}/lib"
-    CACHE STRING "OpenMM libraries")
-
-find_library(OpenMM_LIBRARIES_D
-    NAMES OpenMM_d
-    PATHS "${OpenMM_ROOT_DIR}/lib"
-    CACHE STRING "OpenMM debug libraries")
-
-if(OpenMM_LIBRARIES_D AND NOT OpenMM_LIBRARIES)
-    set(OpenMM_LIBRARIES ${OpenMM_LIBRARIES_D}
-        CACHE STRING "OpenMM libraries" FORCE)
-    message(WARNING " Only found debug versions of the OpenMM libraries!")
-endif()
-
-get_filename_component(OpenMM_LIBRARY_DIR 
-    ${OpenMM_LIBRARIES} 
-    PATH
-    CACHE STRING "OpenMM library path")
-
-find_path(OpenMM_INCLUDE_DIR 
-    NAMES OpenMM.h 
-    PATHS "${OpenMM_ROOT_DIR}/include" "${OpenMM_LIBRARY_DIR}/../include"
-    CACHE STRING "OpenMM include directory")    
-
-# if we did not manage to set the root dir at the beginning but found the 
-# libs then set the ${OpenMM_LIBRARY_DIR}/.. as root
-if(NOT IS_DIRECTORY ${OpenMM_ROOT_DIR})
-    if (IS_DIRECTORY "${OpenMM_LIBRARY_DIR}/..") # just double-checking
-        get_filename_component(OpenMM_ROOT_DIR 
-            "${OpenMM_LIBRARY_DIR}/.." 
-            ABSOLUTE)
-    endif()   
-endif()
-
-if(NOT IS_DIRECTORY ${OpenMM_ROOT_DIR})
-    message(FATAL_ERROR "Could not find OpenMM! Set the OPENMM_ROOT_DIR environment "
-    "variable to contain the path of the OpenMM installation.")
-endif()
-
-if(NOT IS_DIRECTORY ${OpenMM_LIBRARY_DIR})
-    message(FATAL_ERROR "Can't find OpenMM libraries. Check your OpenMM installation!")
-endif()
-
-# now we can be sure that we have the library dir
-if(IS_DIRECTORY "${OpenMM_LIBRARY_DIR}/plugins")
-    get_filename_component(OpenMM_PLUGIN_DIR
-        "${OpenMM_LIBRARY_DIR}/plugins"
-        ABSOLUTE)
-    set(OpenMM_PLUGIN_DIR ${OpenMM_PLUGIN_DIR} CACHE PATH "OpenMM plugins directory")
-else()
-    message(WARNING "Could not detect the OpenMM plugin directory at the default location (${OpenMM_LIBRARY_DIR}/plugins)."
-            "Check your OpenMM installation or set the OPENMM_PLUGIN_DIR environment variable!")
-endif()
-
-if(NOT OpenMM_INCLUDE_DIR)
-    message(FATAL_ERROR "Can't find OpenMM includes. Check your OpenMM installation!")
-endif()
-
-set(OpenMM_ROOT_DIR ${OpenMM_ROOT_DIR} CACHE PATH "OpenMM installation directory")
-
-include(FindPackageHandleStandardArgs)
-find_package_handle_standard_args(OpenMM DEFAULT_MSG 
-                                    OpenMM_ROOT_DIR
-                                    OpenMM_LIBRARIES 
-                                    OpenMM_LIBRARY_DIR 
-                                    OpenMM_INCLUDE_DIR)
-
-mark_as_advanced(OpenMM_INCLUDE_DIR
-    OpenMM_LIBRARIES
-    OpenMM_LIBRARIES_D
-    OpenMM_LIBRARY_DIR)
diff --git a/src/contrib/md_openmm.c b/src/contrib/md_openmm.c
deleted file mode 100644 (file)
index d5a15e7..0000000
+++ /dev/null
@@ -1,585 +0,0 @@
-/*
- * This file is part of the GROMACS molecular simulation package.
- *
- * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
- * Copyright (c) 2001-2010, The GROMACS development team,
- * check out http://www.gromacs.org for more information.
- * Copyright (c) 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.
- *
- * GROMACS is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1
- * of the License, or (at your option) any later version.
- *
- * GROMACS is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with GROMACS; if not, see
- * http://www.gnu.org/licenses, or write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
- *
- * If you want to redistribute modifications to GROMACS, 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 http://www.gromacs.org.
- *
- * To help us fund GROMACS development, we humbly ask that you cite
- * the research papers on the package. Check out http://www.gromacs.org.
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <signal.h>
-#include <stdlib.h>
-
-#include "typedefs.h"
-#include "smalloc.h"
-#include "sysstuff.h"
-#include "vec.h"
-#include "statutil.h"
-#include "vcm.h"
-#include "mdebin.h"
-#include "nrnb.h"
-#include "calcmu.h"
-#include "index.h"
-#include "vsite.h"
-#include "update.h"
-#include "ns.h"
-#include "trnio.h"
-#include "xtcio.h"
-#include "mdrun.h"
-#include "md_support.h"
-#include "confio.h"
-#include "network.h"
-#include "pull.h"
-#include "xvgr.h"
-#include "physics.h"
-#include "names.h"
-#include "xmdrun.h"
-#include "ionize.h"
-#include "disre.h"
-#include "orires.h"
-#include "pme.h"
-#include "mdatoms.h"
-#include "qmmm.h"
-#include "mpelogging.h"
-#include "domdec.h"
-#include "partdec.h"
-#include "topsort.h"
-#include "coulomb.h"
-#include "constr.h"
-#include "compute_io.h"
-#include "mvdata.h"
-#include "checkpoint.h"
-#include "mtop_util.h"
-#include "sighandler.h"
-#include "genborn.h"
-#include "string2.h"
-#include "copyrite.h"
-#include "membed.h"
-
-#ifdef GMX_THREAD_MPI
-#include "tmpi.h"
-#endif
-
-/* include even when OpenMM not used to force compilation of do_md_openmm */
-#include "openmm_wrapper.h"
-
-double do_md_openmm(FILE *fplog,t_commrec *cr,int nfile,const t_filenm fnm[],
-                    const output_env_t oenv, gmx_bool bVerbose,gmx_bool bCompact,
-                    int nstglobalcomm,
-                    gmx_vsite_t *vsite,gmx_constr_t constr,
-                    int stepout,t_inputrec *ir,
-                    gmx_mtop_t *top_global,
-                    t_fcdata *fcd,
-                    t_state *state_global,
-                    t_mdatoms *mdatoms,
-                    t_nrnb *nrnb,gmx_wallcycle_t wcycle,
-                    gmx_edsam_t ed,t_forcerec *fr,
-                    int repl_ex_nst, int repl_ex_nex, int repl_ex_seed,
-                    gmx_membed_t membed,
-                    real cpt_period,real max_hours,
-                    const char *deviceOptions,
-                    unsigned long Flags,
-                    gmx_runtime_t *runtime)
-{
-    gmx_mdoutf_t *outf;
-    gmx_large_int_t step,step_rel;
-    double     run_time;
-    double     t,t0,lam0;
-    gmx_bool       bSimAnn,
-    bFirstStep,bStateFromTPX,bLastStep,bStartingFromCpt;
-    gmx_bool       bInitStep=TRUE;
-    gmx_bool       do_ene,do_log, do_verbose,
-    bX,bV,bF,bCPT;
-    tensor     force_vir,shake_vir,total_vir,pres;
-    int        i,m;
-    int        mdof_flags;
-    rvec       mu_tot;
-    t_vcm      *vcm;
-    int        nchkpt=1;
-    gmx_localtop_t *top;
-    t_mdebin *mdebin;
-    t_state    *state=NULL;
-    rvec       *f_global=NULL;
-    int        n_xtc=-1;
-    rvec       *x_xtc=NULL;
-    gmx_enerdata_t *enerd;
-    rvec       *f=NULL;
-    gmx_global_stat_t gstat;
-    gmx_update_t upd=NULL;
-    t_graph    *graph=NULL;
-    globsig_t   gs;
-
-    gmx_groups_t *groups;
-    gmx_ekindata_t *ekind, *ekind_save;
-    gmx_bool        bAppend;
-    int         a0,a1;
-    matrix      lastbox;
-    real        reset_counters=0,reset_counters_now=0;
-    char        sbuf[STEPSTRSIZE],sbuf2[STEPSTRSIZE];
-    int         handled_stop_condition=gmx_stop_cond_none; 
-
-    const char *ommOptions = NULL;
-    void   *openmmData;
-
-#ifdef GMX_DOUBLE
-    /* Checks in cmake should prevent the compilation in double precision
-     * with OpenMM, but just to be sure we check here.
-     */
-    gmx_fatal(FARGS,"Compilation was performed in double precision, but OpenMM only supports single precision. If you want to use to OpenMM, compile in single precision.");
-#endif
-
-    bAppend  = (Flags & MD_APPENDFILES);
-    check_ir_old_tpx_versions(cr,fplog,ir,top_global);
-
-    groups = &top_global->groups;
-
-    /* Initial values */
-    init_md(fplog,cr,ir,oenv,&t,&t0,state_global->lambda,
-            &(state_global->fep_state),&lam0,
-            nrnb,top_global,&upd,
-            nfile,fnm,&outf,&mdebin,
-            force_vir,shake_vir,mu_tot,&bSimAnn,&vcm,state_global,Flags);
-
-    clear_mat(total_vir);
-    clear_mat(pres);
-    /* Energy terms and groups */
-    snew(enerd,1);
-    init_enerdata(top_global->groups.grps[egcENER].nr,ir->fepvals->n_lambda,
-                  enerd);
-    snew(f,top_global->natoms);
-
-    /* Kinetic energy data */
-    snew(ekind,1);
-    init_ekindata(fplog,top_global,&(ir->opts),ekind);
-    /* needed for iteration of constraints */
-    snew(ekind_save,1);
-    init_ekindata(fplog,top_global,&(ir->opts),ekind_save);
-    /* Copy the cos acceleration to the groups struct */
-    ekind->cosacc.cos_accel = ir->cos_accel;
-
-    gstat = global_stat_init(ir);
-    debug_gmx();
-
-    {
-        double io = compute_io(ir,top_global->natoms,groups,mdebin->ebin->nener,1);
-        if ((io > 2000) && MASTER(cr))
-            fprintf(stderr,
-                    "\nWARNING: This run will generate roughly %.0f Mb of data\n\n",
-                    io);
-    }
-
-    top = gmx_mtop_generate_local_top(top_global,ir);
-
-    a0 = 0;
-    a1 = top_global->natoms;
-
-    state = partdec_init_local_state(cr,state_global);
-    f_global = f;
-
-    atoms2md(top_global,ir,0,NULL,a0,a1-a0,mdatoms);
-
-    if (vsite)
-    {
-        set_vsite_top(vsite,top,mdatoms,cr);
-    }
-
-    if (ir->ePBC != epbcNONE && !ir->bPeriodicMols)
-    {
-        graph = mk_graph(fplog,&(top->idef),0,top_global->natoms,FALSE,FALSE);
-    }
-
-    update_mdatoms(mdatoms,state->lambda[efptMASS]);
-
-    if (deviceOptions[0]=='\0')
-    {
-        /* empty options, which should default to OpenMM in this build */
-        ommOptions=deviceOptions;
-    }
-    else
-    {
-        if (gmx_strncasecmp(deviceOptions,"OpenMM",6)!=0)
-        {
-            gmx_fatal(FARGS, "This Gromacs version currently only works with OpenMM. Use -device \"OpenMM:<options>\"");
-        }
-        else
-        {
-            ommOptions=strchr(deviceOptions,':');
-            if (NULL!=ommOptions)
-            {
-                /* Increase the pointer to skip the colon */
-                ommOptions++;
-            }
-        }
-    }
-
-    openmmData = openmm_init(fplog, ommOptions, ir, top_global, top, mdatoms, fr, state);
-    please_cite(fplog,"Friedrichs2009");
-
-    if (MASTER(cr))
-    {
-        /* Update mdebin with energy history if appending to output files */
-        if ( Flags & MD_APPENDFILES )
-        {
-            restore_energyhistory_from_state(mdebin,&state_global->enerhist);
-        }
-        /* Set the initial energy history in state to zero by updating once */
-        update_energyhistory(&state_global->enerhist,mdebin);
-    }
-
-    if (constr)
-    {
-        set_constraints(constr,top,ir,mdatoms,cr);
-    }
-
-    if (!ir->bContinuation)
-    {
-        if (mdatoms->cFREEZE && (state->flags & (1<<estV)))
-        {
-            /* Set the velocities of frozen particles to zero */
-            for (i=mdatoms->start; i<mdatoms->start+mdatoms->homenr; i++)
-            {
-                for (m=0; m<DIM; m++)
-                {
-                    if (ir->opts.nFreeze[mdatoms->cFREEZE[i]][m])
-                    {
-                        state->v[i][m] = 0;
-                    }
-                }
-            }
-        }
-
-        if (constr)
-        {
-            /* Constrain the initial coordinates and velocities */
-            do_constrain_first(fplog,constr,ir,mdatoms,state,f,
-                               graph,cr,nrnb,fr,top,shake_vir);
-        }
-        if (vsite)
-        {
-            /* Construct the virtual sites for the initial configuration */
-            construct_vsites(fplog,vsite,state->x,nrnb,ir->delta_t,NULL,
-                             top->idef.iparams,top->idef.il,
-                             fr->ePBC,fr->bMolPBC,graph,cr,state->box);
-        }
-    }
-
-    debug_gmx();
-
-    if (MASTER(cr))
-    {
-        char tbuf[20];
-        fprintf(stderr,"starting mdrun '%s'\n",
-                *(top_global->name));
-        if (ir->nsteps >= 0)
-        {
-            sprintf(tbuf,"%8.1f",(ir->init_step+ir->nsteps)*ir->delta_t);
-        }
-        else
-        {
-            sprintf(tbuf,"%s","infinite");
-        }
-        if (ir->init_step > 0)
-        {
-            fprintf(stderr,"%s steps, %s ps (continuing from step %s, %8.1f ps).\n",
-                    gmx_step_str(ir->init_step+ir->nsteps,sbuf),tbuf,
-                    gmx_step_str(ir->init_step,sbuf2),
-                    ir->init_step*ir->delta_t);
-        }
-        else
-        {
-            fprintf(stderr,"%s steps, %s ps.\n",
-                    gmx_step_str(ir->nsteps,sbuf),tbuf);
-        }
-    }
-
-    fprintf(fplog,"\n");
-
-    /* Set and write start time */
-    runtime_start(runtime);
-    print_date_and_time(fplog,cr->nodeid,"Started mdrun",runtime);
-    wallcycle_start(wcycle,ewcRUN);
-    if (fplog)
-        fprintf(fplog,"\n");
-
-    /* safest point to do file checkpointing is here.  More general point would be immediately before integrator call */
-
-    debug_gmx();
-    /***********************************************************
-     *
-     *             Loop over MD steps
-     *
-     ************************************************************/
-
-    /* loop over MD steps or if rerunMD to end of input trajectory */
-    bFirstStep = TRUE;
-    /* Skip the first Nose-Hoover integration when we get the state from tpx */
-    bStateFromTPX = !opt2bSet("-cpi",nfile,fnm);
-    bInitStep = bFirstStep && bStateFromTPX;
-    bStartingFromCpt = (Flags & MD_STARTFROMCPT) && bInitStep;
-    bLastStep = FALSE;
-
-    init_global_signals(&gs,cr,ir,repl_ex_nst);
-
-    step = ir->init_step;
-    step_rel = 0;
-
-    while (!bLastStep)
-    {
-        wallcycle_start(wcycle,ewcSTEP);
-
-        GMX_MPE_LOG(ev_timestep1);
-
-        bLastStep = (step_rel == ir->nsteps);
-        t = t0 + step*ir->delta_t;
-
-        if (gs.set[eglsSTOPCOND] != 0)
-        {
-            bLastStep = TRUE;
-        }
-
-        do_log = do_per_step(step,ir->nstlog) || bFirstStep || bLastStep;
-        do_verbose = bVerbose &&
-                     (step % stepout == 0 || bFirstStep || bLastStep);
-
-        if (MASTER(cr) && do_log)
-        {
-            print_ebin_header(fplog,step,t,state->lambda[efptFEP]);
-        }
-
-        clear_mat(force_vir);
-        GMX_MPE_LOG(ev_timestep2);
-
-        /* We write a checkpoint at this MD step when:
-         * either when we signalled through gs (in OpenMM NS works different),
-         * or at the last step (but not when we do not want confout),
-         * but never at the first step.
-         */
-        bCPT = ((gs.set[eglsCHKPT] ||
-                 (bLastStep && (Flags & MD_CONFOUT))) &&
-                step > ir->init_step );
-        if (bCPT)
-        {
-            gs.set[eglsCHKPT] = 0;
-        }
-
-        /* Now we have the energies and forces corresponding to the
-         * coordinates at time t. We must output all of this before
-         * the update.
-         * for RerunMD t is read from input trajectory
-         */
-        GMX_MPE_LOG(ev_output_start);
-
-        mdof_flags = 0;
-        if (do_per_step(step,ir->nstxout))
-        {
-            mdof_flags |= MDOF_X;
-        }
-        if (do_per_step(step,ir->nstvout))
-        {
-            mdof_flags |= MDOF_V;
-        }
-        if (do_per_step(step,ir->nstfout))
-        {
-            mdof_flags |= MDOF_F;
-        }
-        if (do_per_step(step,ir->nstxtcout))
-        {
-            mdof_flags |= MDOF_XTC;
-        }
-        if (bCPT)
-        {
-            mdof_flags |= MDOF_CPT;
-        };
-        do_ene = (do_per_step(step,ir->nstenergy) || bLastStep);
-
-        if (mdof_flags != 0 || do_ene || do_log)
-        {
-            wallcycle_start(wcycle,ewcTRAJ);
-            bF = (mdof_flags & MDOF_F);
-            bX = (mdof_flags & (MDOF_X | MDOF_XTC | MDOF_CPT));
-            bV = (mdof_flags & (MDOF_V | MDOF_CPT));
-
-            openmm_copy_state(openmmData, state, &t, f, enerd, bX, bV, bF, do_ene);
-
-            upd_mdebin(mdebin,FALSE,TRUE,
-                       t,mdatoms->tmass,enerd,state,ir->fepvals,ir->expandedvals,lastbox,
-                       shake_vir,force_vir,total_vir,pres,
-                       ekind,mu_tot,constr);
-            print_ebin(outf->fp_ene,do_ene,FALSE,FALSE,do_log?fplog:NULL,
-                       step,t,
-                       eprNORMAL,bCompact,mdebin,fcd,groups,&(ir->opts));
-            write_traj(fplog,cr,outf,mdof_flags,top_global,
-                       step,t,state,state_global,f,f_global,&n_xtc,&x_xtc);
-            if (bCPT)
-            {
-                nchkpt++;
-                bCPT = FALSE;
-            }
-            debug_gmx();
-            if (bLastStep && step_rel == ir->nsteps &&
-                    (Flags & MD_CONFOUT) && MASTER(cr))
-            {
-                /* x and v have been collected in write_traj,
-                 * because a checkpoint file will always be written
-                 * at the last step.
-                 */
-                fprintf(stderr,"\nWriting final coordinates.\n");
-                if (ir->ePBC != epbcNONE && !ir->bPeriodicMols)
-                {
-                    /* Make molecules whole only for confout writing */
-                    do_pbc_mtop(fplog,ir->ePBC,state->box,top_global,state_global->x);
-                }
-                write_sto_conf_mtop(ftp2fn(efSTO,nfile,fnm),
-                                    *top_global->name,top_global,
-                                    state_global->x,state_global->v,
-                                    ir->ePBC,state->box);
-                debug_gmx();
-            }
-            wallcycle_stop(wcycle,ewcTRAJ);
-        }
-        GMX_MPE_LOG(ev_output_finish);
-
-
-        /* Determine the wallclock run time up till now */
-        run_time = gmx_gettime() - (double)runtime->real;
-
-        /* Check whether everything is still allright */
-        if (((int)gmx_get_stop_condition() > handled_stop_condition)
-#ifdef GMX_THREAD_MPI
-            && MASTER(cr)
-#endif
-            )
-        {
-           /* this is just make gs.sig compatible with the hack 
-               of sending signals around by MPI_Reduce with together with
-               other floats */
-            /* NOTE: this only works for serial code. For code that allows
-               MPI nodes to propagate their condition, see kernel/md.c*/
-            if ( gmx_get_stop_condition() == gmx_stop_cond_next_ns )
-                gs.set[eglsSTOPCOND]=1;
-            if ( gmx_get_stop_condition() == gmx_stop_cond_next )
-                gs.set[eglsSTOPCOND]=1;
-            /* < 0 means stop at next step, > 0 means stop at next NS step */
-            if (fplog)
-            {
-                fprintf(fplog,
-                        "\n\nReceived the %s signal, stopping at the next %sstep\n\n",
-                        gmx_get_signal_name(),
-                        gs.sig[eglsSTOPCOND]==1 ? "NS " : "");
-                fflush(fplog);
-            }
-            fprintf(stderr,
-                    "\n\nReceived the %s signal, stopping at the next %sstep\n\n",
-                    gmx_get_signal_name(),
-                    gs.sig[eglsSTOPCOND]==1 ? "NS " : "");
-            fflush(stderr);
-            handled_stop_condition=(int)gmx_get_stop_condition();
-        }
-        else if (MASTER(cr) &&
-                 (max_hours > 0 && run_time > max_hours*60.0*60.0*0.99) &&
-                 gs.set[eglsSTOPCOND] == 0)
-        {
-            /* Signal to terminate the run */
-            gs.set[eglsSTOPCOND] = 1;
-            if (fplog)
-            {
-                fprintf(fplog,"\nStep %s: Run time exceeded %.3f hours, will terminate the run\n",gmx_step_str(step,sbuf),max_hours*0.99);
-            }
-            fprintf(stderr, "\nStep %s: Run time exceeded %.3f hours, will terminate the run\n",gmx_step_str(step,sbuf),max_hours*0.99);
-        }
-
-        /* checkpoints */
-        if (MASTER(cr) && (cpt_period >= 0 &&
-                           (cpt_period == 0 ||
-                            run_time >= nchkpt*cpt_period*60.0)) &&
-                gs.set[eglsCHKPT] == 0)
-        {
-            gs.set[eglsCHKPT] = 1;
-        }
-
-        /* Time for performance */
-        if (((step % stepout) == 0) || bLastStep)
-        {
-            runtime_upd_proc(runtime);
-        }
-
-        if (do_per_step(step,ir->nstlog))
-        {
-            if (fflush(fplog) != 0)
-            {
-                gmx_fatal(FARGS,"Cannot flush logfile - maybe you are out of disk space?");
-            }
-        }
-
-        /* Remaining runtime */
-        if (MULTIMASTER(cr) && (do_verbose || gmx_got_usr_signal() ))
-        {
-            print_time(stderr,runtime,step,ir,cr);
-        }
-
-        bFirstStep = FALSE;
-        bInitStep = FALSE;
-        bStartingFromCpt = FALSE;
-        step++;
-        step_rel++;
-
-        openmm_take_one_step(openmmData);
-    }
-    /* End of main MD loop */
-    debug_gmx();
-
-    /* Stop the time */
-    runtime_end(runtime);
-
-    if (MASTER(cr))
-    {
-        if (ir->nstcalcenergy > 0) 
-        {
-            print_ebin(outf->fp_ene,FALSE,FALSE,FALSE,fplog,step,t,
-                       eprAVER,FALSE,mdebin,fcd,groups,&(ir->opts));
-        }
-    }
-
-    openmm_cleanup(fplog, openmmData);
-
-    done_mdoutf(outf);
-
-    debug_gmx();
-
-    runtime->nsteps_done = step_rel;
-
-    return 0;
-}
diff --git a/src/contrib/md_openmm.h b/src/contrib/md_openmm.h
deleted file mode 100644 (file)
index d177db7..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * This file is part of the GROMACS molecular simulation package.
- *
- * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
- * Copyright (c) 2001-2010, The GROMACS development team,
- * check out http://www.gromacs.org for more information.
- * Copyright (c) 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.
- *
- * GROMACS is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1
- * of the License, or (at your option) any later version.
- *
- * GROMACS is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with GROMACS; if not, see
- * http://www.gnu.org/licenses, or write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
- *
- * If you want to redistribute modifications to GROMACS, 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 http://www.gromacs.org.
- *
- * To help us fund GROMACS development, we humbly ask that you cite
- * the research papers on the package. Check out http://www.gromacs.org.
- */
-#ifndef _MD_OPENMM_H
-#define _MD_OPENMM_H
-
-double do_md_openmm(FILE *fplog,t_commrec *cr,int nfile,const t_filenm fnm[],
-             const output_env_t oenv, gmx_bool bVerbose,gmx_bool bCompact,
-             int nstglobalcomm,
-             gmx_vsite_t *vsite,gmx_constr_t constr,
-             int stepout,t_inputrec *ir,
-             gmx_mtop_t *top_global,
-             t_fcdata *fcd,
-             t_state *state_global,
-             t_mdatoms *mdatoms,
-             t_nrnb *nrnb,gmx_wallcycle_t wcycle,
-             gmx_edsam_t ed,t_forcerec *fr,
-             int repl_ex_nst, int repl_ex_nex, int repl_ex_seed,
-             gmx_membed_t membed,
-             real cpt_period,real max_hours,
-             const char *deviceOptions,
-             unsigned long Flags,
-             gmx_runtime_t *runtime);
-
-#endif /* _MD_OPENMM_H */
diff --git a/src/contrib/mdrun_openmm.c b/src/contrib/mdrun_openmm.c
deleted file mode 100644 (file)
index a258666..0000000
+++ /dev/null
@@ -1,511 +0,0 @@
-/*
- * This file is part of the GROMACS molecular simulation package.
- *
- * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
- * Copyright (c) 2001-2004, The GROMACS development team,
- * check out http://www.gromacs.org for more information.
- * Copyright (c) 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.
- *
- * GROMACS is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1
- * of the License, or (at your option) any later version.
- *
- * GROMACS is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with GROMACS; if not, see
- * http://www.gnu.org/licenses, or write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
- *
- * If you want to redistribute modifications to GROMACS, 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 http://www.gromacs.org.
- *
- * To help us fund GROMACS development, we humbly ask that you cite
- * the research papers on the package. Check out http://www.gromacs.org.
- */
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include "typedefs.h"
-#include "macros.h"
-#include "copyrite.h"
-#include "main.h"
-#include "statutil.h"
-#include "smalloc.h"
-#include "futil.h"
-#include "smalloc.h"
-#include "edsam.h"
-#include "mdrun.h"
-#include "xmdrun.h"
-#include "checkpoint.h"
-#ifdef GMX_THREAD_MPI
-#include "thread_mpi.h"
-#endif
-
-/* afm stuf */
-#include "pull.h"
-
-int cmain(int argc,char *argv[])
-{
-  const char *desc[] = {
-    "This is an experimental release of GROMACS for accelerated",
-       "Molecular Dynamics simulations on GPU processors. Support is provided",
-       "by the OpenMM library (https://simtk.org/home/openmm).[PAR]",
-       "*Warning*[BR]",
-       "This release is targeted at developers and advanced users and",
-       "care should be taken before production use. The following should be",
-       "noted before using the program:[PAR]",
-       " * The current release runs only on modern nVidia GPU hardware with CUDA support.",
-       "Make sure that the necessary CUDA drivers and libraries for your operating system",
-       "are already installed. The CUDA SDK also should be installed in order to compile",
-       "the program from source (http://www.nvidia.com/object/cuda_home.html).[PAR]",
-       " * Multiple GPU cards are not supported.[PAR]",
-       " * Only a small subset of the GROMACS features and options are supported on the GPUs.",
-       "See below for a detailed list.[PAR]",
-       " * Consumer level GPU cards are known to often have problems with faulty memory.",
-       "It is recommended that a full memory check of the cards is done at least once",
-       "(for example, using the memtest=full option).",
-       "A partial memory check (for example, memtest=15) before and",
-       "after the simulation run would help spot",
-       "problems resulting from processor overheating.[PAR]",
-       " * The maximum size of the simulated systems depends on the available",
-       "GPU memory,for example, a GTX280 with 1GB memory has been tested with systems",
-       "of up to about 100,000 atoms.[PAR]",
-       " * In order to take a full advantage of the GPU platform features, many algorithms",
-       "have been implemented in a very different way than they are on the CPUs.",
-       "Therefore numercal correspondence between properties of the state of",
-       "simulated systems should not be expected. Moreover, the values will likely vary",
-       "when simulations are done on different GPU hardware.[PAR]",
-       " * Frequent retrieval of system state information such as",
-       "trajectory coordinates and energies can greatly influence the performance",
-       "of the program due to slow CPU<->GPU memory transfer speed.[PAR]",
-       " * MD algorithms are complex, and although the Gromacs code is highly tuned for them,",
-       "they often do not translate very well onto the streaming architetures.",
-       "Realistic expectations about the achievable speed-up from test with GTX280:",
-       "For small protein systems in implicit solvent using all-vs-all kernels the acceleration",
-       "can be as high as 20 times, but in most other setups involving cutoffs and PME the",
-       "acceleration is usually only ~4 times relative to a 3GHz CPU.[PAR]",
-       "Supported features:[PAR]",
-       " * Integrators: md/md-vv/md-vv-avek, sd/sd1 and bd.\n",
-       " * Long-range interactions (option coulombtype): Reaction-Field, Ewald, PME, and cut-off (for Implicit Solvent only)\n",
-       " * Temperature control: Supported only with the md/md-vv/md-vv-avek, sd/sd1 and bd integrators.\n",
-       " * Pressure control: Supported.\n",
-       " * Implicit solvent: Supported.\n",
-       "A detailed description can be found on the GROMACS website:\n",
-       "http://www.gromacs.org/gpu[PAR]",
-/* From the original mdrun documentaion */
-    "The [TT]mdrun[tt] program reads the run input file ([TT]-s[tt])",
-    "and distributes the topology over nodes if needed.",
-    "[TT]mdrun[tt] produces at least four output files.",
-    "A single log file ([TT]-g[tt]) is written, unless the option",
-    "[TT]-seppot[tt] is used, in which case each node writes a log file.",
-    "The trajectory file ([TT]-o[tt]), contains coordinates, velocities and",
-    "optionally forces.",
-    "The structure file ([TT]-c[tt]) contains the coordinates and",
-    "velocities of the last step.",
-    "The energy file ([TT]-e[tt]) contains energies, the temperature,",
-    "pressure, etc, a lot of these things are also printed in the log file.",
-    "Optionally coordinates can be written to a compressed trajectory file",
-    "([TT]-x[tt]).[PAR]",
-/* openmm specific information */
-       "Usage with OpenMM:[BR]",
-       "[TT]mdrun -device \"OpenMM:platform=Cuda,memtest=15,deviceid=0,force-device=no\"[tt][PAR]",
-       "Options:[PAR]",
-       "      [TT]platform[tt] = Cuda\t\t:\tThe only available value. OpenCL support will be available in future.\n",
-       "      [TT]memtest[tt] = 15\t\t:\tRun a partial, random GPU memory test for the given amount of seconds. A full test",
-       "(recommended!) can be run with \"memtest=full\". Memory testing can be disabled with \"memtest=off\".\n",
-       "      [TT]deviceid[tt] = 0\t\t:\tSpecify the target device when multiple cards are present.",
-       "Only one card can be used at any given time though.\n",
-       "      [TT]force-device[tt] = no\t\t:\tIf set to \"yes\" [TT]mdrun[tt]  will be forced to execute on",
-       "hardware that is not officially supported. GPU acceleration can also be achieved on older",
-       "but Cuda capable cards, although the simulation might be too slow, and the memory limits too strict.",
-  };
-  t_commrec    *cr;
-  t_filenm fnm[] = {
-    { efTPX, NULL,      NULL,       ffREAD },
-    { efTRN, "-o",      NULL,       ffWRITE },
-    { efXTC, "-x",      NULL,       ffOPTWR },
-    { efCPT, "-cpi",    NULL,       ffOPTRD },
-    { efCPT, "-cpo",    NULL,       ffOPTWR },
-    { efSTO, "-c",      "confout",  ffWRITE },
-    { efEDR, "-e",      "ener",     ffWRITE },
-    { efLOG, "-g",      "md",       ffWRITE },
-    { efXVG, "-dhdl",   "dhdl",     ffOPTWR },
-    { efXVG, "-field",  "field",    ffOPTWR },
-    { efXVG, "-table",  "table",    ffOPTRD },
-    { efXVG, "-tabletf", "tabletf",    ffOPTRD },
-    { efXVG, "-tablep", "tablep",   ffOPTRD },
-    { efXVG, "-tableb", "table",    ffOPTRD },
-    { efTRX, "-rerun",  "rerun",    ffOPTRD },
-    { efXVG, "-tpi",    "tpi",      ffOPTWR },
-    { efXVG, "-tpid",   "tpidist",  ffOPTWR },
-    { efEDI, "-ei",     "sam",      ffOPTRD },
-    { efXVG, "-eo",     "sam",      ffOPTWR },
-    { efGCT, "-j",      "wham",     ffOPTRD },
-    { efGCT, "-jo",     "bam",      ffOPTWR },
-    { efXVG, "-ffout",  "gct",      ffOPTWR },
-    { efXVG, "-devout", "deviatie", ffOPTWR },
-    { efXVG, "-runav",  "runaver",  ffOPTWR },
-    { efXVG, "-px",     "pullx",    ffOPTWR },
-    { efXVG, "-pf",     "pullf",    ffOPTWR },
-    { efXVG, "-ro",     "rotation", ffOPTWR },
-    { efLOG, "-ra",     "rotangles",ffOPTWR },
-    { efLOG, "-rs",     "rotslabs", ffOPTWR },
-    { efLOG, "-rt",     "rottorque",ffOPTWR },
-    { efMTX, "-mtx",    "nm",       ffOPTWR },
-    { efNDX, "-dn",     "dipole",   ffOPTWR },
-    { efRND, "-multidir",NULL,      ffOPTRDMULT},
-    { efDAT, "-membed", "membed",   ffOPTRD },
-    { efTOP, "-mp",     "membed",   ffOPTRD },
-    { efNDX, "-mn",     "membed",   ffOPTRD }
-  };
-#define NFILE asize(fnm)
-
-  /* Command line options ! */
-  gmx_bool bCart        = FALSE;
-  gmx_bool bPPPME       = FALSE;
-  gmx_bool bPartDec     = FALSE;
-  gmx_bool bDDBondCheck = TRUE;
-  gmx_bool bDDBondComm  = TRUE;
-  gmx_bool bTunePME     = TRUE;
-  gmx_bool bTestVerlet  = FALSE;
-  gmx_bool bVerbose     = FALSE;
-  gmx_bool bCompact     = TRUE;
-  gmx_bool bSepPot      = FALSE;
-  gmx_bool bRerunVSite  = FALSE;
-  gmx_bool bIonize      = FALSE;
-  gmx_bool bConfout     = TRUE;
-  gmx_bool bReproducible = FALSE;
-    
-  int  npme=-1;
-  int  nmultisim=0;
-  int  nstglobalcomm=-1;
-  int  repl_ex_nst=0;
-  int  repl_ex_seed=-1;
-  int  repl_ex_nex=0;
-  int  nstepout=100;
-  int  resetstep=-1;
-  int  nsteps=-2; /* the value -2 means that the mdp option will be used */
-  
-  rvec realddxyz={0,0,0};
-  const char *ddno_opt[ddnoNR+1] =
-    { NULL, "interleave", "pp_pme", "cartesian", NULL };
-  const char *dddlb_opt[] =
-    { NULL, "auto", "no", "yes", NULL };
-  const char   *thread_aff_opt[threadaffNR+1] =
-    { NULL, "auto", "no", "yes", NULL };
-  const char *nbpu_opt[] =
-    { NULL, "auto", "cpu", "gpu", "gpu_cpu", NULL };
-  real rdd=0.0,rconstr=0.0,dlb_scale=0.8,pforce=-1;
-  char *ddcsx=NULL,*ddcsy=NULL,*ddcsz=NULL;
-  real cpt_period=15.0,max_hours=-1;
-  gmx_bool bAppendFiles=TRUE;
-  gmx_bool bKeepAndNumCPT=FALSE;
-  gmx_bool bResetCountersHalfWay=FALSE;
-  output_env_t oenv=NULL;
-  const char *deviceOptions = "";
-
-  gmx_hw_opt_t hw_opt={0,0,0,0,TRUE,FALSE,0,NULL};
-
-  t_pargs pa[] = {
-
-    { "-pd",      FALSE, etBOOL,{&bPartDec},
-      "Use particle decompostion" },
-    { "-dd",      FALSE, etRVEC,{&realddxyz},
-      "Domain decomposition grid, 0 is optimize" },
-    { "-ddorder", FALSE, etENUM, {ddno_opt},
-      "DD node order" },
-    { "-npme",    FALSE, etINT, {&npme},
-      "Number of separate nodes to be used for PME, -1 is guess" },
-    { "-nt",      FALSE, etINT, {&hw_opt.nthreads_tot},
-      "Total number of threads to start (0 is guess)" },
-    { "-ntmpi",   FALSE, etINT, {&hw_opt.nthreads_tmpi},
-      "Number of thread-MPI threads to start (0 is guess)" },
-    { "-ntomp",   FALSE, etINT, {&hw_opt.nthreads_omp},
-      "Number of OpenMP threads per MPI process/thread to start (0 is guess)" },
-    { "-ntomp_pme", FALSE, etINT, {&hw_opt.nthreads_omp_pme},
-      "Number of OpenMP threads per MPI process/thread to start (0 is -ntomp)" },
-    { "-pin",     FALSE, etBOOL, {thread_aff_opt},
-      "Pin OpenMP threads to cores" },
-    { "-pinoffset", FALSE, etINT, {&hw_opt.core_pinning_offset},
-      "Core offset for pinning (for running multiple mdrun processes on a single physical node)" },
-    { "-pinstride", FALSE, etINT, {&hw_opt.core_pinning_stride},
-      "Pinning distance in logical cores for threads, use 0 to minimize the number of threads per physical core" },
-    { "-gpu_id",  FALSE, etSTR, {&hw_opt.gpu_id},
-      "List of GPU id's to use" },
-    { "-ddcheck", FALSE, etBOOL, {&bDDBondCheck},
-      "Check for all bonded interactions with DD" },
-    { "-ddbondcomm", FALSE, etBOOL, {&bDDBondComm},
-      "HIDDENUse special bonded atom communication when [TT]-rdd[tt] > cut-off" },
-    { "-rdd",     FALSE, etREAL, {&rdd},
-      "The maximum distance for bonded interactions with DD (nm), 0 is determine from initial coordinates" },
-    { "-rcon",    FALSE, etREAL, {&rconstr},
-      "Maximum distance for P-LINCS (nm), 0 is estimate" },
-    { "-dlb",     FALSE, etENUM, {dddlb_opt},
-      "Dynamic load balancing (with DD)" },
-    { "-dds",     FALSE, etREAL, {&dlb_scale},
-      "Minimum allowed dlb scaling of the DD cell size" },
-    { "-ddcsx",   FALSE, etSTR, {&ddcsx},
-      "HIDDENThe DD cell sizes in x" },
-    { "-ddcsy",   FALSE, etSTR, {&ddcsy},
-      "HIDDENThe DD cell sizes in y" },
-    { "-ddcsz",   FALSE, etSTR, {&ddcsz},
-      "HIDDENThe DD cell sizes in z" },
-    { "-gcom",    FALSE, etINT,{&nstglobalcomm},
-      "Global communication frequency" },
-    { "-nb",      FALSE, etENUM, {&nbpu_opt},
-      "Calculate non-bonded interactions on" },
-    { "-tunepme", FALSE, etBOOL, {&bTunePME},  
-      "Optimize PME load between PP/PME nodes or GPU/CPU" },
-    { "-testverlet", FALSE, etBOOL, {&bTestVerlet},
-      "Test the Verlet non-bonded scheme" },
-    { "-v",       FALSE, etBOOL,{&bVerbose},  
-      "Be loud and noisy" },
-    { "-compact", FALSE, etBOOL,{&bCompact},  
-      "Write a compact log file" },
-    { "-seppot",  FALSE, etBOOL, {&bSepPot},
-      "Write separate V and dVdl terms for each interaction type and node to the log file(s)" },
-    { "-pforce",  FALSE, etREAL, {&pforce},
-      "Print all forces larger than this (kJ/mol nm)" },
-    { "-reprod",  FALSE, etBOOL,{&bReproducible},  
-      "Try to avoid optimizations that affect binary reproducibility" },
-    { "-cpt",     FALSE, etREAL, {&cpt_period},
-      "Checkpoint interval (minutes)" },
-    { "-cpnum",   FALSE, etBOOL, {&bKeepAndNumCPT},
-      "Keep and number checkpoint files" },
-    { "-append",  FALSE, etBOOL, {&bAppendFiles},
-      "Append to previous output files when continuing from checkpoint instead of adding the simulation part number to all file names" },
-    { "-nsteps",  FALSE, etINT, {&nsteps},
-      "Run this number of steps, overrides .mdp file option" },
-    { "-maxh",   FALSE, etREAL, {&max_hours},
-      "Terminate after 0.99 times this time (hours)" },
-    { "-multi",   FALSE, etINT,{&nmultisim}, 
-      "Do multiple simulations in parallel" },
-    { "-replex",  FALSE, etINT, {&repl_ex_nst}, 
-      "Attempt replica exchange periodically with this period (steps)" },
-    { "-nex",  FALSE, etINT, {&repl_ex_nex},
-      "Number of random exchanges to carry out each exchange interval (N^3 is one suggestion).  -nex zero or not specified gives neighbor replica exchange." },
-    { "-reseed",  FALSE, etINT, {&repl_ex_seed}, 
-      "Seed for replica exchange, -1 is generate a seed" },
-    { "-rerunvsite", FALSE, etBOOL, {&bRerunVSite},
-      "HIDDENRecalculate virtual site coordinates with [TT]-rerun[tt]" },
-    { "-ionize",  FALSE, etBOOL,{&bIonize},
-      "Do a simulation including the effect of an X-Ray bombardment on your system" },
-    { "-confout", FALSE, etBOOL, {&bConfout},
-      "HIDDENWrite the last configuration with [TT]-c[tt] and force checkpointing at the last step" },
-    { "-stepout", FALSE, etINT, {&nstepout},
-      "HIDDENFrequency of writing the remaining runtime" },
-    { "-resetstep", FALSE, etINT, {&resetstep},
-      "HIDDENReset cycle counters after these many time steps" },
-    { "-resethway", FALSE, etBOOL, {&bResetCountersHalfWay},
-      "HIDDENReset the cycle counters after half the number of steps or halfway [TT]-maxh[tt]" },
-    { "-device",  FALSE, etSTR, {&deviceOptions},
-      "Device option string" }
-  };
-  gmx_edsam_t  ed;
-  unsigned long Flags, PCA_Flags;
-  ivec     ddxyz;
-  int      dd_node_order;
-  gmx_bool     bAddPart;
-  FILE     *fplog,*fptest;
-  int      sim_part,sim_part_fn;
-  const char *part_suffix=".part";
-  char     suffix[STRLEN];
-  int      rc;
-  char **multidir=NULL;
-
-
-  cr = init_par(&argc,&argv);
-
-  if (MASTER(cr))
-    CopyRight(stderr, argv[0]);
-
-  PCA_Flags = (PCA_CAN_SET_DEFFNM | (MASTER(cr) ? 0 : PCA_QUIET));
-  
-  /* Comment this in to do fexist calls only on master
-   * works not with rerun or tables at the moment
-   * also comment out the version of init_forcerec in md.c 
-   * with NULL instead of opt2fn
-   */
-  /*
-     if (!MASTER(cr))
-     {
-     PCA_Flags |= PCA_NOT_READ_NODE;
-     }
-     */
-
-  parse_common_args(&argc,argv,PCA_Flags, NFILE,fnm,asize(pa),pa,
-                    asize(desc),desc,0,NULL, &oenv);
-
-
-
-  /* we set these early because they might be used in init_multisystem() 
-     Note that there is the potential for npme>nnodes until the number of
-     threads is set later on, if there's thread parallelization. That shouldn't
-     lead to problems. */ 
-  dd_node_order = nenum(ddno_opt);
-  cr->npmenodes = npme;
-
-  /* now check the -multi and -multidir option */
-  if (opt2bSet("-multidir", NFILE, fnm))
-  {
-      int i;
-      if (nmultisim > 0)
-      {
-          gmx_fatal(FARGS, "mdrun -multi and -multidir options are mutually exclusive.");
-      }
-      nmultisim = opt2fns(&multidir, "-multidir", NFILE, fnm);
-  }
-
-
-  if (repl_ex_nst != 0 && nmultisim < 2)
-      gmx_fatal(FARGS,"Need at least two replicas for replica exchange (option -multi)");
-
-  if (repl_ex_nex < 0)
-      gmx_fatal(FARGS,"Replica exchange number of exchanges needs to be positive");
-
-  if (nmultisim > 1) {
-#ifndef GMX_THREAD_MPI
-    gmx_bool bParFn = (multidir == NULL);
-    init_multisystem(cr, nmultisim, multidir, NFILE, fnm, bParFn);
-#else
-    gmx_fatal(FARGS,"mdrun -multi is not supported with the thread library.Please compile GROMACS with MPI support");
-#endif
-  }
-
-  bAddPart = !bAppendFiles;
-
-  /* Check if there is ANY checkpoint file available */        
-  sim_part    = 1;
-  sim_part_fn = sim_part;
-  if (opt2bSet("-cpi",NFILE,fnm))
-  {
-      if (bSepPot && bAppendFiles)
-      {
-          gmx_fatal(FARGS,"Output file appending is not supported with -seppot");
-      }
-
-      bAppendFiles =
-                read_checkpoint_simulation_part(opt2fn_master("-cpi", NFILE,
-                                                              fnm,cr),
-                                                &sim_part_fn,NULL,cr,
-                                                bAppendFiles,NFILE,fnm,
-                                                part_suffix,&bAddPart);
-      if (sim_part_fn==0 && MASTER(cr))
-      {
-          fprintf(stdout,"No previous checkpoint file present, assuming this is a new run.\n");
-      }
-      else
-      {
-          sim_part = sim_part_fn + 1;
-      }
-
-      if (MULTISIM(cr) && MASTER(cr))
-      {
-          check_multi_int(stdout,cr->ms,sim_part,"simulation part", TRUE);
-      }
-  } 
-  else
-  {
-      bAppendFiles = FALSE;
-  }
-
-  if (!bAppendFiles)
-  {
-      sim_part_fn = sim_part;
-  }
-
-  if (bAddPart)
-  {
-      /* Rename all output files (except checkpoint files) */
-      /* create new part name first (zero-filled) */
-      sprintf(suffix,"%s%04d",part_suffix,sim_part_fn);
-
-      add_suffix_to_output_names(fnm,NFILE,suffix);
-      if (MASTER(cr))
-      {
-          fprintf(stdout,"Checkpoint file is from part %d, new output files will be suffixed '%s'.\n",sim_part-1,suffix);
-      }
-  }
-
-  Flags = opt2bSet("-rerun",NFILE,fnm) ? MD_RERUN : 0;
-  Flags = Flags | (bSepPot       ? MD_SEPPOT       : 0);
-  Flags = Flags | (bIonize       ? MD_IONIZE       : 0);
-  Flags = Flags | (bPartDec      ? MD_PARTDEC      : 0);
-  Flags = Flags | (bDDBondCheck  ? MD_DDBONDCHECK  : 0);
-  Flags = Flags | (bDDBondComm   ? MD_DDBONDCOMM   : 0);
-  Flags = Flags | (bTunePME      ? MD_TUNEPME      : 0);
-  Flags = Flags | (bTestVerlet   ? MD_TESTVERLET   : 0);
-  Flags = Flags | (bConfout      ? MD_CONFOUT      : 0);
-  Flags = Flags | (bRerunVSite   ? MD_RERUN_VSITE  : 0);
-  Flags = Flags | (bReproducible ? MD_REPRODUCIBLE : 0);
-  Flags = Flags | (bAppendFiles  ? MD_APPENDFILES  : 0); 
-  Flags = Flags | (opt2parg_bSet("-append", asize(pa),pa) ? MD_APPENDFILESSET : 0); 
-  Flags = Flags | (bKeepAndNumCPT ? MD_KEEPANDNUMCPT : 0); 
-  Flags = Flags | (sim_part>1    ? MD_STARTFROMCPT : 0); 
-  Flags = Flags | (bResetCountersHalfWay ? MD_RESETCOUNTERSHALFWAY : 0);
-
-
-  /* We postpone opening the log file if we are appending, so we can 
-     first truncate the old log file and append to the correct position 
-     there instead.  */
-  if ((MASTER(cr) || bSepPot) && !bAppendFiles) 
-  {
-      gmx_log_open(ftp2fn(efLOG,NFILE,fnm),cr,
-                   !bSepPot,Flags & MD_APPENDFILES,&fplog);
-      CopyRight(fplog,argv[0]);
-      please_cite(fplog,"Hess2008b");
-      please_cite(fplog,"Spoel2005a");
-      please_cite(fplog,"Lindahl2001a");
-      please_cite(fplog,"Berendsen95a");
-  }
-  else if (!MASTER(cr) && bSepPot)
-  {
-      gmx_log_open(ftp2fn(efLOG,NFILE,fnm),cr,!bSepPot,Flags,&fplog);
-  }
-  else
-  {
-      fplog = NULL;
-  }
-
-  ddxyz[XX] = (int)(realddxyz[XX] + 0.5);
-  ddxyz[YY] = (int)(realddxyz[YY] + 0.5);
-  ddxyz[ZZ] = (int)(realddxyz[ZZ] + 0.5);
-
-  rc = mdrunner(&hw_opt, fplog,cr,NFILE,fnm,oenv,bVerbose,bCompact,
-                nstglobalcomm, ddxyz,dd_node_order,rdd,rconstr,
-                dddlb_opt[0],dlb_scale,ddcsx,ddcsy,ddcsz,
-                nbpu_opt[0],
-                nsteps,nstepout,resetstep,
-                nmultisim,repl_ex_nst,repl_ex_nex,repl_ex_seed,
-                pforce, cpt_period,max_hours,deviceOptions,Flags);
-
-  gmx_finalize_par();
-
-  if (MULTIMASTER(cr)) {
-      gmx_thanx(stderr);
-  }
-
-  /* Log file has to be closed in mdrunner if we are appending to it 
-     (fplog not set here) */
-  if (MASTER(cr) && !bAppendFiles) 
-  {
-      gmx_log_close(fplog);
-  }
-
-  return rc;
-}
-
diff --git a/src/contrib/openmm_gpu_utils.cu b/src/contrib/openmm_gpu_utils.cu
deleted file mode 100644 (file)
index cf10dfb..0000000
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * This file is part of the GROMACS molecular simulation package.
- *
- * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
- * Copyright (c) 2001-2010,2012 The GROMACS development team,
- * check out http://www.gromacs.org for more information.
- * Copyright (c) 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.
- *
- * GROMACS is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1
- * of the License, or (at your option) any later version.
- *
- * GROMACS is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with GROMACS; if not, see
- * http://www.gnu.org/licenses, or write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
- *
- * If you want to redistribute modifications to GROMACS, 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 http://www.gromacs.org.
- *
- * To help us fund GROMACS development, we humbly ask that you cite
- * the research papers on the package. Check out http://www.gromacs.org.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-
-#include "smalloc.h"
-#include "string2.h"
-#include "types/hw_info.h"
-
-#include "openmm_gpu_utils.h"
-#include "../../src/gmxlib/cuda_tools/cudautils.cuh"
-
-// TODO put this list into an external file and include it so that the list is easily accessible
-/*! List of supported GPUs. */
-static const char * const SupportedGPUs[] = {
-    /* GT400 */
-    "Geforce GTX 480",
-    "Geforce GTX 470",
-    "Geforce GTX 465",
-    "Geforce GTX 460",
-
-    "Tesla C2070",
-    "Tesla C2050",
-    "Tesla S2070",
-    "Tesla S2050",
-    "Tesla M2070",
-    "Tesla M2050",
-
-    "Quadro 5000",
-    "Quadro 6000",
-
-    /* GT200 */
-    "Geforce GTX 295",
-    "Geforce GTX 285",
-    "Geforce GTX 280",
-    "Geforce GTX 275",
-    "Geforce GTX 260",
-    "GeForce GTS 250",
-    "GeForce GTS 150",
-
-    "GeForce GTX 285M",
-    "GeForce GTX 280M",
-
-    "Tesla S1070",
-    "Tesla C1060",
-    "Tesla M1060",
-
-    "Quadro FX 5800",
-    "Quadro FX 4800",
-    "Quadro CX",
-    "Quadro Plex 2200 D2",
-    "Quadro Plex 2200 S4",
-
-    /* G90 */
-    "GeForce 9800 G", /* GX2, GTX, GTX+, GT */
-    "GeForce 9800M GTX",
-
-    "Quadro FX 4700",
-    "Quadro Plex 2100 D4"
-};
-
-/*! Number of supported GPUs */
-#define NB_GPUS (sizeof(SupportedGPUs)/sizeof(SupportedGPUs[0]))
-
-FUNC_QUALIFIER
-gmx_bool is_gmx_openmm_supported_gpu(int dev_id, char *gpu_name) FUNC_TERM_INT
-
-/*! 
- * \brief Checks whether the GPU with the given name is supported in Gromacs-OpenMM.
- * 
- * \param[in] gpu_name  the name of the CUDA device
- * \returns             TRUE if the device is supported, otherwise FALSE
- */
-static bool is_gmx_openmm_supported_gpu_name(char *gpuName)
-{
-    size_t i;
-    for (i = 0; i < NB_GPUS; i++)
-    {
-        trim(gpuName);
-        if (gmx_strncasecmp(gpuName, SupportedGPUs[i], strlen(SupportedGPUs[i])) == 0)
-            return 1;
-    }
-    return 0;
-}
-
-/*! \brief Checks whether the GPU with the given device id is supported in Gromacs-OpenMM.
- *
- * \param[in] dev_id    the device id of the GPU or -1 if the device has already been selected
- * \param[out] gpu_name Set to contain the name of the CUDA device, if NULL passed, no device name is set. 
- * \returns             TRUE if the device is supported, otherwise FALSE
- * 
- */
-gmx_bool is_gmx_openmm_supported_gpu(int dev_id, char *gpu_name)
-{
-    cudaDeviceProp dev_prop;
-
-    if (debug) fprintf(debug, "Checking compatibility with device #%d, %s\n", dev_id, gpu_name);
-
-    if (do_sanity_checks(dev_id, &dev_prop) != 0)
-        return -1;
-
-    if (gpu_name != NULL)
-    { 
-        strcpy(gpu_name, dev_prop.name);
-    }
-    return is_gmx_openmm_supported_gpu_name(dev_prop.name);
-}
-
-
diff --git a/src/contrib/openmm_gpu_utils.h b/src/contrib/openmm_gpu_utils.h
deleted file mode 100644 (file)
index c5874d6..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * This file is part of the GROMACS molecular simulation package.
- *
- * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
- * Copyright (c) 2001-2010, The GROMACS development team,
- * check out http://www.gromacs.org for more information.
- * Copyright (c) 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.
- *
- * GROMACS is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1
- * of the License, or (at your option) any later version.
- *
- * GROMACS is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with GROMACS; if not, see
- * http://www.gnu.org/licenses, or write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
- *
- * If you want to redistribute modifications to GROMACS, 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 http://www.gromacs.org.
- *
- * To help us fund GROMACS development, we humbly ask that you cite
- * the research papers on the package. Check out http://www.gromacs.org.
- */
-
-#ifndef _OPENMM_GPU_UTILS_H_
-#define _OPENMM_GPU_UTILS_H_
-
-#include "types/simple.h"
-#include "types/hw_info.h"
-
-#define FUNC_TERM_INT {return -1;}
-#define FUNC_TERM_VOID {}
-#define FUNC_QUALIFIER static
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-FUNC_QUALIFIER
-gmx_bool is_gmx_openmm_supported_gpu(int dev_id, char *gpu_name) FUNC_TERM_INT
-
-#ifdef __cplusplus
-}
-#endif
-
-#undef FUNC_TERM_INT
-#undef FUNC_TERM_VOID
-#undef FUNC_QUALIFIER
-
-#endif /* _OPENMM_GPU_UTILS_H_ */
diff --git a/src/contrib/openmm_wrapper.cpp b/src/contrib/openmm_wrapper.cpp
deleted file mode 100644 (file)
index 3343aba..0000000
+++ /dev/null
@@ -1,1514 +0,0 @@
-/* -*- mode: c; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; c-file-style: "stroustrup"; -*-
- *
- * 
- *                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-2010, 2013, 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 Lesser 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
- * 
- * And Hey:
- * Gallium Rubidium Oxygen Manganese Argon Carbon Silicon
- */
-
-/*
- * Note, that parts of this source code originate from the Simtk release 
- * of OpenMM accelerated Gromacs, for more details see: 
- * https://simtk.org/project/xml/downloads.xml?group_id=161#package_id600
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <types/simple.h>
-#include <cmath>
-#include <set>
-#include <iostream>
-#include <sstream>
-#include <fstream>
-#include <map>
-#include <vector>
-#include <cctype>
-#include <algorithm>
-
-using namespace std;
-
-#include "OpenMM.h"
-
-#include "gmx_fatal.h"
-#include "typedefs.h"
-#include "mdrun.h"
-#include "physics.h"
-#include "string2.h"
-#include "openmm_gpu_utils.h"
-#include "gpu_utils.h"
-#include "mtop_util.h"
-
-#include "openmm_wrapper.h"
-
-using namespace OpenMM;
-
-/*! \cond */
-#define MEM_ERR_MSG(str) \
-    "The %s-simulation GPU memory test detected errors. As memory errors would cause incorrect " \
-    "simulation results, gromacs has aborted execution.\n Make sure that your GPU's memory is not " \
-    "overclocked and that the device is properly cooled.\n", (str)
-/*! \endcond */
-
-#define COMBRULE_CHK_TOL            1e-6
-#define COMBRULE_SIGMA(sig1, sig2)  (((sig1) + (sig2))/2)
-#define COMBRULE_EPS(eps1, eps2)    (sqrt((eps1) * (eps2)))
-
-/*! 
- * \brief Convert string to integer type.
- * \param[in]  s    String to convert from.
- * \param[in]  f    Basefield format flag that takes any of the following I/O
- *                  manipulators: dec, hex, oct.
- * \param[out] t    Destination variable to convert to.
- */
-template <class T>
-static gmx_bool from_string(T& t, const string& s, ios_base& (*f)(ios_base&))
-{
-    istringstream iss(s);
-    return !(iss >> f >> t).fail();
-}
-
-/*!
- * \brief Split string around a given delimiter.
- * \param[in] s      String to split.
- * \param[in] delim  Delimiter character.
- * \returns          Vector of strings found in \p s.
- */
-static vector<string> split(const string &s, char delim)
-{
-    vector<string> elems;
-    stringstream ss(s);
-    string item;
-    while (getline(ss, item, delim))
-    {
-        if (item.length() != 0)
-            elems.push_back(item);
-    }
-    return elems;
-}
-
-/*!
- * \brief Split a string of the form "option=value" into "option" and "value" strings.
- * This string corresponds to one option and the associated value from the option list 
- * in the mdrun -device argument.
- *
- * \param[in]  s    A string containing an "option=value" pair that needs to be split up.
- * \param[out] opt  The name of the option.
- * \param[out] val  Value of the option. 
- */
-static void splitOptionValue(const string &s, string &opt, string &val)
-{
-    size_t eqPos = s.find('=');
-    if (eqPos != string::npos)
-    {
-        opt = s.substr(0, eqPos);
-        if (eqPos != s.length())  val = s.substr(eqPos+1);
-    }
-}
-
-/*!
- * \brief Compare two strings ignoring case.
- * This function is in fact a wrapper around the gromacs function gmx_strncasecmp().
- * \param[in] s1 String. 
- * \param[in] s2 String.
- * \returns      Similarly to the C function strncasecmp(), the return value is an  
-                 integer less than, equal to, or greater than 0 if \p s1 less than, 
-                 identical to, or greater than \p s2.
- */
-static gmx_bool isStringEqNCase(const string& s1, const string& s2)
-{
-    return (gmx_strncasecmp(s1.c_str(), s2.c_str(), max(s1.length(), s2.length())) == 0);
-}
-
-/*!
- * \brief Convert string to upper case.
- *
- * \param[in]  s    String to convert to uppercase.
- * \returns         The given string converted to uppercase.
- */
-static string toUpper(const string &s)
-{
-    string stmp(s);
-    std::transform(stmp.begin(), stmp.end(), stmp.begin(), static_cast < int(*)(int) > (toupper));
-    return stmp;
-}
-
-/*! 
-  \name Sizes of constant device option arrays GmxOpenMMPlatformOptions#platforms, 
-  GmxOpenMMPlatformOptions#memtests, GmxOpenMMPlatformOptions#deviceid, 
-  GmxOpenMMPlatformOptions#force_dev.  */
-/* {@ */
-#define SIZEOF_PLATFORMS    2  // 2
-#define SIZEOF_MEMTESTS     3 
-#define SIZEOF_DEVICEIDS    1 
-#define SIZEOF_FORCE_DEV    2 
-
-#define SIZEOF_CHECK_COMBRULE 2
-/* @} */
-
-/*! Possible platform options in the mdrun -device option. */
-static const char *devOptStrings[] = { "platform", "deviceid", "memtest", "force-device", "check-combrule" }; 
-
-/*! Enumerated platform options in the mdrun -device option. */
-enum devOpt
-{
-    PLATFORM     = 0,
-    DEVICEID     = 1,
-    MEMTEST      = 2,
-    FORCE_DEVICE = 3
-};
-
-/*!
- * \brief Class to extract and manage the platform options in the mdrun -device option.
- * 
- */
-class GmxOpenMMPlatformOptions
-{
-public:
-    GmxOpenMMPlatformOptions(const char *opt);
-    ~GmxOpenMMPlatformOptions() { options.clear(); }
-    string getOptionValue(const string &opt);
-    void remOption(const string &opt);
-    void print();
-private:
-    void setOption(const string &opt, const string &val);
-
-    map<string, string> options; /*!< Data structure to store the option (name, value) pairs. */
-
-    static const char * const platforms[SIZEOF_PLATFORMS];  /*!< Available OpenMM platforms; size #SIZEOF_PLATFORMS */
-    static const char * const memtests[SIZEOF_MEMTESTS];    /*!< Available types of memory tests, also valid 
-                                                                 any positive integer >=15; size #SIZEOF_MEMTESTS */
-    static const char * const deviceid[SIZEOF_DEVICEIDS];   /*!< Possible values for deviceid option; 
-                                                                 also valid any positive integer; size #SIZEOF_DEVICEIDS */
-    static const char * const force_dev[SIZEOF_FORCE_DEV];  /*!< Possible values for for force-device option; 
-                                                                 size #SIZEOF_FORCE_DEV */
-    static const char * const check_combrule[SIZEOF_CHECK_COMBRULE]; /* XXX temporary debug feature to 
-                                                                      turn off combination rule check */
-};
-
-const char * const GmxOpenMMPlatformOptions::platforms[SIZEOF_PLATFORMS]
-                    = {"CUDA", "Reference"};
-                    //= { "Reference", "CUDA" /*,"OpenCL"*/ };
-const char * const GmxOpenMMPlatformOptions::memtests[SIZEOF_MEMTESTS]
-                    = { "15", "full", "off" };
-const char * const GmxOpenMMPlatformOptions::deviceid[SIZEOF_DEVICEIDS]
-                    = { "0" };
-const char * const GmxOpenMMPlatformOptions::force_dev[SIZEOF_FORCE_DEV]
-                    = { "no", "yes" };
-const char * const GmxOpenMMPlatformOptions::check_combrule[SIZEOF_CHECK_COMBRULE] 
-                    = { "yes", "no" };
-
-/*!
- * \brief Contructor.
- * Takes the option list, parses it, checks the options and their values for validity.
- * When certain options are not provided by the user, as default value the first item  
- * of the respective constant array is taken (GmxOpenMMPlatformOptions#platforms, 
- * GmxOpenMMPlatformOptions#memtests, GmxOpenMMPlatformOptions#deviceid, 
- * GmxOpenMMPlatformOptions#force_dev). 
- * \param[in] optionString  Option list part of the mdrun -device parameter.
- */
-GmxOpenMMPlatformOptions::GmxOpenMMPlatformOptions(const char *optionString)
-{
-    // set default values
-    setOption("platform",       platforms[0]);
-    setOption("memtest",        memtests[0]);
-    setOption("deviceid",       deviceid[0]);
-    setOption("force-device",   force_dev[0]);
-    setOption("check-combrule", check_combrule[0]);
-
-    string opt(optionString);
-
-    // remove all whitespaces
-    opt.erase(remove_if(opt.begin(), opt.end(), ::isspace), opt.end());
-    // tokenize around ","-s
-    vector<string> tokens = split(opt, ',');
-
-    for (vector<string>::iterator it = tokens.begin(); it != tokens.end(); ++it)
-    {
-        string opt = "", val = "";
-        splitOptionValue(*it, opt, val);
-
-        if (isStringEqNCase(opt, "platform"))
-        {
-            /* no check, this will fail if platform does not exist when we try to set it */
-            setOption(opt, val);
-            continue;
-        }
-
-        if (isStringEqNCase(opt, "memtest"))
-        {
-            /* the value has to be an integer >15(s) or "full" OR "off" */
-            if (!isStringEqNCase(val, "full") && !isStringEqNCase(val, "off")) 
-            {
-                int secs;
-                if (!from_string<int>(secs, val, std::dec))
-                {
-                    gmx_fatal(FARGS, "Invalid value for option memtest option: \"%s\"!", val.c_str());
-                }
-                if (secs < 15)
-                {
-                    gmx_fatal(FARGS, "Incorrect value for memtest option (%d). "
-                            "Memtest needs to run for at least 15s!", secs);
-                }
-            }
-            setOption(opt, val);
-            continue;
-        }
-
-        if (isStringEqNCase(opt, "deviceid"))
-        {
-            int id;
-            if (!from_string<int>(id, val, std::dec) )
-            {
-                gmx_fatal(FARGS, "Invalid device id: \"%s\"!", val.c_str());
-            }
-            setOption(opt, val);
-            continue;
-        }
-
-        if (isStringEqNCase(opt, "force-device"))
-        {
-            /* */
-            if (!isStringEqNCase(val, "yes") && !isStringEqNCase(val, "no"))
-            {
-                gmx_fatal(FARGS, "Invalid OpenMM force option: \"%s\"!", val.c_str());
-            }
-            setOption(opt, val);
-            continue;
-        }
-
-        if (isStringEqNCase(opt, "check-combrule"))
-        {
-            /* */
-            if (!isStringEqNCase(val, "yes") && !isStringEqNCase(val, "no"))
-            {
-                gmx_fatal(FARGS, "Invalid OpenMM force option: \"%s\"!", val.c_str());
-            }
-            setOption(opt, val);
-            continue;
-        }
-
-
-        // if we got till here something went wrong
-        gmx_fatal(FARGS, "Invalid OpenMM platform option: \"%s\"!", (*it).c_str());
-    }
-}
-
-
-/*!
- * \brief Getter function.
- * \param[in] opt   Name of the option.
- * \returns         Returns the value associated to an option. 
- */
-string GmxOpenMMPlatformOptions::getOptionValue(const string &opt)
-{
-       map<string, string> :: const_iterator it = options.find(toUpper(opt));
-       if (it != options.end())
-    {
-               return it->second;
-    }
-    else
-    {
-        return NULL;
-    }
-}
-
-/*!
- * \brief Setter function - private, only used from contructor.
- * \param[in] opt   Name of the option.
- * \param[in] val   Value for the option. 
- */
-void GmxOpenMMPlatformOptions::setOption(const string &opt, const string &val)
-{
-    options[toUpper(opt)] = val;
-}
-
-/*!
- * \brief Removes an option with its value from the map structure. If the option 
- * does not exist, returns without any action.
- * \param[in] opt   Name of the option.
- */
-void GmxOpenMMPlatformOptions::remOption(const string &opt) 
-{ 
-    options.erase(toUpper(opt)); 
-}
-
-/*!
- * \brief Print option-value pairs to a file (debugging function). 
- */
-void GmxOpenMMPlatformOptions::print()
-{
-    cout << ">> Platform options: " << endl 
-         << ">> platform     = " << getOptionValue("platform") << endl
-         << ">> deviceID     = " << getOptionValue("deviceid") << endl
-         << ">> memtest      = " << getOptionValue("memtest") << endl
-         << ">> force-device = " << getOptionValue("force-device") << endl;
-}
-
-/*!
- * \brief Container for OpenMM related data structures that represent the bridge 
- *        between the Gromacs data-structures and the OpenMM library and is but it's 
- *        only passed through the API functions as void to disable direct access. 
- */
-class OpenMMData
-{
-public:
-    System* system;      /*! The system to simulate. */
-    Context* context;   /*! The OpenMM context in which the simulation is carried out. */
-    Integrator* integrator; /*! The integrator used in the simulation. */
-    gmx_bool removeCM;          /*! If \true remove venter of motion, false otherwise. */
-    GmxOpenMMPlatformOptions *platformOpt; /*! Platform options. */
-};
-
-/*!
- *  \brief Runs memtest on the GPU that has alreaby been initialized by OpenMM.
- *  \param[in] fplog    Pointer to gromacs log file.
- *  \param[in] devId    Device id of the GPU to run the test on. 
-                        Note: as OpenMM previously creates the context,for now this is always -1.
- *  \param[in] pre_post Contains either "Pre" or "Post" just to be able to differentiate in 
- *                      stdout messages/log between memtest carried out before and after simulation.
- *  \param[in] opt      Pointer to platform options object.
- */
-static void runMemtest(FILE* fplog, int devId, const char* pre_post, GmxOpenMMPlatformOptions *opt)
-{
-    char        strout_buf[STRLEN];
-    int         which_test;
-    int         res = 0;
-    string      s = opt->getOptionValue("memtest");
-    const char  *test_type = s.c_str();
-
-    if (!gmx_strcasecmp(test_type, "off"))
-    {
-        which_test = 0;
-    }
-    else
-    {
-        if (!gmx_strcasecmp(test_type, "full"))
-        {
-            which_test = 2;
-        }
-        else
-        {
-            from_string<int>(which_test, test_type, std::dec);
-        }
-    }
-
-    if (which_test < 0) 
-    {
-        gmx_fatal(FARGS, "Amount of seconds for memetest is negative (%d). ", which_test);
-    }
-
-    switch (which_test)
-    {
-        case 0: /* no memtest */
-            sprintf(strout_buf, "%s-simulation GPU memtest skipped. Note, that faulty memory can cause "
-                "incorrect results!", pre_post);
-            fprintf(fplog, "%s\n", strout_buf);
-            gmx_warning(strout_buf);
-            break; /* case 0 */
-
-        case 1: /* quick memtest */
-            fprintf(fplog,  "%s-simulation %s GPU memtest in progress...\n", pre_post, test_type);
-            fprintf(stdout, "\n%s-simulation %s GPU memtest in progress...", pre_post, test_type);
-            fflush(fplog);
-            fflush(stdout);
-            res = do_quick_memtest(devId);
-            break; /* case 1 */
-
-        case 2: /* full memtest */
-            fprintf(fplog,  "%s-simulation %s memtest in progress...\n", pre_post, test_type);
-            fprintf(stdout, "\n%s-simulation %s memtest in progress...", pre_post, test_type);
-            fflush(fplog);
-            fflush(stdout);
-            res = do_full_memtest(devId);
-            break; /* case 2 */
-
-        default: /* timed memtest */
-            fprintf(fplog,  "%s-simulation ~%ds memtest in progress...\n", pre_post, which_test);
-            fprintf(stdout, "\n%s-simulation ~%ds memtest in progress...", pre_post, which_test);
-            fflush(fplog);
-            fflush(stdout);
-            res = do_timed_memtest(devId, which_test);
-        }
-
-        if (which_test != 0)
-        {
-            if (res != 0)
-            {
-                gmx_fatal(FARGS, MEM_ERR_MSG(pre_post));
-            }
-            else
-            {
-                fprintf(fplog,  "Memory test completed without errors.\n");
-                fflush(fplog);
-                fprintf(stdout, "done, no errors detected\n");
-                fflush(stdout);           
-            }
-        }
-}
-
-/*!
- * \brief Convert Lennard-Jones parameters c12 and c6 to sigma and epsilon.
- * 
- * \param[in] c12
- * \param[in] c6
- * \param[out] sigma 
- * \param[out] epsilon
- */
-static void convert_c_12_6(double c12, double c6, double *sigma, double *epsilon)
-{
-    if (c12 == 0 && c6 == 0)
-    {
-        *epsilon    = 0.0;        
-        *sigma      = 1.0;
-    }
-    else if (c12 > 0 && c6 > 0)
-    {
-        *epsilon    = (c6*c6)/(4.0*c12);
-        *sigma      = pow(c12/c6, 1.0/6.0);
-    }
-    else 
-    {
-        gmx_fatal(FARGS,"OpenMM only supports c6 > 0 and c12 > 0 or c6 = c12 = 0.");
-    } 
-}
-
-/*!
- * \brief Does gromacs option checking.
- *
- * Checks the gromacs mdp options for features unsupported in OpenMM, case in which 
- * interrupts the execution. It also warns the user about pecularities of OpenMM 
- * implementations.
- * \param[in] fplog         Gromacs log file pointer.
- * \param[in] ir            Gromacs input parameters, see ::t_inputrec
- * \param[in] top           Gromacs node local topology, \see gmx_localtop_t
- * \param[in] state         Gromacs state structure \see ::t_state
- * \param[in] mdatoms       Gromacs atom parameters, \see ::t_mdatoms
- * \param[in] fr            \see ::t_forcerec
- * \param[in] state         Gromacs systems state, \see ::t_state
- */
-static void checkGmxOptions(FILE* fplog, GmxOpenMMPlatformOptions *opt,
-                            t_inputrec *ir, gmx_localtop_t *top,
-                            t_forcerec *fr, t_state *state)
-{
-    char    warn_buf[STRLEN];
-    int     i, j, natoms;
-    double  c6, c12;
-    double  sigma_ij=0, sigma_ji=0, sigma_ii=0, sigma_jj=0, sigma_comb;
-    double  eps_ij=0, eps_ji=0, eps_ii=0, eps_jj=0, eps_comb;
-
-    /* Abort if unsupported critical options are present */
-
-    /* Integrator */
-    if (ir->eI ==  eiMD)
-    {
-        gmx_warning( "OpenMM does not support leap-frog, will use velocity-verlet integrator.");
-    }
-
-    if (    (ir->eI !=  eiMD)   &&
-            (ir->eI !=  eiVV)   &&
-            (ir->eI !=  eiVVAK) &&
-            (ir->eI !=  eiSD1)  &&
-            (ir->eI !=  eiSD2)  &&
-            (ir->eI !=  eiBD) )
-    {
-        gmx_fatal(FARGS, "OpenMM supports only the following integrators: md/md-vv/md-vv-avek, sd/sd1, and bd.");
-    }
-
-    /* Electroctstics */
-    if (   !(ir->coulombtype == eelPME   ||
-             EEL_RF(ir->coulombtype)     ||
-             ir->coulombtype == eelRF    ||
-             ir->coulombtype == eelEWALD ||
-             // no-cutoff
-             (ir->coulombtype == eelCUT && ir->rcoulomb == 0 &&  ir->rvdw == 0) ||
-             // we could have cut-off combined with GBSA (openmm will use RF)
-             ir->implicit_solvent == eisGBSA)   )
-    {
-        gmx_fatal(FARGS,"OpenMM supports only the following methods for electrostatics: "
-                "NoCutoff (i.e. rcoulomb = rvdw = 0 ),Reaction-Field, Ewald or PME.");
-    }
-
-    if (EEL_RF(ir->coulombtype) && ir->epsilon_rf != 0)
-    {
-        // openmm has epsilon_rf=inf hard-coded
-        gmx_warning("OpenMM will use a Reaction-Field epsilon of infinity instead of %g.",ir->epsilon_rf);
-    }
-
-    if (ir->etc != etcNO &&
-        ir->eI  != eiSD1 &&
-        ir->eI  != eiSD2 &&
-        ir->eI  != eiBD )
-    {
-        gmx_warning("OpenMM supports only Andersen thermostat with the md/md-vv/md-vv-avek integrators.");
-    }
-
-    if (ir->implicit_solvent == eisGBSA &&
-        ir->gb_algorithm != egbOBC  )
-    {
-        gmx_warning("OpenMM does not support the specified algorithm for Generalized Born, will use OBC instead.");
-    }
-
-    if (ir->opts.ngtc > 1)
-        gmx_fatal(FARGS,"OpenMM does not support multiple temperature coupling groups.");
-
-    if (ir->epc != epcNO)
-        gmx_warning("OpenMM supports only Monte Carlo barostat for pressure coupling.");
-
-    if (ir->opts.annealing[0])
-        gmx_fatal(FARGS,"OpenMM does not support simulated annealing.");
-    
-    if (top->idef.il[F_CONSTR].nr > 0 && ir->eConstrAlg != econtSHAKE)
-        gmx_warning("OpenMM provides contraints as a combination "
-                    "of SHAKE, SETTLE and CCMA. Accuracy is based on the SHAKE tolerance set "
-                    "by the \"shake_tol\" option.");
-
-    if (ir->nwall != 0)
-        gmx_fatal(FARGS,"OpenMM does not support walls.");
-
-    if (ir->ePull != epullNO)
-        gmx_fatal(FARGS,"OpenMM does not support pulling.");
-
-    /* check for interaction types */
-    for (i = 0; i < F_EPOT; i++)
-    {
-        if (!(i == F_CONSTR ||
-            i == F_SETTLE   ||
-            i == F_BONDS    ||            
-            i == F_HARMONIC ||
-            i == F_UREY_BRADLEY ||
-            i == F_ANGLES   ||
-            i == F_PDIHS    ||
-            i == F_RBDIHS   ||
-            i == F_PIDIHS   ||
-            i == F_IDIHS    ||
-            i == F_LJ14     ||
-            i == F_GB12     || /* The GB parameters are hardcoded both in */
-            i == F_GB13     || /* Gromacs and OpenMM */
-            i == F_GB14   ) &&
-            top->idef.il[i].nr > 0)
-        {
-            gmx_fatal(FARGS, "OpenMM does not support (some) of the provided interaction " 
-                    "type(s) (%s) ", interaction_function[i].longname);
-        }
-    }
-
-    if (ir->efep != efepNO)
-        gmx_fatal(FARGS,"OpenMM does not support free energy calculations.");
-
-    if (ir->opts.ngacc > 1)
-        gmx_fatal(FARGS,"OpenMM does not support non-equilibrium MD (accelerated groups).");
-
-    if (IR_ELEC_FIELD(*ir))
-        gmx_fatal(FARGS,"OpenMM does not support electric fields.");
-
-    if (ir->bQMMM)
-        gmx_fatal(FARGS,"OpenMM does not support QMMM calculations.");
-
-    if (ir->rcoulomb != ir->rvdw)
-        gmx_fatal(FARGS,"OpenMM uses a single cutoff for both Coulomb "
-                  "and VdW interactions. Please set rcoulomb equal to rvdw.");
-    
-    if (EEL_FULL(ir->coulombtype))
-    {
-        if (ir->ewald_geometry == eewg3DC)
-            gmx_fatal(FARGS,"OpenMM supports only Ewald 3D geometry.");
-        if (ir->epsilon_surface != 0)
-            gmx_fatal(FARGS,"OpenMM does not support dipole correction in Ewald summation.");
-    }
-
-    if (TRICLINIC(state->box))        
-    {
-        gmx_fatal(FARGS,"OpenMM does not support triclinic unit cells.");
-    }
-
-    /* XXX this is just debugging code to disable the combination rule check */
-    if ( isStringEqNCase(opt->getOptionValue("check-combrule"), "yes") )
-    {
-    /* As OpenMM by default uses hardcoded combination rules 
-       sigma_ij = (sigma_i + sigma_j)/2, eps_ij = sqrt(eps_i * eps_j)
-       we need to check whether the force field params obey this 
-       and if not, we can't use this force field so we exit 
-       grace-fatal-fully. */
-    real *nbfp = fr->nbfp;
-    natoms = fr->ntype;
-    if (debug) 
-    {   
-        fprintf(debug, ">> Atom parameters: <<\n%10s%5s %5s %5s %5s COMB\n", 
-                "", "i-j", "j-i", "i-i", "j-j");
-    }
-    /* loop over all i-j atom pairs and verify if 
-       sigma_ij = sigma_ji = sigma_comb and eps_ij = eps_ji = eps_comb */
-    for (i = 0; i < natoms; i++)
-    {
-        /* i-i */
-        /* nbfp now includes the 6.0/12.0 prefactors to save flops in kernels */
-        c12 = C12(nbfp, natoms, i, i)/12.0;
-        c6  = C6(nbfp,  natoms, i, i)/6.0;
-        convert_c_12_6(c12, c6, &sigma_ii, &eps_ii);
-
-        for (j = 0; j < i; j++)
-        {
-            /* i-j */
-            c12 = C12(nbfp, natoms, i, j)/12.0;
-            c6  = C6(nbfp,  natoms, i, j)/6.0;
-            convert_c_12_6(c12, c6, &sigma_ij, &eps_ij);
-            /* j-i */
-            c12 = C12(nbfp, natoms, j, i)/12.0;
-            c6  = C6(nbfp,  natoms, j, i)/6.0;
-            convert_c_12_6(c12, c6, &sigma_ji, &eps_ji);
-            /* j-j */
-            c12 = C12(nbfp, natoms, j, j)/12.0;
-            c6  = C6(nbfp,  natoms, j, j)/6.0;
-            convert_c_12_6(c12, c6, &sigma_jj, &eps_jj);
-            /* OpenMM hardcoded combination rules */
-            sigma_comb = COMBRULE_SIGMA(sigma_ii, sigma_jj);
-            eps_comb = COMBRULE_EPS(eps_ii, eps_jj);
-  
-            if (debug)
-            {
-                fprintf(debug, "i=%-3d j=%-3d", i, j);
-                fprintf(debug, "%-11s", "sigma");
-                fprintf(debug, "%5.3f %5.3f %5.3f %5.3f %5.3f\n",  
-                        sigma_ij, sigma_ji, sigma_ii, sigma_jj, sigma_comb);
-                fprintf(debug, "%11s%-11s", "", "epsilon");
-                fprintf(debug, "%5.3f %5.3f %5.3f %5.3f %5.3f\n", 
-                        eps_ij, eps_ji, eps_ii, eps_jj, eps_comb);
-            }
-
-            /* check the values against the rule used by omm */
-            if((fabs(eps_ij) > COMBRULE_CHK_TOL && 
-                fabs(eps_ji) > COMBRULE_CHK_TOL) &&
-               (fabs(sigma_comb - sigma_ij) > COMBRULE_CHK_TOL ||
-               fabs(sigma_comb - sigma_ji) > COMBRULE_CHK_TOL ||
-               fabs(eps_comb - eps_ij) > COMBRULE_CHK_TOL ||
-               fabs(eps_comb - eps_ji) > COMBRULE_CHK_TOL ))
-            {
-                gmx_fatal(FARGS,
-                        "The combination rules of the used force-field do not "
-                        "match the one supported by OpenMM:  "
-                        "sigma_ij = (sigma_i + sigma_j)/2, eps_ij = sqrt(eps_i * eps_j). "
-                        "Switch to a force-field that uses these rules in order to "
-                        "simulate this system using OpenMM.\n");                        
-            }
-        }
-    }
-    if (debug) { fprintf(debug, ">><<\n\n"); }
-
-    /* if we got here, log that everything is fine */
-    if (debug)
-    {
-        fprintf(debug, ">> The combination rule of the used force matches the one used by OpenMM.\n");
-    }
-    fprintf(fplog, "The combination rule of the used force field matches the one used by OpenMM.\n");   
-
-    } /* if (are we checking the combination rules) ... */
-}
-
-
-/*!
- * \brief Initialize OpenMM, run sanity/consistency checks, and return a pointer to 
- * the OpenMMData.
- * 
- * Various gromacs data structures are passed that contain the parameters, state and 
- * other porperties of the system to simulate. These serve as input for initializing 
- * OpenMM. Besides, a set of misc action are taken:
- *  - OpenMM plugins are loaded;
- *  - platform options in \p platformOptStr are parsed and checked; 
- *  - Gromacs parameters are checked for OpenMM support and consistency;
- *  - after the OpenMM is initialized memtest executed in the same GPU context.
- * 
- * \param[in] fplog             Gromacs log file handler.
- * \param[in] platformOptStr    Platform option string. 
- * \param[in] ir                The Gromacs input parameters, see ::t_inputrec
- * \param[in] top_global        Gromacs system toppology, \see ::gmx_mtop_t
- * \param[in] top               Gromacs node local topology, \see gmx_localtop_t
- * \param[in] mdatoms           Gromacs atom parameters, \see ::t_mdatoms
- * \param[in] fr                \see ::t_forcerec
- * \param[in] state             Gromacs systems state, \see ::t_state
- * \returns                     Pointer to a 
- * 
- */
-void* openmm_init(FILE *fplog, const char *platformOptStr,
-                  t_inputrec *ir,
-                  gmx_mtop_t *top_global, gmx_localtop_t *top,
-                  t_mdatoms *mdatoms, t_forcerec *fr, t_state *state)
-{
-
-    char warn_buf[STRLEN];
-    static gmx_bool hasLoadedPlugins = false;
-    string usedPluginDir;
-    int devId;
-
-    try
-    {
-        if (!hasLoadedPlugins)
-        {
-            vector<string> loadedPlugins;
-            /*  Look for OpenMM plugins at various locations (listed in order of priority):
-                - on the path in OPENMM_PLUGIN_DIR environment variable if this is specified
-                - on the path in the OPENMM_PLUGIN_DIR macro that is set by the build script
-                - at the default location assumed by OpenMM
-            */
-            /* env var */
-            char *pluginDir = getenv("OPENMM_PLUGIN_DIR");
-            trim(pluginDir);
-            /* no env var or empty */
-            if (pluginDir != NULL && *pluginDir != '\0')
-            {
-                loadedPlugins = Platform::loadPluginsFromDirectory(pluginDir);
-                if (!loadedPlugins.empty())
-                {
-                    hasLoadedPlugins = true;
-                    usedPluginDir = pluginDir;
-                }
-                else
-                {
-                    gmx_fatal(FARGS, "The directory provided in the OPENMM_PLUGIN_DIR environment variable "
-                              "(%s) does not contain valid OpenMM plugins. Check your OpenMM installation!", 
-                              pluginDir);
-                }
-            }
-
-            /* macro set at build time  */
-#ifdef OPENMM_PLUGIN_DIR
-            if (!hasLoadedPlugins)
-            {
-                loadedPlugins = Platform::loadPluginsFromDirectory(OPENMM_PLUGIN_DIR);
-                if (!loadedPlugins.empty())
-                {
-                    hasLoadedPlugins = true;
-                    usedPluginDir = OPENMM_PLUGIN_DIR;
-                }
-            }
-#endif
-            /* default loocation */
-            if (!hasLoadedPlugins)
-            {
-                loadedPlugins = Platform::loadPluginsFromDirectory(Platform::getDefaultPluginsDirectory());
-                if (!loadedPlugins.empty())
-                {
-                    hasLoadedPlugins = true;
-                    usedPluginDir = Platform::getDefaultPluginsDirectory();
-                }
-            }
-
-            /* if there are still no plugins loaded there won't be any */
-            if (!hasLoadedPlugins)
-            {
-                gmx_fatal(FARGS, "No OpenMM plugins were found! You can provide the"
-                          " plugin directory in the OPENMM_PLUGIN_DIR environment variable.", pluginDir);
-            }
-
-            fprintf(fplog, "\nOpenMM plugins loaded from directory %s:\t", usedPluginDir.c_str());
-            for (int i = 0; i < (int)loadedPlugins.size(); i++)
-            {
-                fprintf(fplog, "%s, ", loadedPlugins[i].c_str());
-            }
-            fprintf(fplog, "\n");
-        }
-
-        /* parse option string */
-        GmxOpenMMPlatformOptions *opt = new GmxOpenMMPlatformOptions(platformOptStr);
-        devId = atoi(opt->getOptionValue("deviceid").c_str());
-
-        if (debug)
-        {
-            opt->print();
-        }
-
-        /* check wheter Gromacs options compatibility with OpenMM */
-        checkGmxOptions(fplog, opt, ir, top, fr, state);
-
-        /* Create the system. */
-        const t_idef& idef = top->idef;
-        const int numAtoms = top_global->natoms;
-        const int numConstraints = idef.il[F_CONSTR].nr/3;
-        const int numSettle = idef.il[F_SETTLE].nr/2;
-        const int numBonds = idef.il[F_BONDS].nr/3;
-        const int numHarmonic = idef.il[F_HARMONIC].nr/3;
-        const int numUB = idef.il[F_UREY_BRADLEY].nr/4;
-        const int numAngles = idef.il[F_ANGLES].nr/4;
-        const int numPeriodic = idef.il[F_PDIHS].nr/5;
-        const int numPeriodicImproper = idef.il[F_PIDIHS].nr/5;
-        const int numRB = idef.il[F_RBDIHS].nr/5;
-        const int numImproperDih = idef.il[F_IDIHS].nr/5;
-        const int num14 = idef.il[F_LJ14].nr/3;
-        System* sys = new System();
-        if (ir->nstcomm > 0)
-            sys->addForce(new CMMotionRemover(ir->nstcomm));
-
-        /* Set bonded force field terms. */
-
-               /* 
-                * CUDA platform currently doesn't support more than one
-                * instance of a force object, so we pack all forces that
-                * use the same form into one.
-               */
-
-        const int* bondAtoms = (int*) idef.il[F_BONDS].iatoms;
-        HarmonicBondForce* bondForce = new HarmonicBondForce();
-        sys->addForce(bondForce);
-        int offset = 0;
-        for (int i = 0; i < numBonds; ++i)
-        {
-            int type = bondAtoms[offset++];
-            int atom1 = bondAtoms[offset++];
-            int atom2 = bondAtoms[offset++];
-            bondForce->addBond(atom1, atom2,
-                               idef.iparams[type].harmonic.rA, idef.iparams[type].harmonic.krA);
-        }
-
-        const int* harmonicAtoms = (int*) idef.il[F_HARMONIC].iatoms;
-        offset = 0;
-        for (int i = 0; i < numHarmonic; ++i)
-        {
-            int type = harmonicAtoms[offset++];
-            int atom1 = harmonicAtoms[offset++];
-            int atom2 = harmonicAtoms[offset++];
-            bondForce->addBond(atom1, atom2,
-                               idef.iparams[type].harmonic.rA, idef.iparams[type].harmonic.krA);
-        }
-
-               /* Set the angle force field terms */
-        const int* angleAtoms = (int*) idef.il[F_ANGLES].iatoms;
-        HarmonicAngleForce* angleForce = new HarmonicAngleForce();
-        sys->addForce(angleForce);
-        offset = 0;
-        for (int i = 0; i < numAngles; ++i)
-        {
-            int type = angleAtoms[offset++];
-            int atom1 = angleAtoms[offset++];
-            int atom2 = angleAtoms[offset++];
-            int atom3 = angleAtoms[offset++];
-            angleForce->addAngle(atom1, atom2, atom3, 
-                    idef.iparams[type].harmonic.rA*M_PI/180.0, idef.iparams[type].harmonic.krA);
-        }
-
-        /* Urey-Bradley includes both the angle and bond potential for 1-3 interactions */
-        const int* ubAtoms = (int*) idef.il[F_UREY_BRADLEY].iatoms;
-               /* HarmonicBondForce* ubBondForce = new HarmonicBondForce(); */
-               /*  HarmonicAngleForce* ubAngleForce = new HarmonicAngleForce(); */
-        /* sys->addForce(ubBondForce); */
-        /* sys->addForce(ubAngleForce); */
-        offset = 0;
-        for (int i = 0; i < numUB; ++i)
-        {
-            int type = ubAtoms[offset++];
-            int atom1 = ubAtoms[offset++];
-            int atom2 = ubAtoms[offset++];
-            int atom3 = ubAtoms[offset++];
-            /* ubBondForce->addBond(atom1, atom3, */
-            bondForce->addBond(atom1, atom3,
-                               idef.iparams[type].u_b.r13A, idef.iparams[type].u_b.kUBA);
-            /* ubAngleForce->addAngle(atom1, atom2, atom3, */ 
-            angleForce->addAngle(atom1, atom2, atom3, 
-                    idef.iparams[type].u_b.thetaA*M_PI/180.0, idef.iparams[type].u_b.kthetaA);
-        }
-
-               /* Set proper dihedral terms */
-        const int* periodicAtoms = (int*) idef.il[F_PDIHS].iatoms;
-        PeriodicTorsionForce* periodicForce = new PeriodicTorsionForce();
-        sys->addForce(periodicForce);
-        offset = 0;
-        for (int i = 0; i < numPeriodic; ++i)
-        {
-            int type = periodicAtoms[offset++];
-            int atom1 = periodicAtoms[offset++];
-            int atom2 = periodicAtoms[offset++];
-            int atom3 = periodicAtoms[offset++];
-            int atom4 = periodicAtoms[offset++];
-            periodicForce->addTorsion(atom1, atom2, atom3, atom4,
-                                      idef.iparams[type].pdihs.mult,
-                                      idef.iparams[type].pdihs.phiA*M_PI/180.0, 
-                                      idef.iparams[type].pdihs.cpA);
-        }
-
-               /* Set improper dihedral terms that are represented by a periodic function (as in AMBER FF) */
-        const int* periodicImproperAtoms = (int*) idef.il[F_PIDIHS].iatoms;
-        /* PeriodicTorsionForce* periodicImproperForce = new PeriodicTorsionForce(); */
-        /* sys->addForce(periodicImproperForce); */
-        offset = 0;
-        for (int i = 0; i < numPeriodicImproper; ++i)
-        {
-            int type = periodicImproperAtoms[offset++];
-            int atom1 = periodicImproperAtoms[offset++];
-            int atom2 = periodicImproperAtoms[offset++];
-            int atom3 = periodicImproperAtoms[offset++];
-            int atom4 = periodicImproperAtoms[offset++];
-            /* periodicImproperForce->addTorsion(atom1, atom2, atom3, atom4, */
-            periodicForce->addTorsion(atom1, atom2, atom3, atom4,
-                                      idef.iparams[type].pdihs.mult,
-                                      idef.iparams[type].pdihs.phiA*M_PI/180.0,
-                                      idef.iparams[type].pdihs.cpA);
-        }
-
-        /* Ryckaert-Bellemans dihedrals */
-        const int* rbAtoms = (int*) idef.il[F_RBDIHS].iatoms;
-        RBTorsionForce* rbForce = new RBTorsionForce();
-        sys->addForce(rbForce);
-        offset = 0;
-        for (int i = 0; i < numRB; ++i)
-        {
-            int type = rbAtoms[offset++];
-            int atom1 = rbAtoms[offset++];
-            int atom2 = rbAtoms[offset++];
-            int atom3 = rbAtoms[offset++];
-            int atom4 = rbAtoms[offset++];
-            rbForce->addTorsion(atom1, atom2, atom3, atom4,
-                                idef.iparams[type].rbdihs.rbcA[0], idef.iparams[type].rbdihs.rbcA[1],
-                                idef.iparams[type].rbdihs.rbcA[2], idef.iparams[type].rbdihs.rbcA[3],
-                                idef.iparams[type].rbdihs.rbcA[4], idef.iparams[type].rbdihs.rbcA[5]);
-        }
-
-               /* Set improper dihedral terms (as in CHARMM FF) */
-        const int* improperDihAtoms = (int*) idef.il[F_IDIHS].iatoms;
-               CustomTorsionForce* improperDihForce = new CustomTorsionForce("2.0*k*asin(sin((theta-theta0)/2))^2");
-        sys->addForce(improperDihForce);
-               improperDihForce->addPerTorsionParameter("k");
-               improperDihForce->addPerTorsionParameter("theta0");
-               vector<double> improperDihParameters(2);
-        offset = 0;
-        for (int i = 0; i < numImproperDih; ++i)
-        {
-            int type = improperDihAtoms[offset++];
-            int atom1 = improperDihAtoms[offset++];
-            int atom2 = improperDihAtoms[offset++];
-            int atom3 = improperDihAtoms[offset++];
-            int atom4 = improperDihAtoms[offset++];
-                       improperDihParameters[0] = idef.iparams[type].harmonic.krA;
-                       improperDihParameters[1] = idef.iparams[type].harmonic.rA*M_PI/180.0;
-            improperDihForce->addTorsion(atom1, atom2, atom3, atom4,
-                                improperDihParameters);
-        }
-
-        /* Set nonbonded parameters and masses. */
-        int ntypes = fr->ntype;
-        int* types = mdatoms->typeA;
-        real* nbfp = fr->nbfp;
-        real* charges = mdatoms->chargeA;
-        real* masses = mdatoms->massT;
-        NonbondedForce* nonbondedForce = new NonbondedForce();
-        sys->addForce(nonbondedForce);
-        
-        switch (ir->ePBC)
-        {
-        case epbcNONE:
-            if (ir->rcoulomb == 0)
-            {
-                nonbondedForce->setNonbondedMethod(NonbondedForce::NoCutoff);
-            }
-            else
-            {
-                nonbondedForce->setNonbondedMethod(NonbondedForce::CutoffNonPeriodic);
-            }
-            break;
-        case epbcXYZ:
-            switch (ir->coulombtype)
-            {
-            case eelCUT:
-            case eelRF:
-            case eelGRF:
-            case eelRF_NEC:
-            case eelRF_ZERO:
-                nonbondedForce->setNonbondedMethod(NonbondedForce::CutoffPeriodic);
-                break;
-
-            case eelEWALD:
-                nonbondedForce->setNonbondedMethod(NonbondedForce::Ewald);
-                break;
-
-            case eelPME:
-                nonbondedForce->setNonbondedMethod(NonbondedForce::PME);
-                break;
-
-            default:
-                gmx_fatal(FARGS,"Internal error: you should not see this message, it means that the"
-                          "electrosatics option check failed. Please report this error!");
-            }        
-            sys->setDefaultPeriodicBoxVectors(Vec3(state->box[0][0], 0, 0),
-                                       Vec3(0, state->box[1][1], 0), Vec3(0, 0, state->box[2][2]));                    
-            nonbondedForce->setCutoffDistance(ir->rcoulomb);
-           
-            break;
-        default:            
-            gmx_fatal(FARGS,"OpenMM supports only full periodic boundary conditions "
-                              "(pbc = xyz), or none (pbc = no).");
-        }
-
-
-        /* Fix for PME and Ewald error tolerance 
-         *
-                *  OpenMM uses approximate formulas to calculate the Ewald parameter:
-                *  alpha = (1.0/cutoff)*sqrt(-log(2.0*tolerlance));
-                *  and the grid spacing for PME:
-                *  gridX = ceil(2*alpha*box[0][0]/3*(pow(tol, 0.2)))
-                *  gridY = ceil(2*alpha*box[1][1]/3*(pow(tol, 0.2)));
-                *  gridZ = ceil(2*alpha*box[2][2]/3*(pow(tol, 0.2)));
-                *
-                *  
-                *  If the default ewald_rtol=1e-5 is used we silently adjust the value to the 
-                *  OpenMM default of 5e-4 otherwise a warning is issued about the action taken. 
-                *
-               */
-        double corr_ewald_rtol = 50.0 * ir->ewald_rtol;
-        if ((ir->ePBC == epbcXYZ) && 
-            (ir->coulombtype == eelEWALD || ir->coulombtype == eelPME))
-        {
-            if (debug)
-            {
-                fprintf(debug, ">> ewald_rtol = %e (corrected = %e) \n",
-                    ir->ewald_rtol, corr_ewald_rtol);
-            }
-
-            if (fabs(ir->ewald_rtol - 1e-5) > 1e-10)
-            {
-                gmx_warning("OpenMM uses the ewald_rtol parameter with approximate formulas "
-                        "to calculate the alpha and grid spacing parameters of the Ewald "
-                        "and PME methods. This tolerance need to be corrected in order to get "
-                        "settings close to the ones used in GROMACS. Although the internal correction "
-                        "should work for any reasonable value of ewald_rtol, using values other than "
-                        "the default 1e-5 might cause incorrect behavior.");
-
-                if (corr_ewald_rtol > 1)
-                {
-                    gmx_fatal(FARGS, "The ewald_rtol accuracy term is >1 after the "
-                            "adjustment for OpenMM (%e)", corr_ewald_rtol);
-                }
-            }
-            nonbondedForce->setEwaldErrorTolerance(corr_ewald_rtol);
-        }
-
-        for (int i = 0; i < numAtoms; ++i)
-        {
-            /* nbfp now includes the 6.0/12.0 derivative prefactors to save flops in kernels*/
-            double c12 = nbfp[types[i]*2*ntypes+types[i]*2+1]/12.0;
-            double c6 = nbfp[types[i]*2*ntypes+types[i]*2]/6.0;
-            double sigma=0.0, epsilon=0.0;
-            convert_c_12_6(c12, c6, &sigma, &epsilon);
-            nonbondedForce->addParticle(charges[i], sigma, epsilon);
-            sys->addParticle(masses[i]);
-        }
-
-        // Build a table of all exclusions.
-        vector<set<int> > exclusions(numAtoms);
-        for (int i = 0; i < numAtoms; i++)
-        {
-            int start = top->excls.index[i];
-            int end = top->excls.index[i+1];
-            for (int j = start; j < end; j++)
-                exclusions[i].insert(top->excls.a[j]);
-        }
-
-        // Record the 1-4 interactions, and remove them from the list of exclusions.
-        const int* nb14Atoms = (int*) idef.il[F_LJ14].iatoms;
-        offset = 0;
-        for (int i = 0; i < num14; ++i)
-        {
-            int type = nb14Atoms[offset++];
-            int atom1 = nb14Atoms[offset++];
-            int atom2 = nb14Atoms[offset++];
-            double sigma=0, epsilon=0;
-            convert_c_12_6(idef.iparams[type].lj14.c12A, 
-                    idef.iparams[type].lj14.c6A,
-                    &sigma, &epsilon);
-            nonbondedForce->addException(atom1, atom2,
-                                         fr->fudgeQQ*charges[atom1]*charges[atom2], sigma, epsilon);
-            exclusions[atom1].erase(atom2);
-            exclusions[atom2].erase(atom1);
-        }
-
-        // Record exclusions.
-        for (int i = 0; i < numAtoms; i++)
-        {
-            for (set<int>::const_iterator iter = exclusions[i].begin(); iter != exclusions[i].end(); ++iter)
-            {
-                if (i < *iter)
-                {
-                    nonbondedForce->addException(i, *iter, 0.0, 1.0, 0.0);
-                }
-            }
-        }
-
-        // Add GBSA if needed.
-        if (ir->implicit_solvent == eisGBSA)
-        {
-            gmx_warning("The OBC scale factors alpha, beta and gamma are hardcoded in OpenMM with the default Gromacs values.");
-            t_atoms atoms       = gmx_mtop_global_atoms(top_global);
-            GBSAOBCForce* gbsa  = new GBSAOBCForce();
-
-            sys->addForce(gbsa);
-            gbsa->setSoluteDielectric(ir->epsilon_r);
-            gbsa->setSolventDielectric(ir->gb_epsilon_solvent);
-            gbsa->setCutoffDistance(nonbondedForce->getCutoffDistance());
-            if (nonbondedForce->getNonbondedMethod() == NonbondedForce::NoCutoff)
-                gbsa->setNonbondedMethod(GBSAOBCForce::NoCutoff);
-            else if (nonbondedForce->getNonbondedMethod() == NonbondedForce::CutoffNonPeriodic)
-                gbsa->setNonbondedMethod(GBSAOBCForce::CutoffNonPeriodic);
-            else if (nonbondedForce->getNonbondedMethod() == NonbondedForce::CutoffPeriodic)
-                gbsa->setNonbondedMethod(GBSAOBCForce::CutoffPeriodic);
-            else
-                gmx_fatal(FARGS,"OpenMM supports only Reaction-Field electrostatics with OBC/GBSA.");
-
-            for (int i = 0; i < numAtoms; ++i)
-            {
-                gbsa->addParticle(charges[i],
-                                  top_global->atomtypes.gb_radius[atoms.atom[i].type],
-                                  top_global->atomtypes.S_hct[atoms.atom[i].type]);
-            }
-            free_t_atoms(&atoms, FALSE);
-        }
-
-        // Set constraints.
-        const int* constraintAtoms = (int*) idef.il[F_CONSTR].iatoms;
-        offset = 0;
-        for (int i = 0; i < numConstraints; ++i)
-        {
-            int type = constraintAtoms[offset++];
-            int atom1 = constraintAtoms[offset++];
-            int atom2 = constraintAtoms[offset++];
-            sys->addConstraint(atom1, atom2, idef.iparams[type].constr.dA);
-        }
-        const int* settleAtoms = (int*) idef.il[F_SETTLE].iatoms;
-        offset = 0;
-        for (int i = 0; i < numSettle; ++i)
-        {
-            int type = settleAtoms[offset++];
-            int oxygen = settleAtoms[offset++];
-            sys->addConstraint(oxygen, oxygen+1, idef.iparams[type].settle.doh);
-            sys->addConstraint(oxygen, oxygen+2, idef.iparams[type].settle.doh);
-            sys->addConstraint(oxygen+1, oxygen+2, idef.iparams[type].settle.dhh);
-        }
-
-        // Create an integrator for simulating the system.
-        double friction = (ir->opts.tau_t[0] == 0.0 ? 0.0 : 1.0/ir->opts.tau_t[0]);
-        Integrator* integ;
-        if (ir->eI == eiBD)
-        {
-            integ = new BrownianIntegrator(ir->opts.ref_t[0], friction, ir->delta_t);
-            static_cast<BrownianIntegrator*>(integ)->setRandomNumberSeed(ir->ld_seed); 
-        }
-        else if (EI_SD(ir->eI))
-        {
-            integ = new LangevinIntegrator(ir->opts.ref_t[0], friction, ir->delta_t);
-            static_cast<LangevinIntegrator*>(integ)->setRandomNumberSeed(ir->ld_seed); 
-        }
-        else 
-        {
-            integ = new VerletIntegrator(ir->delta_t);
-            if ( ir->etc != etcNO)
-            {
-                AndersenThermostat* thermostat = new AndersenThermostat(ir->opts.ref_t[0], friction); 
-                sys->addForce(thermostat);
-            }           
-        }
-
-               // Add pressure coupling
-        if (ir->epc != epcNO)
-               {
-          // convert gromacs pressure tensor to a scalar
-          double pressure = (ir->ref_p[0][0] + ir->ref_p[1][1] + ir->ref_p[2][2]) / 3.0;
-          int frequency = int(ir->tau_p / ir->delta_t); // update frequency in time steps
-          if (frequency < 1) frequency = 1;
-          double temperature = ir->opts.ref_t[0]; // in kelvin
-          sys->addForce(new MonteCarloBarostat(pressure, temperature, frequency));
-               }
-
-        integ->setConstraintTolerance(ir->shake_tol);
-
-        // Create a context and initialize it.
-        Context* context = NULL;
-
-        /*      
-        OpenMM could automatically select the "best" GPU, however we're not't 
-        going to let it do that for now, as the current algorithm is very rudimentary
-        and we anyway support only CUDA.        
-        if (platformOptStr == NULL || platformOptStr == "")
-        {
-            context = new Context(*sys, *integ);
-        }
-        else
-        */        
-        {
-            /* which platform should we use */
-            for (int i = 0; i < (int)Platform::getNumPlatforms() && context == NULL; i++)
-            {
-                if (isStringEqNCase(opt->getOptionValue("platform"), Platform::getPlatform(i).getName()))
-                {
-                    Platform& platform = Platform::getPlatform(i);
-                    // set standard properties
-                    platform.setPropertyDefaultValue("CudaDevice", opt->getOptionValue("deviceid"));
-                    // TODO add extra properties
-                    context = new Context(*sys, *integ, platform);
-                }
-            }
-            if (context == NULL)
-            {
-                gmx_fatal(FARGS, "The requested platform \"%s\" could not be found.", 
-                        opt->getOptionValue("platform").c_str());
-            }
-        }
-
-        Platform& platform = context->getPlatform();
-        fprintf(fplog, "Gromacs will use the OpenMM platform: %s\n", platform.getName().c_str());
-
-        const vector<string>& properties = platform.getPropertyNames();
-        if (debug)
-        {
-            for (int i = 0; i < (int)properties.size(); i++)
-            {
-                fprintf(debug, ">> %s: %s\n", properties[i].c_str(), 
-                        platform.getPropertyValue(*context, properties[i]).c_str());
-            }
-        }
-
-        /* only for CUDA */
-        if (isStringEqNCase(opt->getOptionValue("platform"), "CUDA"))
-        {
-            int tmp;
-            if (!from_string<int>(tmp, platform.getPropertyValue(*context, "CudaDevice"), std::dec))
-            {
-                gmx_fatal(FARGS, "Internal error: couldn't determine the device selected by OpenMM");
-
-            }
-
-            /* For now this is just to double-check if OpenMM selected the GPU we wanted,
-            but when we'll let OpenMM select the GPU automatically, it will query the deviceId.
-            */            
-            if (tmp != devId)
-            {
-                gmx_fatal(FARGS, "Internal error: OpenMM is using device #%d"
-                        "while initialized for device #%d", tmp, devId);
-            }        
-            
-            /* check GPU compatibility */
-            char gpuname[STRLEN];
-            devId = atoi(opt->getOptionValue("deviceid").c_str());
-            if (!is_gmx_openmm_supported_gpu(-1, gpuname))
-            {
-                if (!gmx_strcasecmp(opt->getOptionValue("force-device").c_str(), "yes"))
-                {
-                    sprintf(warn_buf, "Non-supported GPU selected (#%d, %s), forced continuing."
-                            "Note, that the simulation can be slow or it migth even crash.", 
-                            devId, gpuname);
-                    fprintf(fplog, "%s\n", warn_buf);
-                    gmx_warning(warn_buf);
-                }
-                else
-                {
-                    gmx_fatal(FARGS, "The selected GPU (#%d, %s) is not supported by Gromacs! "
-                              "Most probably you have a low-end GPU which would not perform well, " 
-                              "or new hardware that has not been tested with the current release. "
-                              "If you still want to try using the device, use the force-device=yes option.", 
-                              devId, gpuname);
-                }
-            }
-            else
-            {
-                fprintf(fplog, "Gromacs will run on the GPU #%d (%s).\n", devId, gpuname);
-            }
-        }
-        
-        /* only for CUDA */
-        if (isStringEqNCase(opt->getOptionValue("platform"), "CUDA"))
-        {
-            /* pre-simulation memtest */
-            runMemtest(fplog, -1, "Pre", opt);
-        }
-
-        vector<Vec3> pos(numAtoms);
-        vector<Vec3> vel(numAtoms);
-        for (int i = 0; i < numAtoms; ++i)
-        {
-            pos[i] = Vec3(state->x[i][0], state->x[i][1], state->x[i][2]);
-            vel[i] = Vec3(state->v[i][0], state->v[i][1], state->v[i][2]);
-        }
-        context->setPositions(pos);
-        context->setVelocities(vel);
-
-        // Return a structure containing the system, integrator, and context.
-        OpenMMData* data = new OpenMMData();
-        data->system = sys;
-        data->integrator = integ;
-        data->context = context;
-        data->removeCM = (ir->nstcomm > 0);
-        data->platformOpt = opt;
-        return data;
-    }
-    catch (std::exception& e)
-    {
-        gmx_fatal(FARGS, "OpenMM exception caught while initializating: %s", e.what());
-    } 
-    return NULL; /* just to avoid warnings */
-}
-
-/*!
- * \brief Integrate one step.
- *
- * \param[in] data  OpenMMData object created by openmm_init().
- */
-void openmm_take_one_step(void* data)
-{
-    // static int step = 0; printf("----> taking step #%d\n", step++);
-    try
-    {
-        static_cast<OpenMMData*>(data)->integrator->step(1);
-    }
-    catch (std::exception& e)
-    {
-        gmx_fatal(FARGS, "OpenMM exception caught while taking a step: %s", e.what());
-    }
-}
-
-/*!
- * \brief Integrate n steps.
- *
- * \param[in] data  OpenMMData object created by openmm_init().
- */
-void openmm_take_steps(void* data, int nstep)
-{
-    try
-    {
-        static_cast<OpenMMData*>(data)->integrator->step(nstep);
-    }
-    catch (std::exception& e)
-    {
-        gmx_fatal(FARGS, "OpenMM exception caught while taking a step: %s", e.what());
-    }
-}
-
-/*!
- * \brief Clean up the data structures cretead for OpenMM.
- *
- * \param[in] log   Log file pointer.
- * \param[in] data  OpenMMData object created by openmm_init().
- */
-void openmm_cleanup(FILE* fplog, void* data)
-{
-    OpenMMData* d = static_cast<OpenMMData*>(data);
-    /* only for CUDA */
-    if (isStringEqNCase(d->platformOpt->getOptionValue("platform"), "CUDA"))
-    {
-        /* post-simulation memtest */
-        runMemtest(fplog, -1, "Post", d->platformOpt);
-    }
-    delete d->system;
-    delete d->integrator;
-    delete d->context;
-    delete d->platformOpt;
-    delete d;
-}
-
-/*!
- * \brief Copy the current state information from OpenMM into the Gromacs data structures.
- * 
- * This function results in the requested proprties to be copied from the 
- * GPU to host. As this represents a bottleneck, the frequency of pulling data
- * should be minimized. 
- *
- * \param[in]   data        OpenMMData object created by openmm_init().
- * \param[out]  time        Simulation time for which the state was created.
- * \param[out]  state       State of the system: coordinates and velocities.
- * \param[out]  f           Forces.
- * \param[out]  enerd       Energies.
- * \param[in]   includePos  True if coordinates are requested.
- * \param[in]   includeVel  True if velocities are requested. 
- * \param[in]   includeForce True if forces are requested. 
- * \param[in]   includeEnergy True if energies are requested. 
- */
-void openmm_copy_state(void *data,
-                       t_state *state, double *time,
-                       rvec f[], gmx_enerdata_t *enerd,
-                       gmx_bool includePos, gmx_bool includeVel, gmx_bool includeForce, gmx_bool includeEnergy)
-{
-    int types = 0;
-    if (includePos)
-        types += State::Positions;
-    if (includeVel)
-        types += State::Velocities;
-    if (includeForce)
-        types += State::Forces;
-    if (includeEnergy)
-        types += State::Energy;
-    if (types == 0)
-        return;
-    try
-    {
-        State currentState = static_cast<OpenMMData*>(data)->context->getState(types);
-        int numAtoms =  static_cast<OpenMMData*>(data)->system->getNumParticles();
-        if (includePos)
-        {
-            for (int i = 0; i < numAtoms; i++)
-            {
-                Vec3 x = currentState.getPositions()[i];
-                state->x[i][0] = x[0];
-                state->x[i][1] = x[1];
-                state->x[i][2] = x[2];
-            }
-        }
-        if (includeVel)
-        {
-            for (int i = 0; i < numAtoms; i++)
-            {
-                Vec3 v = currentState.getVelocities()[i];
-                state->v[i][0] = v[0];
-                state->v[i][1] = v[1];
-                state->v[i][2] = v[2];
-            }
-        }
-        if (includeForce)
-        {
-            for (int i = 0; i < numAtoms; i++)
-            {
-                Vec3 force = currentState.getForces()[i];
-                f[i][0] = force[0];
-                f[i][1] = force[1];
-                f[i][2] = force[2];
-            }
-        }
-        if (includeEnergy)
-        {
-            int numConstraints = static_cast<OpenMMData*>(data)->system->getNumConstraints();
-            int dof = 3*numAtoms-numConstraints;
-            if (static_cast<OpenMMData*>(data)->removeCM)
-                dof -= 3;
-            enerd->term[F_EPOT] = currentState.getPotentialEnergy();
-            enerd->term[F_EKIN] = currentState.getKineticEnergy();
-            enerd->term[F_ETOT] = enerd->term[F_EPOT] + enerd->term[F_EKIN];
-            enerd->term[F_TEMP] = 2.0*enerd->term[F_EKIN]/dof/BOLTZ;
-        }
-        *time = currentState.getTime();
-    }
-    catch (std::exception& e)
-    {
-        gmx_fatal(FARGS, "OpenMM exception caught while retrieving state information: %s", e.what());
-    }
-}
diff --git a/src/contrib/openmm_wrapper.h b/src/contrib/openmm_wrapper.h
deleted file mode 100644 (file)
index 7013426..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * This file is part of the GROMACS molecular simulation package.
- *
- * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
- * Copyright (c) 2001-2010, The GROMACS development team,
- * check out http://www.gromacs.org for more information.
- * Copyright (c) 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.
- *
- * GROMACS is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1
- * of the License, or (at your option) any later version.
- *
- * GROMACS is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with GROMACS; if not, see
- * http://www.gnu.org/licenses, or write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
- *
- * If you want to redistribute modifications to GROMACS, 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 http://www.gromacs.org.
- *
- * To help us fund GROMACS development, we humbly ask that you cite
- * the research papers on the package. Check out http://www.gromacs.org.
- */
-
-#ifndef _OPENMM_WRAPPER_H_
-#define _OPENMM_WRAPPER_H_
-
-#ifdef __cplusplus
-extern "C"
-{
-#endif
-
-void* openmm_init(FILE *fplog, const char *platformOptStr,
-                    t_inputrec *ir,
-                    gmx_mtop_t *top_global, gmx_localtop_t *top,
-                    t_mdatoms *mdatoms, t_forcerec *fr, t_state *state);
-
-void openmm_take_one_step(void* data);
-
-void openmm_take_steps(void* data, int nsteps);
-
-void openmm_copy_state(void *data,
-                        t_state *state, double *time,
-                        rvec f[], gmx_enerdata_t *enerd,
-                        gmx_bool includePos, gmx_bool includeVel, gmx_bool includeForce, gmx_bool includeEnergy);
-
-void openmm_cleanup(FILE *fplog, void* data);
-
-#ifdef __cplusplus
-} // extern "C"
-#endif
-
-#endif /* _OPENMM_WRAPPER_H_ */
-
diff --git a/src/contrib/runner_openmm.c b/src/contrib/runner_openmm.c
deleted file mode 100644 (file)
index 1d15fd0..0000000
+++ /dev/null
@@ -1,1993 +0,0 @@
-/*
- * This file is part of the GROMACS molecular simulation package.
- *
- * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
- * Copyright (c) 2001-2004, The GROMACS development team,
- * check out http://www.gromacs.org for more information.
- * Copyright (c) 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.
- *
- * GROMACS is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1
- * of the License, or (at your option) any later version.
- *
- * GROMACS is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with GROMACS; if not, see
- * http://www.gnu.org/licenses, or write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
- *
- * If you want to redistribute modifications to GROMACS, 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 http://www.gromacs.org.
- *
- * To help us fund GROMACS development, we humbly ask that you cite
- * the research papers on the package. Check out http://www.gromacs.org.
- */
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-#if defined(HAVE_SCHED_H) && defined(HAVE_SCHED_GETAFFINITY)
-#define _GNU_SOURCE
-#include <sched.h>
-#include <sys/syscall.h>
-#endif
-#include <signal.h>
-#include <stdlib.h>
-#include <string.h>
-#include <assert.h>
-
-#include "typedefs.h"
-#include "smalloc.h"
-#include "sysstuff.h"
-#include "statutil.h"
-#include "mdrun.h"
-#include "md_logging.h"
-#include "md_support.h"
-#include "network.h"
-#include "pull.h"
-#include "names.h"
-#include "disre.h"
-#include "orires.h"
-#include "pme.h"
-#include "mdatoms.h"
-#include "repl_ex.h"
-#include "qmmm.h"
-#include "mpelogging.h"
-#include "domdec.h"
-#include "partdec.h"
-#include "coulomb.h"
-#include "constr.h"
-#include "mvdata.h"
-#include "checkpoint.h"
-#include "mtop_util.h"
-#include "sighandler.h"
-#include "tpxio.h"
-#include "txtdump.h"
-#include "gmx_detect_hardware.h"
-#include "gmx_omp_nthreads.h"
-#include "pull_rotation.h"
-#include "calc_verletbuf.h"
-#include "../mdlib/nbnxn_search.h"
-#include "../mdlib/nbnxn_consts.h"
-#include "gmx_fatal_collective.h"
-#include "membed.h"
-#include "md_openmm.h"
-#include "gmx_omp.h"
-
-#include "thread_mpi/threads.h"
-
-#include "gromacs/utility/gmxmpi.h"
-
-#ifdef GMX_FAHCORE
-#include "corewrap.h"
-#endif
-
-#include "gpu_utils.h"
-#include "nbnxn_cuda_data_mgmt.h"
-
-typedef struct { 
-    gmx_integrator_t *func;
-} gmx_intp_t;
-
-/* The array should match the eI array in include/types/enums.h */
-const gmx_intp_t integrator[eiNR] = { {do_md_openmm}, {do_md_openmm}, {do_md_openmm}, {do_md_openmm}, {do_md_openmm}, {do_md_openmm}, {do_md_openmm}, {do_md_openmm}, {do_md_openmm}, {do_md_openmm}, {do_md_openmm},{do_md_openmm}};
-
-gmx_large_int_t     deform_init_init_step_tpx;
-matrix              deform_init_box_tpx;
-#ifdef GMX_THREAD_MPI
-tMPI_Thread_mutex_t deform_init_box_mutex=TMPI_THREAD_MUTEX_INITIALIZER;
-#endif
-
-
-#ifdef GMX_THREAD_MPI
-struct mdrunner_arglist
-{
-    gmx_hw_opt_t *hw_opt;
-    FILE *fplog;
-    t_commrec *cr;
-    int nfile;
-    const t_filenm *fnm;
-    output_env_t oenv;
-    gmx_bool bVerbose;
-    gmx_bool bCompact;
-    int nstglobalcomm;
-    ivec ddxyz;
-    int dd_node_order;
-    real rdd;
-    real rconstr;
-    const char *dddlb_opt;
-    real dlb_scale;
-    const char *ddcsx;
-    const char *ddcsy;
-    const char *ddcsz;
-    const char *nbpu_opt;
-    int nsteps_cmdline;
-    int nstepout;
-    int resetstep;
-    int nmultisim;
-    int repl_ex_nst;
-    int repl_ex_nex;
-    int repl_ex_seed;
-    real pforce;
-    real cpt_period;
-    real max_hours;
-    const char *deviceOptions;
-    unsigned long Flags;
-    int ret; /* return value */
-};
-
-
-/* The function used for spawning threads. Extracts the mdrunner() 
-   arguments from its one argument and calls mdrunner(), after making
-   a commrec. */
-static void mdrunner_start_fn(void *arg)
-{
-    struct mdrunner_arglist *mda=(struct mdrunner_arglist*)arg;
-    struct mdrunner_arglist mc=*mda; /* copy the arg list to make sure 
-                                        that it's thread-local. This doesn't
-                                        copy pointed-to items, of course,
-                                        but those are all const. */
-    t_commrec *cr;  /* we need a local version of this */
-    FILE *fplog=NULL;
-    t_filenm *fnm;
-
-    fnm = dup_tfn(mc.nfile, mc.fnm);
-
-    cr = init_par_threads(mc.cr);
-
-    if (MASTER(cr))
-    {
-        fplog=mc.fplog;
-    }
-
-    mda->ret=mdrunner(mc.hw_opt, fplog, cr, mc.nfile, fnm, mc.oenv, 
-                      mc.bVerbose, mc.bCompact, mc.nstglobalcomm, 
-                      mc.ddxyz, mc.dd_node_order, mc.rdd,
-                      mc.rconstr, mc.dddlb_opt, mc.dlb_scale, 
-                      mc.ddcsx, mc.ddcsy, mc.ddcsz,
-                      mc.nbpu_opt,
-                      mc.nsteps_cmdline, mc.nstepout, mc.resetstep,
-                      mc.nmultisim, mc.repl_ex_nst, mc.repl_ex_nex, mc.repl_ex_seed, mc.pforce, 
-                      mc.cpt_period, mc.max_hours, mc.deviceOptions, mc.Flags);
-}
-
-/* called by mdrunner() to start a specific number of threads (including 
-   the main thread) for thread-parallel runs. This in turn calls mdrunner()
-   for each thread. 
-   All options besides nthreads are the same as for mdrunner(). */
-static t_commrec *mdrunner_start_threads(gmx_hw_opt_t *hw_opt, 
-              FILE *fplog,t_commrec *cr,int nfile, 
-              const t_filenm fnm[], const output_env_t oenv, gmx_bool bVerbose,
-              gmx_bool bCompact, int nstglobalcomm,
-              ivec ddxyz,int dd_node_order,real rdd,real rconstr,
-              const char *dddlb_opt,real dlb_scale,
-              const char *ddcsx,const char *ddcsy,const char *ddcsz,
-              const char *nbpu_opt,
-              int nsteps_cmdline, int nstepout,int resetstep,
-              int nmultisim,int repl_ex_nst,int repl_ex_nex, int repl_ex_seed,
-              real pforce,real cpt_period, real max_hours, 
-              const char *deviceOptions, unsigned long Flags)
-{
-    int ret;
-    struct mdrunner_arglist *mda;
-    t_commrec *crn; /* the new commrec */
-    t_filenm *fnmn;
-
-    /* first check whether we even need to start tMPI */
-    if (hw_opt->nthreads_tmpi < 2)
-    {
-        return cr;
-    }
-
-    /* a few small, one-time, almost unavoidable memory leaks: */
-    snew(mda,1);
-    fnmn=dup_tfn(nfile, fnm);
-
-    /* fill the data structure to pass as void pointer to thread start fn */
-    mda->hw_opt=hw_opt;
-    mda->fplog=fplog;
-    mda->cr=cr;
-    mda->nfile=nfile;
-    mda->fnm=fnmn;
-    mda->oenv=oenv;
-    mda->bVerbose=bVerbose;
-    mda->bCompact=bCompact;
-    mda->nstglobalcomm=nstglobalcomm;
-    mda->ddxyz[XX]=ddxyz[XX];
-    mda->ddxyz[YY]=ddxyz[YY];
-    mda->ddxyz[ZZ]=ddxyz[ZZ];
-    mda->dd_node_order=dd_node_order;
-    mda->rdd=rdd;
-    mda->rconstr=rconstr;
-    mda->dddlb_opt=dddlb_opt;
-    mda->dlb_scale=dlb_scale;
-    mda->ddcsx=ddcsx;
-    mda->ddcsy=ddcsy;
-    mda->ddcsz=ddcsz;
-    mda->nbpu_opt=nbpu_opt;
-    mda->nsteps_cmdline=nsteps_cmdline;
-    mda->nstepout=nstepout;
-    mda->resetstep=resetstep;
-    mda->nmultisim=nmultisim;
-    mda->repl_ex_nst=repl_ex_nst;
-    mda->repl_ex_nex=repl_ex_nex;
-    mda->repl_ex_seed=repl_ex_seed;
-    mda->pforce=pforce;
-    mda->cpt_period=cpt_period;
-    mda->max_hours=max_hours;
-    mda->deviceOptions=deviceOptions;
-    mda->Flags=Flags;
-
-    /* now spawn new threads that start mdrunner_start_fn(), while 
-       the main thread returns */
-    ret=tMPI_Init_fn(TRUE, hw_opt->nthreads_tmpi,
-                     (hw_opt->bThreadPinning ? TMPI_AFFINITY_ALL_CORES : TMPI_AFFINITY_NONE),
-                     mdrunner_start_fn, (void*)(mda) );
-    if (ret!=TMPI_SUCCESS)
-        return NULL;
-
-    /* make a new comm_rec to reflect the new situation */
-    crn=init_par_threads(cr);
-    return crn;
-}
-
-
-static int get_tmpi_omp_thread_division(const gmx_hw_info_t *hwinfo,
-                                        const gmx_hw_opt_t *hw_opt,
-                                        int nthreads_tot,
-                                        int ngpu)
-{
-    int nthreads_tmpi;
-
-    /* There are no separate PME nodes here, as we ensured in
-     * check_and_update_hw_opt that nthreads_tmpi>0 with PME nodes
-     * and a conditional ensures we would not have ended up here.
-     * Note that separate PME nodes might be switched on later.
-     */
-    if (ngpu > 0)
-    {
-        nthreads_tmpi = ngpu;
-        if (nthreads_tot > 0 && nthreads_tot < nthreads_tmpi)
-        {
-            nthreads_tmpi = nthreads_tot;
-        }
-    }
-    else if (hw_opt->nthreads_omp > 0)
-    {
-        /* Here we could oversubscribe, when we do, we issue a warning later */
-        nthreads_tmpi = max(1,nthreads_tot/hw_opt->nthreads_omp);
-    }
-    else
-    {
-        /* TODO choose nthreads_omp based on hardware topology
-           when we have a hardware topology detection library */
-        /* In general, when running up to 4 threads, OpenMP should be faster.
-         * Note: on AMD Bulldozer we should avoid running OpenMP over two dies.
-         * On Intel>=Nehalem running OpenMP on a single CPU is always faster,
-         * even on two CPUs it's usually faster (but with many OpenMP threads
-         * it could be faster not to use HT, currently we always use HT).
-         * On Nehalem/Westmere we want to avoid running 16 threads over
-         * two CPUs with HT, so we need a limit<16; thus we use 12.
-         * A reasonable limit for Intel Sandy and Ivy bridge,
-         * not knowing the topology, is 16 threads.
-         */
-        const int nthreads_omp_always_faster             =  4;
-        const int nthreads_omp_always_faster_Nehalem     = 12;
-        const int nthreads_omp_always_faster_SandyBridge = 16;
-        const int first_model_Nehalem     = 0x1A;
-        const int first_model_SandyBridge = 0x2A;
-        gmx_bool bIntel_Family6;
-
-        bIntel_Family6 =
-            (gmx_cpuid_vendor(hwinfo->cpuid_info) == GMX_CPUID_VENDOR_INTEL &&
-             gmx_cpuid_family(hwinfo->cpuid_info) == 6);
-
-        if (nthreads_tot <= nthreads_omp_always_faster ||
-            (bIntel_Family6 &&
-             ((gmx_cpuid_model(hwinfo->cpuid_info) >= nthreads_omp_always_faster_Nehalem && nthreads_tot <= nthreads_omp_always_faster_Nehalem) ||
-              (gmx_cpuid_model(hwinfo->cpuid_info) >= nthreads_omp_always_faster_SandyBridge && nthreads_tot <= nthreads_omp_always_faster_SandyBridge))))
-        {
-            /* Use pure OpenMP parallelization */
-            nthreads_tmpi = 1;
-        }
-        else
-        {
-            /* Don't use OpenMP parallelization */
-            nthreads_tmpi = nthreads_tot;
-        }
-    }
-
-    return nthreads_tmpi;
-}
-
-
-/* Get the number of threads to use for thread-MPI based on how many
- * were requested, which algorithms we're using,
- * and how many particles there are.
- * At the point we have already called check_and_update_hw_opt.
- * Thus all options should be internally consistent and consistent
- * with the hardware, except that ntmpi could be larger than #GPU.
- */
-static int get_nthreads_mpi(gmx_hw_info_t *hwinfo,
-                            gmx_hw_opt_t *hw_opt,
-                            t_inputrec *inputrec, gmx_mtop_t *mtop,
-                            const t_commrec *cr,
-                            FILE *fplog)
-{
-    int nthreads_hw,nthreads_tot_max,nthreads_tmpi,nthreads_new,ngpu;
-    int min_atoms_per_mpi_thread;
-    char *env;
-    char sbuf[STRLEN];
-    gmx_bool bCanUseGPU;
-
-    if (hw_opt->nthreads_tmpi > 0)
-    {
-        /* Trivial, return right away */
-        return hw_opt->nthreads_tmpi;
-    }
-
-    nthreads_hw = hwinfo->nthreads_hw_avail;
-
-    /* How many total (#tMPI*#OpenMP) threads can we start? */ 
-    if (hw_opt->nthreads_tot > 0)
-    {
-        nthreads_tot_max = hw_opt->nthreads_tot;
-    }
-    else
-    {
-        nthreads_tot_max = nthreads_hw;
-    }
-
-    bCanUseGPU = (inputrec->cutoff_scheme == ecutsVERLET && hwinfo->bCanUseGPU);
-    if (bCanUseGPU)
-    {
-        ngpu = hwinfo->gpu_info.ncuda_dev_use;
-    }
-    else
-    {
-        ngpu = 0;
-    }
-
-    nthreads_tmpi =
-        get_tmpi_omp_thread_division(hwinfo,hw_opt,nthreads_tot_max,ngpu);
-
-    if (inputrec->eI == eiNM || EI_TPI(inputrec->eI))
-    {
-        /* Steps are divided over the nodes iso splitting the atoms */
-        min_atoms_per_mpi_thread = 0;
-    }
-    else
-    {
-        if (bCanUseGPU)
-        {
-            min_atoms_per_mpi_thread = MIN_ATOMS_PER_GPU;
-        }
-        else
-        {
-            min_atoms_per_mpi_thread = MIN_ATOMS_PER_MPI_THREAD;
-        }
-    }
-
-    /* Check if an algorithm does not support parallel simulation.  */
-    if (nthreads_tmpi != 1 &&
-        ( inputrec->eI == eiLBFGS ||
-          inputrec->coulombtype == eelEWALD ) )
-    {
-        nthreads_tmpi = 1;
-
-        md_print_warn(cr,fplog,"The integration or electrostatics algorithm doesn't support parallel runs. Using a single thread-MPI thread.\n");
-        if (hw_opt->nthreads_tmpi > nthreads_tmpi)
-        {
-            gmx_fatal(FARGS,"You asked for more than 1 thread-MPI thread, but an algorithm doesn't support that");
-        }
-    }
-    else if (mtop->natoms/nthreads_tmpi < min_atoms_per_mpi_thread)
-    {
-        /* the thread number was chosen automatically, but there are too many
-           threads (too few atoms per thread) */
-        nthreads_new = max(1,mtop->natoms/min_atoms_per_mpi_thread);
-
-        /* Avoid partial use of Hyper-Threading */
-        if (gmx_cpuid_x86_smt(hwinfo->cpuid_info) == GMX_CPUID_X86_SMT_ENABLED &&
-            nthreads_new > nthreads_hw/2 && nthreads_new < nthreads_hw)
-        {
-            nthreads_new = nthreads_hw/2;
-        }
-
-        /* Avoid large prime numbers in the thread count */
-        if (nthreads_new >= 6)
-        {
-            /* Use only 6,8,10 with additional factors of 2 */
-            int fac;
-
-            fac = 2;
-            while (3*fac*2 <= nthreads_new)
-            {
-                fac *= 2;
-            }
-
-            nthreads_new = (nthreads_new/fac)*fac;
-        }
-        else
-        {
-            /* Avoid 5 */
-            if (nthreads_new == 5)
-            {
-                nthreads_new = 4;
-            }
-        }
-
-        nthreads_tmpi = nthreads_new;
-
-        fprintf(stderr,"\n");
-        fprintf(stderr,"NOTE: Parallelization is limited by the small number of atoms,\n");
-        fprintf(stderr,"      only starting %d thread-MPI threads.\n",nthreads_tmpi);
-        fprintf(stderr,"      You can use the -nt and/or -ntmpi option to optimize the number of threads.\n\n");
-    }
-
-    return nthreads_tmpi;
-}
-#endif /* GMX_THREAD_MPI */
-
-
-/* Environment variable for setting nstlist */
-static const char*  NSTLIST_ENVVAR          =  "GMX_NSTLIST";
-/* Try to increase nstlist when using a GPU with nstlist less than this */
-static const int    NSTLIST_GPU_ENOUGH      = 20;
-/* Increase nstlist until the non-bonded cost increases more than this factor */
-static const float  NBNXN_GPU_LIST_OK_FAC   = 1.25;
-/* Don't increase nstlist beyond a non-bonded cost increases of this factor */
-static const float  NBNXN_GPU_LIST_MAX_FAC  = 1.40;
-
-/* Try to increase nstlist when running on a GPU */
-static void increase_nstlist(FILE *fp,t_commrec *cr,
-                             t_inputrec *ir,const gmx_mtop_t *mtop,matrix box)
-{
-    char *env;
-    int  nstlist_orig,nstlist_prev;
-    verletbuf_list_setup_t ls;
-    real rlist_inc,rlist_ok,rlist_max,rlist_new,rlist_prev;
-    int  i;
-    t_state state_tmp;
-    gmx_bool bBox,bDD,bCont;
-    const char *nstl_fmt="\nFor optimal performance with a GPU nstlist (now %d) should be larger.\nThe optimum depends on your CPU and GPU resources.\nYou might want to try several nstlist values.\n";
-    const char *vbd_err="Can not increase nstlist for GPU run because verlet-buffer-drift is not set or used";
-    const char *box_err="Can not increase nstlist for GPU run because the box is too small";
-    const char *dd_err ="Can not increase nstlist for GPU run because of domain decomposition limitations";
-    char buf[STRLEN];
-
-    /* Number of + nstlist alternative values to try when switching  */
-    const int nstl[]={ 20, 25, 40, 50 };
-#define NNSTL  sizeof(nstl)/sizeof(nstl[0])
-
-    env = getenv(NSTLIST_ENVVAR);
-    if (env == NULL)
-    {
-        if (fp != NULL)
-        {
-            fprintf(fp,nstl_fmt,ir->nstlist);
-        }
-    }
-
-    if (ir->verletbuf_drift == 0)
-    {
-        gmx_fatal(FARGS,"You are using an old tpr file with a GPU, please generate a new tpr file with an up to date version of grompp");
-    }
-
-    if (ir->verletbuf_drift < 0)
-    {
-        if (MASTER(cr))
-        {
-            fprintf(stderr,"%s\n",vbd_err);
-        }
-        if (fp != NULL)
-        {
-            fprintf(fp,"%s\n",vbd_err);
-        }
-
-        return;
-    }
-
-    nstlist_orig = ir->nstlist;
-    if (env != NULL)
-    {
-        sprintf(buf,"Getting nstlist from environment variable GMX_NSTLIST=%s",env);
-        if (MASTER(cr))
-        {
-            fprintf(stderr,"%s\n",buf);
-        }
-        if (fp != NULL)
-        {
-            fprintf(fp,"%s\n",buf);
-        }
-        sscanf(env,"%d",&ir->nstlist);
-    }
-
-    verletbuf_get_list_setup(TRUE,&ls);
-
-    /* Allow rlist to make the list double the size of the cut-off sphere */
-    rlist_inc = nbnxn_get_rlist_effective_inc(NBNXN_GPU_CLUSTER_SIZE,mtop->natoms/det(box));
-    rlist_ok  = (max(ir->rvdw,ir->rcoulomb) + rlist_inc)*pow(NBNXN_GPU_LIST_OK_FAC,1.0/3.0) - rlist_inc;
-    rlist_max = (max(ir->rvdw,ir->rcoulomb) + rlist_inc)*pow(NBNXN_GPU_LIST_MAX_FAC,1.0/3.0) - rlist_inc;
-    if (debug)
-    {
-        fprintf(debug,"GPU nstlist tuning: rlist_inc %.3f rlist_max %.3f\n",
-                rlist_inc,rlist_max);
-    }
-
-    i = 0;
-    nstlist_prev = nstlist_orig;
-    rlist_prev   = ir->rlist;
-    do
-    {
-        if (env == NULL)
-        {
-            ir->nstlist = nstl[i];
-        }
-
-        /* Set the pair-list buffer size in ir */
-        calc_verlet_buffer_size(mtop,det(box),ir,ir->verletbuf_drift,&ls,
-                                NULL,&rlist_new);
-
-        /* Does rlist fit in the box? */
-        bBox = (sqr(rlist_new) < max_cutoff2(ir->ePBC,box));
-        bDD  = TRUE;
-        if (bBox && DOMAINDECOMP(cr))
-        {
-            /* Check if rlist fits in the domain decomposition */
-            if (inputrec2nboundeddim(ir) < DIM)
-            {
-                gmx_incons("Changing nstlist with domain decomposition and unbounded dimensions is not implemented yet");
-            }
-            copy_mat(box,state_tmp.box);
-            bDD = change_dd_cutoff(cr,&state_tmp,ir,rlist_new);
-        }
-
-        bCont = FALSE;
-
-        if (env == NULL)
-        {
-            if (bBox && bDD && rlist_new <= rlist_max)
-            {
-                /* Increase nstlist */
-                nstlist_prev = ir->nstlist;
-                rlist_prev   = rlist_new;
-                bCont = (i+1 < NNSTL && rlist_new < rlist_ok);
-            }
-            else
-            {
-                /* Stick with the previous nstlist */
-                ir->nstlist = nstlist_prev;
-                rlist_new   = rlist_prev;
-                bBox = TRUE;
-                bDD  = TRUE;
-            }
-        }
-
-        i++;
-    }
-    while (bCont);
-
-    if (!bBox || !bDD)
-    {
-        gmx_warning(!bBox ? box_err : dd_err);
-        if (fp != NULL)
-        {
-            fprintf(fp,"\n%s\n",bBox ? box_err : dd_err);
-        }
-        ir->nstlist = nstlist_orig;
-    }
-    else if (ir->nstlist != nstlist_orig || rlist_new != ir->rlist)
-    {
-        sprintf(buf,"Changing nstlist from %d to %d, rlist from %g to %g",
-                nstlist_orig,ir->nstlist,
-                ir->rlist,rlist_new);
-        if (MASTER(cr))
-        {
-            fprintf(stderr,"%s\n\n",buf);
-        }
-        if (fp != NULL)
-        {
-            fprintf(fp,"%s\n\n",buf);
-        }
-        ir->rlist     = rlist_new;
-        ir->rlistlong = rlist_new;
-    }
-}
-
-static void prepare_verlet_scheme(FILE *fplog,
-                                  gmx_hw_info_t *hwinfo,
-                                  t_commrec *cr,
-                                  gmx_hw_opt_t *hw_opt,
-                                  const char *nbpu_opt,
-                                  t_inputrec *ir,
-                                  const gmx_mtop_t *mtop,
-                                  matrix box,
-                                  gmx_bool *bUseGPU)
-{
-    /* Here we only check for GPU usage on the MPI master process,
-     * as here we don't know how many GPUs we will use yet.
-     * We check for a GPU on all processes later.
-     */
-    *bUseGPU = hwinfo->bCanUseGPU || (getenv("GMX_EMULATE_GPU") != NULL);
-
-    if (ir->verletbuf_drift > 0)
-    {
-        /* Update the Verlet buffer size for the current run setup */
-        verletbuf_list_setup_t ls;
-        real rlist_new;
-
-        /* Here we assume CPU acceleration is on. But as currently
-         * calc_verlet_buffer_size gives the same results for 4x8 and 4x4
-         * and 4x2 gives a larger buffer than 4x4, this is ok.
-         */
-        verletbuf_get_list_setup(*bUseGPU,&ls);
-
-        calc_verlet_buffer_size(mtop,det(box),ir,
-                                ir->verletbuf_drift,&ls,
-                                NULL,&rlist_new);
-        if (rlist_new != ir->rlist)
-        {
-            if (fplog != NULL)
-            {
-                fprintf(fplog,"\nChanging rlist from %g to %g for non-bonded %dx%d atom kernels\n\n",
-                        ir->rlist,rlist_new,
-                        ls.cluster_size_i,ls.cluster_size_j);
-            }
-            ir->rlist     = rlist_new;
-            ir->rlistlong = rlist_new;
-        }
-    }
-
-    /* With GPU or emulation we should check nstlist for performance */
-    if ((EI_DYNAMICS(ir->eI) &&
-         *bUseGPU &&
-         ir->nstlist < NSTLIST_GPU_ENOUGH) ||
-        getenv(NSTLIST_ENVVAR) != NULL)
-    {
-        /* Choose a better nstlist */
-        increase_nstlist(fplog,cr,ir,mtop,box);
-    }
-}
-
-static void convert_to_verlet_scheme(FILE *fplog,
-                                     t_inputrec *ir,
-                                     gmx_mtop_t *mtop,real box_vol)
-{
-    char *conv_mesg="Converting input file with group cut-off scheme to the Verlet cut-off scheme";
-
-    md_print_warn(NULL,fplog,"%s\n",conv_mesg);
-
-    ir->cutoff_scheme   = ecutsVERLET;
-    ir->verletbuf_drift = 0.005;
-
-    if (ir->rcoulomb != ir->rvdw)
-    {
-        gmx_fatal(FARGS,"The VdW and Coulomb cut-offs are different, whereas the Verlet scheme only supports equal cut-offs");
-    }
-
-    if (ir->vdwtype == evdwUSER || EEL_USER(ir->coulombtype))
-    {
-        gmx_fatal(FARGS,"User non-bonded potentials are not (yet) supported with the Verlet scheme");
-    }
-    else if (EVDW_SWITCHED(ir->vdwtype) || EEL_SWITCHED(ir->coulombtype))
-    {
-        md_print_warn(NULL,fplog,"Converting switched or shifted interactions to a shifted potential (without force shift), this will lead to slightly different interaction potentials");
-
-        if (EVDW_SWITCHED(ir->vdwtype))
-        {
-            ir->vdwtype = evdwCUT;
-        }
-        if (EEL_SWITCHED(ir->coulombtype))
-        {
-            if (EEL_FULL(ir->coulombtype))
-            {
-                /* With full electrostatic only PME can be switched */
-                ir->coulombtype = eelPME;
-            }
-            else
-            {
-                md_print_warn(NULL,fplog,"NOTE: Replacing %s electrostatics with reaction-field with epsilon-rf=inf\n",eel_names[ir->coulombtype]);
-                ir->coulombtype = eelRF;
-                ir->epsilon_rf  = 0.0;
-            }
-        }
-
-        /* We set the target energy drift to a small number.
-         * Note that this is only for testing. For production the user
-         * should think about this and set the mdp options.
-         */
-        ir->verletbuf_drift = 1e-4;
-    }
-
-    if (inputrec2nboundeddim(ir) != 3)
-    {
-        gmx_fatal(FARGS,"Can only convert old tpr files to the Verlet cut-off scheme with 3D pbc");
-    }
-
-    if (ir->efep != efepNO || ir->implicit_solvent != eisNO)
-    {
-        gmx_fatal(FARGS,"Will not convert old tpr files to the Verlet cut-off scheme with free-energy calculations or implicit solvent");
-    }
-
-    if (EI_DYNAMICS(ir->eI) && !(EI_MD(ir->eI) && ir->etc == etcNO))
-    {
-        verletbuf_list_setup_t ls;
-
-        verletbuf_get_list_setup(FALSE,&ls);
-        calc_verlet_buffer_size(mtop,box_vol,ir,ir->verletbuf_drift,&ls,
-                                NULL,&ir->rlist);
-    }
-    else
-    {
-        ir->verletbuf_drift = -1;
-        ir->rlist           = 1.05*max(ir->rvdw,ir->rcoulomb);
-    }
-
-    gmx_mtop_remove_chargegroups(mtop);
-}
-
-/* Check the process affinity mask. If it is non-zero, something
- * else has set the affinity, and mdrun should honor that and
- * not attempt to do its own thread pinning.
- *
- * This function should be called twice. Once before the OpenMP
- * library gets initialized with bAfterOpenMPInit=FALSE (which will
- * detect affinity set by external tools like taskset), and again
- * later, after the OpenMP initialization, with bAfterOpenMPInit=TRUE
- * (which will detect affinity changes made by the OpenMP library).
- *
- * Note that this will only work on Linux, because we use a GNU
- * feature. */
-static void check_cpu_affinity_set(FILE *fplog, const t_commrec *cr,
-                                   gmx_hw_opt_t *hw_opt, int ncpus,
-                                   gmx_bool bAfterOpenmpInit)
-{
-#ifdef HAVE_SCHED_GETAFFINITY
-    cpu_set_t mask_current;
-    int       i, ret, cpu_count, cpu_set;
-    gmx_bool  bAllSet;
-
-    assert(hw_opt);
-    if (!hw_opt->bThreadPinning)
-    {
-        /* internal affinity setting is off, don't bother checking process affinity */
-        return;
-    }
-
-    CPU_ZERO(&mask_current);
-    if ((ret = sched_getaffinity(0, sizeof(cpu_set_t), &mask_current)) != 0)
-    {
-        /* failed to query affinity mask, will just return */
-        if (debug)
-        {
-            fprintf(debug, "Failed to query affinity mask (error %d)", ret);
-        }
-        return;
-    }
-
-    /* Before proceeding with the actual check, make sure that the number of
-     * detected CPUs is >= the CPUs in the current set.
-     * We need to check for CPU_COUNT as it was added only in glibc 2.6. */
-#ifdef CPU_COUNT
-    if (ncpus < CPU_COUNT(&mask_current))
-    {
-        if (debug)
-        {
-            fprintf(debug, "%d CPUs detected, but %d was returned by CPU_COUNT",
-                    ncpus, CPU_COUNT(&mask_current));
-        }
-        return;
-    }
-#endif /* CPU_COUNT */
-
-    bAllSet = TRUE;
-    for (i = 0; (i < ncpus && i < CPU_SETSIZE); i++)
-    {
-        bAllSet = bAllSet && (CPU_ISSET(i, &mask_current) != 0);
-    }
-
-    if (!bAllSet)
-    {
-        if (!bAfterOpenmpInit)
-        {
-            md_print_warn(cr, fplog,
-                          "%s detected a non-default process affinity, "
-                          "so it will not attempt to pin its threads", ShortProgram());
-        }
-        else
-        {
-            md_print_warn(cr, fplog,
-                          "%s detected a non-default process affinity, "
-                          "probably set by the OpenMP library, "
-                          "so it will not attempt to pin its threads", ShortProgram());
-        }
-        hw_opt->bThreadPinning = FALSE;
-
-        if (debug)
-        {
-            fprintf(debug, "Non-default affinity mask found, mdrun will not pin threads\n");
-        }
-    }
-    else
-    {
-        if (debug)
-        {
-            fprintf(debug, "Default affinity mask found\n");
-        }
-    }
-#endif /* HAVE_SCHED_GETAFFINITY */
-}
-
-/* Set CPU affinity. Can be important for performance.
-   On some systems (e.g. Cray) CPU Affinity is set by default.
-   But default assigning doesn't work (well) with only some ranks
-   having threads. This causes very low performance.
-   External tools have cumbersome syntax for setting affinity
-   in the case that only some ranks have threads.
-   Thus it is important that GROMACS sets the affinity internally
-   if only PME is using threads.
-*/
-static void set_cpu_affinity(FILE *fplog,
-                             const t_commrec *cr,
-                             gmx_hw_opt_t *hw_opt,
-                             int nthreads_pme,
-                             const gmx_hw_info_t *hwinfo,
-                             const t_inputrec *inputrec)
-{
-#if defined GMX_THREAD_MPI
-    /* With the number of TMPI threads equal to the number of cores
-     * we already pinned in thread-MPI, so don't pin again here.
-     */
-    if (hw_opt->nthreads_tmpi == tMPI_Thread_get_hw_number())
-    {
-        return;
-    }
-#endif
-
-#ifndef __APPLE__
-    /* If the tMPI thread affinity setting is not supported encourage the user
-     * to report it as it's either a bug or an exotic platform which we might
-     * want to support. */
-    if (tMPI_Thread_setaffinity_support() != TMPI_SETAFFINITY_SUPPORT_YES)
-    {
-        md_print_warn(NULL, fplog,
-                      "Can not set thread affinities on the current plarform. On NUMA systems this\n"
-                      "can cause performance degradation. If you think your platform should support\n"
-                      "setting affinities, contact the GROMACS developers.");
-        return;
-    }
-#endif /* __APPLE__ */
-
-    if (hw_opt->bThreadPinning)
-    {
-        int nth_affinity_set, thread_id_node, thread_id,
-            nthread_local, nthread_node, nthread_hw_max, nphyscore;
-        int offset;
-        char *env;
-
-        /* threads on this MPI process or TMPI thread */
-        if (cr->duty & DUTY_PP)
-        {
-            nthread_local = gmx_omp_nthreads_get(emntNonbonded);
-        }
-        else
-        {
-            nthread_local = gmx_omp_nthreads_get(emntPME);
-        }
-
-        /* map the current process to cores */
-        thread_id_node = 0;
-        nthread_node = nthread_local;
-#ifdef GMX_MPI
-        if (PAR(cr) || MULTISIM(cr))
-        {
-            /* We need to determine a scan of the thread counts in this
-             * compute node.
-             */
-            MPI_Comm comm_intra;
-
-            MPI_Comm_split(MPI_COMM_WORLD,gmx_hostname_num(),cr->rank_intranode,
-                           &comm_intra);
-            MPI_Scan(&nthread_local,&thread_id_node,1,MPI_INT,MPI_SUM,comm_intra);
-            /* MPI_Scan is inclusive, but here we need exclusive */
-            thread_id_node -= nthread_local;
-            /* Get the total number of threads on this physical node */
-            MPI_Allreduce(&nthread_local,&nthread_node,1,MPI_INT,MPI_SUM,comm_intra);
-            MPI_Comm_free(&comm_intra);
-        }
-#endif
-
-        offset = 0;
-        if (hw_opt->core_pinning_offset > 0)
-        {
-            offset = hw_opt->core_pinning_offset;
-            if (SIMMASTER(cr))
-            {
-                fprintf(stderr, "Applying core pinning offset %d\n", offset);
-            }
-            if (fplog)
-            {
-                fprintf(fplog, "Applying core pinning offset %d\n", offset);
-            }
-        }
-
-        /* With Intel Hyper-Threading enabled, we want to pin consecutive
-         * threads to physical cores when using more threads than physical
-         * cores or when the user requests so.
-         */
-        nthread_hw_max = hwinfo->nthreads_hw_avail;
-        nphyscore = -1;
-        if (hw_opt->bPinHyperthreading ||
-            (gmx_cpuid_x86_smt(hwinfo->cpuid_info) == GMX_CPUID_X86_SMT_ENABLED &&
-             nthread_node > nthread_hw_max/2 && getenv("GMX_DISABLE_PINHT") == NULL))
-        {
-            if (gmx_cpuid_x86_smt(hwinfo->cpuid_info) != GMX_CPUID_X86_SMT_ENABLED)
-            {
-                /* We print to stderr on all processes, as we might have
-                 * different settings on different physical nodes.
-                 */
-                if (gmx_cpuid_vendor(hwinfo->cpuid_info) != GMX_CPUID_VENDOR_INTEL)
-                {
-                    md_print_warn(NULL, fplog, "Pinning for Hyper-Threading layout requested, "
-                                  "but non-Intel CPU detected (vendor: %s)\n",
-                                  gmx_cpuid_vendor_string[gmx_cpuid_vendor(hwinfo->cpuid_info)]);
-                }
-                else
-                {
-                    md_print_warn(NULL, fplog, "Pinning for Hyper-Threading layout requested, "
-                                  "but the CPU detected does not have Intel Hyper-Threading support "
-                                  "(or it is turned off)\n");
-                }
-            }
-            nphyscore = nthread_hw_max/2;
-
-            if (SIMMASTER(cr))
-            {
-                fprintf(stderr, "Pinning to Hyper-Threading cores with %d physical cores in a compute node\n",
-                        nphyscore);
-            }
-            if (fplog)
-            {
-                fprintf(fplog, "Pinning to Hyper-Threading cores with %d physical cores in a compute node\n",
-                        nphyscore);
-            }
-        }
-
-        /* Set the per-thread affinity. In order to be able to check the success
-         * of affinity settings, we will set nth_affinity_set to 1 on threads
-         * where the affinity setting succeded and to 0 where it failed.
-         * Reducing these 0/1 values over the threads will give the total number
-         * of threads on which we succeeded.
-         */
-         nth_affinity_set = 0;
-#pragma omp parallel firstprivate(thread_id_node) num_threads(nthread_local) \
-                     reduction(+:nth_affinity_set)
-        {
-            int      core;
-            gmx_bool setaffinity_ret;
-
-            thread_id       = gmx_omp_get_thread_num();
-            thread_id_node += thread_id;
-            if (nphyscore <= 0)
-            {
-                core = offset + thread_id_node;
-            }
-            else
-            {
-                /* Lock pairs of threads to the same hyperthreaded core */
-                core = offset + thread_id_node/2 + (thread_id_node % 2)*nphyscore;
-            }
-
-            setaffinity_ret = tMPI_Thread_setaffinity_single(tMPI_Thread_self(), core);
-
-            /* store the per-thread success-values of the setaffinity */
-            nth_affinity_set = (setaffinity_ret == 0);
-
-            if (debug)
-            {
-                fprintf(debug, "On rank %2d, thread %2d, core %2d the affinity setting returned %d\n",
-                        cr->nodeid, gmx_omp_get_thread_num(), core, setaffinity_ret);
-            }
-        }
-
-        if (nth_affinity_set > nthread_local)
-        {
-            char msg[STRLEN];
-
-            sprintf(msg, "Looks like we have set affinity for more threads than "
-                    "we have (%d > %d)!\n", nth_affinity_set, nthread_local);
-            gmx_incons(msg);
-        }
-        else
-        {
-            /* check & warn if some threads failed to set their affinities */
-            if (nth_affinity_set != nthread_local)
-            {
-                char sbuf1[STRLEN], sbuf2[STRLEN];
-
-                /* sbuf1 contains rank info, while sbuf2 OpenMP thread info */
-                sbuf1[0] = sbuf2[0] = '\0';
-#ifdef GMX_MPI
-#ifdef GMX_THREAD_MPI
-                sprintf(sbuf1, "In thread-MPI thread #%d: ", cr->nodeid);
-#else /* GMX_LIB_MPI */
-                sprintf(sbuf1, "In MPI process #%d: ", cr->nodeid);
-#endif
-#endif /* GMX_MPI */
-
-                if (nthread_local > 1)
-                {
-                    sprintf(sbuf2, "of %d/%d thread%s ",
-                            nthread_local - nth_affinity_set, nthread_local,
-                            (nthread_local - nth_affinity_set) > 1 ? "s" : "");
-                }
-
-                md_print_warn(NULL, fplog,
-                              "NOTE: %sAffinity setting %sfailed.\n"
-                              "      This can cause performance degradation!",
-                              sbuf1, sbuf2);
-            }
-        }
-    }
-}
-
-
-static void check_and_update_hw_opt(gmx_hw_opt_t *hw_opt,
-                                    int cutoff_scheme)
-{
-    gmx_omp_nthreads_read_env(&hw_opt->nthreads_omp);
-
-#ifndef GMX_THREAD_MPI
-    if (hw_opt->nthreads_tot > 0)
-    {
-        gmx_fatal(FARGS,"Setting the total number of threads is only supported with thread-MPI and Gromacs was compiled without thread-MPI");
-    }
-    if (hw_opt->nthreads_tmpi > 0)
-    {
-        gmx_fatal(FARGS,"Setting the number of thread-MPI threads is only supported with thread-MPI and Gromacs was compiled without thread-MPI");
-    }
-#endif
-
-    if (hw_opt->nthreads_tot > 0 && hw_opt->nthreads_omp_pme <= 0)
-    {
-        /* We have the same number of OpenMP threads for PP and PME processes,
-         * thus we can perform several consistency checks.
-         */
-        if (hw_opt->nthreads_tmpi > 0 &&
-            hw_opt->nthreads_omp > 0 &&
-            hw_opt->nthreads_tot != hw_opt->nthreads_tmpi*hw_opt->nthreads_omp)
-        {
-            gmx_fatal(FARGS,"The total number of threads requested (%d) does not match the thread-MPI threads (%d) times the OpenMP threads (%d) requested",
-                      hw_opt->nthreads_tot,hw_opt->nthreads_tmpi,hw_opt->nthreads_omp);
-        }
-
-        if (hw_opt->nthreads_tmpi > 0 &&
-            hw_opt->nthreads_tot % hw_opt->nthreads_tmpi != 0)
-        {
-            gmx_fatal(FARGS,"The total number of threads requested (%d) is not divisible by the number of thread-MPI threads requested (%d)",
-                      hw_opt->nthreads_tot,hw_opt->nthreads_tmpi);
-        }
-
-        if (hw_opt->nthreads_omp > 0 &&
-            hw_opt->nthreads_tot % hw_opt->nthreads_omp != 0)
-        {
-            gmx_fatal(FARGS,"The total number of threads requested (%d) is not divisible by the number of OpenMP threads requested (%d)",
-                      hw_opt->nthreads_tot,hw_opt->nthreads_omp);
-        }
-
-        if (hw_opt->nthreads_tmpi > 0 &&
-            hw_opt->nthreads_omp <= 0)
-        {
-            hw_opt->nthreads_omp = hw_opt->nthreads_tot/hw_opt->nthreads_tmpi;
-        }
-    }
-
-#ifndef GMX_OPENMP
-    if (hw_opt->nthreads_omp > 1)
-    {
-        gmx_fatal(FARGS,"OpenMP threads are requested, but Gromacs was compiled without OpenMP support");
-    }
-#endif
-
-    if (cutoff_scheme == ecutsGROUP)
-    {
-        /* We only have OpenMP support for PME only nodes */
-        if (hw_opt->nthreads_omp > 1)
-        {
-            gmx_fatal(FARGS,"OpenMP threads have been requested with cut-off scheme %s, but these are only supported with cut-off scheme %s",
-                      ecutscheme_names[cutoff_scheme],
-                      ecutscheme_names[ecutsVERLET]);
-        }
-        hw_opt->nthreads_omp = 1;
-    }
-
-    if (hw_opt->nthreads_omp_pme > 0 && hw_opt->nthreads_omp <= 0)
-    {
-        gmx_fatal(FARGS,"You need to specify -ntomp in addition to -ntomp_pme");
-    }
-
-    if (hw_opt->nthreads_tot == 1)
-    {
-        hw_opt->nthreads_tmpi = 1;
-
-        if (hw_opt->nthreads_omp > 1)
-        {
-            gmx_fatal(FARGS,"You requested %d OpenMP threads with %d total threads",
-                      hw_opt->nthreads_tmpi,hw_opt->nthreads_tot);
-        }
-        hw_opt->nthreads_omp = 1;
-    }
-
-    if (hw_opt->nthreads_omp_pme <= 0 && hw_opt->nthreads_omp > 0)
-    {
-        hw_opt->nthreads_omp_pme = hw_opt->nthreads_omp;
-    }
-
-    if (debug)
-    {
-        fprintf(debug,"hw_opt: nt %d ntmpi %d ntomp %d ntomp_pme %d gpu_id '%s'\n",
-                hw_opt->nthreads_tot,
-                hw_opt->nthreads_tmpi,
-                hw_opt->nthreads_omp,
-                hw_opt->nthreads_omp_pme,
-                hw_opt->gpu_id!=NULL ? hw_opt->gpu_id : "");
-                
-    }
-}
-
-
-/* Override the value in inputrec with value passed on the command line (if any) */
-static void override_nsteps_cmdline(FILE *fplog,
-                                    int nsteps_cmdline,
-                                    t_inputrec *ir,
-                                    const t_commrec *cr)
-{
-    assert(ir);
-    assert(cr);
-
-    /* override with anything else than the default -2 */
-    if (nsteps_cmdline > -2)
-    {
-        char stmp[STRLEN];
-
-        ir->nsteps = nsteps_cmdline;
-        if (EI_DYNAMICS(ir->eI))
-        {
-            sprintf(stmp, "Overriding nsteps with value passed on the command line: %d steps, %.3f ps",
-                    nsteps_cmdline, nsteps_cmdline*ir->delta_t);
-        }
-        else
-        {
-            sprintf(stmp, "Overriding nsteps with value passed on the command line: %d steps",
-                    nsteps_cmdline);
-        }
-
-        md_print_warn(cr, fplog, "%s\n", stmp);
-    }
-}
-
-/* Data structure set by SIMMASTER which needs to be passed to all nodes
- * before the other nodes have read the tpx file and called gmx_detect_hardware.
- */
-typedef struct {
-    int cutoff_scheme; /* The cutoff scheme from inputrec_t */
-    gmx_bool bUseGPU;       /* Use GPU or GPU emulation          */
-} master_inf_t;
-
-int mdrunner(gmx_hw_opt_t *hw_opt,
-             FILE *fplog,t_commrec *cr,int nfile,
-             const t_filenm fnm[], const output_env_t oenv, gmx_bool bVerbose,
-             gmx_bool bCompact, int nstglobalcomm,
-             ivec ddxyz,int dd_node_order,real rdd,real rconstr,
-             const char *dddlb_opt,real dlb_scale,
-             const char *ddcsx,const char *ddcsy,const char *ddcsz,
-             const char *nbpu_opt,
-             int nsteps_cmdline, int nstepout,int resetstep,
-             int nmultisim,int repl_ex_nst,int repl_ex_nex,
-             int repl_ex_seed, real pforce,real cpt_period,real max_hours,
-             const char *deviceOptions, unsigned long Flags)
-{
-    gmx_bool   bForceUseGPU,bTryUseGPU;
-    double     nodetime=0,realtime;
-    t_inputrec *inputrec;
-    t_state    *state=NULL;
-    matrix     box;
-    gmx_ddbox_t ddbox={0};
-    int        npme_major,npme_minor;
-    real       tmpr1,tmpr2;
-    t_nrnb     *nrnb;
-    gmx_mtop_t *mtop=NULL;
-    t_mdatoms  *mdatoms=NULL;
-    t_forcerec *fr=NULL;
-    t_fcdata   *fcd=NULL;
-    real       ewaldcoeff=0;
-    gmx_pme_t  *pmedata=NULL;
-    gmx_vsite_t *vsite=NULL;
-    gmx_constr_t constr;
-    int        i,m,nChargePerturbed=-1,status,nalloc;
-    char       *gro;
-    gmx_wallcycle_t wcycle;
-    gmx_bool       bReadRNG,bReadEkin;
-    int        list;
-    gmx_runtime_t runtime;
-    int        rc;
-    gmx_large_int_t reset_counters;
-    gmx_edsam_t ed=NULL;
-    t_commrec   *cr_old=cr; 
-    int         nthreads_pme=1;
-    int         nthreads_pp=1;
-    gmx_membed_t membed=NULL;
-    gmx_hw_info_t *hwinfo=NULL;
-    master_inf_t minf={-1,FALSE};
-
-    /* CAUTION: threads may be started later on in this function, so
-       cr doesn't reflect the final parallel state right now */
-    snew(inputrec,1);
-    snew(mtop,1);
-    
-    if (Flags & MD_APPENDFILES) 
-    {
-        fplog = NULL;
-    }
-
-    bForceUseGPU = (strncmp(nbpu_opt, "gpu", 3) == 0);
-    bTryUseGPU   = (strncmp(nbpu_opt, "auto", 4) == 0) || bForceUseGPU;
-
-    snew(state,1);
-    if (SIMMASTER(cr)) 
-    {
-        /* Read (nearly) all data required for the simulation */
-        read_tpx_state(ftp2fn(efTPX,nfile,fnm),inputrec,state,NULL,mtop);
-
-        if (inputrec->cutoff_scheme != ecutsVERLET &&
-            ((Flags & MD_TESTVERLET) || getenv("GMX_VERLET_SCHEME") != NULL))
-        {
-            convert_to_verlet_scheme(fplog,inputrec,mtop,det(state->box));
-        }
-
-        /* Detect hardware, gather information. With tMPI only thread 0 does it
-         * and after threads are started broadcasts hwinfo around. */
-        snew(hwinfo, 1);
-        gmx_detect_hardware(fplog, hwinfo, cr,
-                            bForceUseGPU, bTryUseGPU, hw_opt->gpu_id);
-
-        minf.cutoff_scheme = inputrec->cutoff_scheme;
-        minf.bUseGPU       = FALSE;
-
-        if (inputrec->cutoff_scheme == ecutsVERLET)
-        {
-            prepare_verlet_scheme(fplog,hwinfo,cr,hw_opt,nbpu_opt,
-                                  inputrec,mtop,state->box,
-                                  &minf.bUseGPU);
-        }
-        else if (hwinfo->bCanUseGPU)
-        {
-            md_print_warn(cr,fplog,
-                          "NOTE: GPU(s) found, but the current simulation can not use GPUs\n"
-                          "      To use a GPU, set the mdp option: cutoff-scheme = Verlet\n"
-                          "      (for quick performance testing you can use the -testverlet option)\n");
-
-            if (bForceUseGPU)
-            {
-                gmx_fatal(FARGS,"GPU requested, but can't be used without cutoff-scheme=Verlet");
-            }
-        }
-    }
-#ifndef GMX_THREAD_MPI
-    if (PAR(cr))
-    {
-        gmx_bcast_sim(sizeof(minf),&minf,cr);
-    }
-#endif
-    if (minf.bUseGPU && cr->npmenodes == -1)
-    {
-        /* Don't automatically use PME-only nodes with GPUs */
-        cr->npmenodes = 0;
-    }
-
-    /* Check for externally set OpenMP affinity and turn off internal
-     * pinning if any is found. We need to do this check early to tell
-     * thread-MPI whether it should do pinning when spawning threads.
-     */
-    gmx_omp_check_thread_affinity(fplog, cr, hw_opt);
-
-#ifdef GMX_THREAD_MPI
-    /* With thread-MPI inputrec is only set here on the master thread */
-    if (SIMMASTER(cr))
-#endif
-    {
-        check_and_update_hw_opt(hw_opt,minf.cutoff_scheme);
-
-#ifdef GMX_THREAD_MPI
-        /* Early check for externally set process affinity. Can't do over all
-         * MPI processes because hwinfo is not available everywhere, but with
-         * thread-MPI it's needed as pinning might get turned off which needs
-         * to be known before starting thread-MPI. */
-        check_cpu_affinity_set(fplog,
-                               NULL,
-                               hw_opt, hwinfo->nthreads_hw_avail, FALSE);
-#endif
-
-#ifdef GMX_THREAD_MPI
-        if (cr->npmenodes > 0 && hw_opt->nthreads_tmpi <= 0)
-        {
-            gmx_fatal(FARGS,"You need to explicitly specify the number of MPI threads (-ntmpi) when using separate PME nodes");
-        }
-#endif
-
-        if (hw_opt->nthreads_omp_pme != hw_opt->nthreads_omp &&
-            cr->npmenodes <= 0)
-        {
-            gmx_fatal(FARGS,"You need to explicitly specify the number of PME nodes (-npme) when using different number of OpenMP threads for PP and PME nodes");
-        }
-    }
-
-#ifdef GMX_THREAD_MPI
-    if (SIMMASTER(cr))
-    {
-        /* NOW the threads will be started: */
-        hw_opt->nthreads_tmpi = get_nthreads_mpi(hwinfo,
-                                                 hw_opt,
-                                                 inputrec, mtop,
-                                                 cr, fplog);
-        if (hw_opt->nthreads_tot > 0 && hw_opt->nthreads_omp <= 0)
-        {
-            hw_opt->nthreads_omp = hw_opt->nthreads_tot/hw_opt->nthreads_tmpi;
-        }
-
-        if (hw_opt->nthreads_tmpi > 1)
-        {
-            /* now start the threads. */
-            cr=mdrunner_start_threads(hw_opt, fplog, cr_old, nfile, fnm, 
-                                      oenv, bVerbose, bCompact, nstglobalcomm, 
-                                      ddxyz, dd_node_order, rdd, rconstr, 
-                                      dddlb_opt, dlb_scale, ddcsx, ddcsy, ddcsz,
-                                      nbpu_opt,
-                                      nsteps_cmdline, nstepout, resetstep, nmultisim, 
-                                      repl_ex_nst, repl_ex_nex, repl_ex_seed, pforce,
-                                      cpt_period, max_hours, deviceOptions, 
-                                      Flags);
-            /* the main thread continues here with a new cr. We don't deallocate
-               the old cr because other threads may still be reading it. */
-            if (cr == NULL)
-            {
-                gmx_comm("Failed to spawn threads");
-            }
-        }
-    }
-#endif
-    /* END OF CAUTION: cr is now reliable */
-
-    /* g_membed initialisation *
-     * Because we change the mtop, init_membed is called before the init_parallel *
-     * (in case we ever want to make it run in parallel) */
-    if (opt2bSet("-membed",nfile,fnm))
-    {
-        if (MASTER(cr))
-        {
-            fprintf(stderr,"Initializing membed");
-        }
-        membed = init_membed(fplog,nfile,fnm,mtop,inputrec,state,cr,&cpt_period);
-    }
-
-    if (PAR(cr))
-    {
-        /* now broadcast everything to the non-master nodes/threads: */
-        init_parallel(fplog, cr, inputrec, mtop);
-
-        /* This check needs to happen after get_nthreads_mpi() */
-        if (inputrec->cutoff_scheme == ecutsVERLET && (Flags & MD_PARTDEC))
-        {
-            gmx_fatal_collective(FARGS,cr,NULL,
-                                 "The Verlet cut-off scheme is not supported with particle decomposition.\n"
-                                 "You can achieve the same effect as particle decomposition by running in parallel using only OpenMP threads.");
-        }
-    }
-    if (fplog != NULL)
-    {
-        pr_inputrec(fplog,0,"Input Parameters",inputrec,FALSE);
-    }
-
-#if defined GMX_THREAD_MPI
-    /* With tMPI we detected on thread 0 and we'll just pass the hwinfo pointer
-     * to the other threads  -- slightly uncool, but works fine, just need to
-     * make sure that the data doesn't get freed twice. */
-    if (cr->nnodes > 1)
-    {
-        if (!SIMMASTER(cr))
-        {
-            snew(hwinfo, 1);
-        }
-        gmx_bcast(sizeof(&hwinfo), &hwinfo, cr);
-    }
-#else
-    if (PAR(cr) && !SIMMASTER(cr))
-    {
-        /* now we have inputrec on all nodes, can run the detection */
-        /* TODO: perhaps it's better to propagate within a node instead? */
-        snew(hwinfo, 1);
-        gmx_detect_hardware(fplog, hwinfo, cr,
-                                 bForceUseGPU, bTryUseGPU, hw_opt->gpu_id);
-    }
-
-    /* Now do the affinity check with MPI/no-MPI (done earlier with thread-MPI). */
-    check_cpu_affinity_set(fplog, cr,
-                           hw_opt, hwinfo->nthreads_hw_avail, FALSE);
-#endif
-
-    /* now make sure the state is initialized and propagated */
-    set_state_entries(state,inputrec,cr->nnodes);
-
-    /* remove when vv and rerun works correctly! */
-    if (PAR(cr) && EI_VV(inputrec->eI) && ((Flags & MD_RERUN) || (Flags & MD_RERUN_VSITE)))
-    {
-        gmx_fatal(FARGS,
-                  "Currently can't do velocity verlet with rerun in parallel.");
-    }
-
-    /* A parallel command line option consistency check that we can
-       only do after any threads have started. */
-    if (!PAR(cr) &&
-        (ddxyz[XX] > 1 || ddxyz[YY] > 1 || ddxyz[ZZ] > 1 || cr->npmenodes > 0))
-    {
-        gmx_fatal(FARGS,
-                  "The -dd or -npme option request a parallel simulation, "
-#ifndef GMX_MPI
-                  "but %s was compiled without threads or MPI enabled"
-#else
-#ifdef GMX_THREAD_MPI
-                  "but the number of threads (option -nt) is 1"
-#else
-                  "but %s was not started through mpirun/mpiexec or only one process was requested through mpirun/mpiexec"
-#endif
-#endif
-                  , ShortProgram()
-            );
-    }
-
-    if ((Flags & MD_RERUN) &&
-        (EI_ENERGY_MINIMIZATION(inputrec->eI) || eiNM == inputrec->eI))
-    {
-        gmx_fatal(FARGS, "The .mdp file specified an energy mininization or normal mode algorithm, and these are not compatible with mdrun -rerun");
-    }
-
-    if (can_use_allvsall(inputrec,mtop,TRUE,cr,fplog) && PAR(cr))
-    {
-        /* All-vs-all loops do not work with domain decomposition */
-        Flags |= MD_PARTDEC;
-    }
-
-    if (!EEL_PME(inputrec->coulombtype) || (Flags & MD_PARTDEC))
-    {
-        if (cr->npmenodes > 0)
-        {
-            if (!EEL_PME(inputrec->coulombtype))
-            {
-                gmx_fatal_collective(FARGS,cr,NULL,
-                                     "PME nodes are requested, but the system does not use PME electrostatics");
-            }
-            if (Flags & MD_PARTDEC)
-            {
-                gmx_fatal_collective(FARGS,cr,NULL,
-                                     "PME nodes are requested, but particle decomposition does not support separate PME nodes");
-            }
-        }
-
-        cr->npmenodes = 0;
-    }
-
-#ifdef GMX_FAHCORE
-    fcRegisterSteps(inputrec->nsteps,inputrec->init_step);
-#endif
-
-    /* NMR restraints must be initialized before load_checkpoint,
-     * since with time averaging the history is added to t_state.
-     * For proper consistency check we therefore need to extend
-     * t_state here.
-     * So the PME-only nodes (if present) will also initialize
-     * the distance restraints.
-     */
-    snew(fcd,1);
-
-    /* This needs to be called before read_checkpoint to extend the state */
-    init_disres(fplog,mtop,inputrec,cr,Flags & MD_PARTDEC,fcd,state);
-
-    if (gmx_mtop_ftype_count(mtop,F_ORIRES) > 0)
-    {
-        if (PAR(cr) && !(Flags & MD_PARTDEC))
-        {
-            gmx_fatal(FARGS,"Orientation restraints do not work (yet) with domain decomposition, use particle decomposition (mdrun option -pd)");
-        }
-        /* Orientation restraints */
-        if (MASTER(cr))
-        {
-            init_orires(fplog,mtop,state->x,inputrec,cr->ms,&(fcd->orires),
-                        state);
-        }
-    }
-
-    if (DEFORM(*inputrec))
-    {
-        /* Store the deform reference box before reading the checkpoint */
-        if (SIMMASTER(cr))
-        {
-            copy_mat(state->box,box);
-        }
-        if (PAR(cr))
-        {
-            gmx_bcast(sizeof(box),box,cr);
-        }
-        /* Because we do not have the update struct available yet
-         * in which the reference values should be stored,
-         * we store them temporarily in static variables.
-         * This should be thread safe, since they are only written once
-         * and with identical values.
-         */
-#ifdef GMX_THREAD_MPI
-        tMPI_Thread_mutex_lock(&deform_init_box_mutex);
-#endif
-        deform_init_init_step_tpx = inputrec->init_step;
-        copy_mat(box,deform_init_box_tpx);
-#ifdef GMX_THREAD_MPI
-        tMPI_Thread_mutex_unlock(&deform_init_box_mutex);
-#endif
-    }
-
-    if (opt2bSet("-cpi",nfile,fnm)) 
-    {
-        /* Check if checkpoint file exists before doing continuation.
-         * This way we can use identical input options for the first and subsequent runs...
-         */
-        if( gmx_fexist_master(opt2fn_master("-cpi",nfile,fnm,cr),cr) )
-        {
-            load_checkpoint(opt2fn_master("-cpi",nfile,fnm,cr),&fplog,
-                            cr,Flags & MD_PARTDEC,ddxyz,
-                            inputrec,state,&bReadRNG,&bReadEkin,
-                            (Flags & MD_APPENDFILES),
-                            (Flags & MD_APPENDFILESSET));
-            
-            if (bReadRNG)
-            {
-                Flags |= MD_READ_RNG;
-            }
-            if (bReadEkin)
-            {
-                Flags |= MD_READ_EKIN;
-            }
-        }
-    }
-
-    if (((MASTER(cr) || (Flags & MD_SEPPOT)) && (Flags & MD_APPENDFILES))
-#ifdef GMX_THREAD_MPI
-        /* With thread MPI only the master node/thread exists in mdrun.c,
-         * therefore non-master nodes need to open the "seppot" log file here.
-         */
-        || (!MASTER(cr) && (Flags & MD_SEPPOT))
-#endif
-        )
-    {
-        gmx_log_open(ftp2fn(efLOG,nfile,fnm),cr,!(Flags & MD_SEPPOT),
-                             Flags,&fplog);
-    }
-
-    /* override nsteps with value from cmdline */
-    override_nsteps_cmdline(fplog, nsteps_cmdline, inputrec, cr);
-
-    if (SIMMASTER(cr)) 
-    {
-        copy_mat(state->box,box);
-    }
-
-    if (PAR(cr)) 
-    {
-        gmx_bcast(sizeof(box),box,cr);
-    }
-
-    /* Essential dynamics */
-    if (opt2bSet("-ei",nfile,fnm))
-    {
-        /* Open input and output files, allocate space for ED data structure */
-        ed = ed_open(nfile,fnm,Flags,cr);
-    }
-
-    if (PAR(cr) && !((Flags & MD_PARTDEC) ||
-                     EI_TPI(inputrec->eI) ||
-                     inputrec->eI == eiNM))
-    {
-        cr->dd = init_domain_decomposition(fplog,cr,Flags,ddxyz,rdd,rconstr,
-                                           dddlb_opt,dlb_scale,
-                                           ddcsx,ddcsy,ddcsz,
-                                           mtop,inputrec,
-                                           box,state->x,
-                                           &ddbox,&npme_major,&npme_minor);
-
-        make_dd_communicators(fplog,cr,dd_node_order);
-
-        /* Set overallocation to avoid frequent reallocation of arrays */
-        set_over_alloc_dd(TRUE);
-    }
-    else
-    {
-        /* PME, if used, is done on all nodes with 1D decomposition */
-        cr->npmenodes = 0;
-        cr->duty = (DUTY_PP | DUTY_PME);
-        npme_major = 1;
-        npme_minor = 1;
-        if (!EI_TPI(inputrec->eI))
-        {
-            npme_major = cr->nnodes;
-        }
-        
-        if (inputrec->ePBC == epbcSCREW)
-        {
-            gmx_fatal(FARGS,
-                      "pbc=%s is only implemented with domain decomposition",
-                      epbc_names[inputrec->ePBC]);
-        }
-    }
-
-    if (PAR(cr))
-    {
-        /* After possible communicator splitting in make_dd_communicators.
-         * we can set up the intra/inter node communication.
-         */
-        gmx_setup_nodecomm(fplog,cr);
-    }
-
-    /* Initialize per-physical-node MPI process/thread ID and counters. */
-    gmx_init_intranode_counters(cr);
-
-#ifdef GMX_MPI
-    md_print_info(cr,fplog,"Using %d MPI %s\n",
-                  cr->nnodes,
-#ifdef GMX_THREAD_MPI
-                  cr->nnodes==1 ? "thread" : "threads"
-#else
-                  cr->nnodes==1 ? "process" : "processes"
-#endif
-                  );
-    fflush(stderr);
-#endif
-
-    gmx_omp_nthreads_init(fplog, cr,
-                          hwinfo->nthreads_hw_avail,
-                          hw_opt->nthreads_omp,
-                          hw_opt->nthreads_omp_pme,
-                          (cr->duty & DUTY_PP) == 0,
-                          inputrec->cutoff_scheme == ecutsVERLET);
-
-    gmx_check_hw_runconf_consistency(fplog, hwinfo, cr, hw_opt->nthreads_tmpi, minf.bUseGPU);
-
-    /* getting number of PP/PME threads
-       PME: env variable should be read only on one node to make sure it is 
-       identical everywhere;
-     */
-    /* TODO nthreads_pp is only used for pinning threads.
-     * This is a temporary solution until we have a hw topology library.
-     */
-    nthreads_pp  = gmx_omp_nthreads_get(emntNonbonded);
-    nthreads_pme = gmx_omp_nthreads_get(emntPME);
-
-    wcycle = wallcycle_init(fplog,resetstep,cr,nthreads_pp,nthreads_pme);
-
-    if (PAR(cr))
-    {
-        /* Master synchronizes its value of reset_counters with all nodes 
-         * including PME only nodes */
-        reset_counters = wcycle_get_reset_counters(wcycle);
-        gmx_bcast_sim(sizeof(reset_counters),&reset_counters,cr);
-        wcycle_set_reset_counters(wcycle, reset_counters);
-    }
-
-    snew(nrnb,1);
-    if (cr->duty & DUTY_PP)
-    {
-        /* For domain decomposition we allocate dynamically
-         * in dd_partition_system.
-         */
-        if (DOMAINDECOMP(cr))
-        {
-            bcast_state_setup(cr,state);
-        }
-        else
-        {
-            if (PAR(cr))
-            {
-                bcast_state(cr,state,TRUE);
-            }
-        }
-
-        /* Initiate forcerecord */
-        fr = mk_forcerec();
-        fr->hwinfo = hwinfo;
-        init_forcerec(fplog,oenv,fr,fcd,inputrec,mtop,cr,box,FALSE,
-                      opt2fn("-table",nfile,fnm),
-                      opt2fn("-tabletf",nfile,fnm),
-                      opt2fn("-tablep",nfile,fnm),
-                      opt2fn("-tableb",nfile,fnm),
-                      nbpu_opt,
-                      FALSE,pforce);
-
-        /* version for PCA_NOT_READ_NODE (see md.c) */
-        /*init_forcerec(fplog,fr,fcd,inputrec,mtop,cr,box,FALSE,
-          "nofile","nofile","nofile","nofile",FALSE,pforce);
-          */        
-        fr->bSepDVDL = ((Flags & MD_SEPPOT) == MD_SEPPOT);
-
-        /* Initialize QM-MM */
-        if(fr->bQMMM)
-        {
-            init_QMMMrec(cr,box,mtop,inputrec,fr);
-        }
-
-        /* Initialize the mdatoms structure.
-         * mdatoms is not filled with atom data,
-         * as this can not be done now with domain decomposition.
-         */
-        mdatoms = init_mdatoms(fplog,mtop,inputrec->efep!=efepNO);
-
-        /* Initialize the virtual site communication */
-        vsite = init_vsite(mtop,cr,FALSE);
-
-        calc_shifts(box,fr->shift_vec);
-
-        /* With periodic molecules the charge groups should be whole at start up
-         * and the virtual sites should not be far from their proper positions.
-         */
-        if (!inputrec->bContinuation && MASTER(cr) &&
-            !(inputrec->ePBC != epbcNONE && inputrec->bPeriodicMols))
-        {
-            /* Make molecules whole at start of run */
-            if (fr->ePBC != epbcNONE)
-            {
-                do_pbc_first_mtop(fplog,inputrec->ePBC,box,mtop,state->x);
-            }
-            if (vsite)
-            {
-                /* Correct initial vsite positions are required
-                 * for the initial distribution in the domain decomposition
-                 * and for the initial shell prediction.
-                 */
-                construct_vsites_mtop(fplog,vsite,mtop,state->x);
-            }
-        }
-
-        if (EEL_PME(fr->eeltype))
-        {
-            ewaldcoeff = fr->ewaldcoeff;
-            pmedata = &fr->pmedata;
-        }
-        else
-        {
-            pmedata = NULL;
-        }
-    }
-    else
-    {
-        /* This is a PME only node */
-
-        /* We don't need the state */
-        done_state(state);
-
-        ewaldcoeff = calc_ewaldcoeff(inputrec->rcoulomb, inputrec->ewald_rtol);
-        snew(pmedata,1);
-    }
-
-    /* Before setting affinity, check whether the affinity has changed
-     * - which indicates that probably the OpenMP library has changed it since
-     * we first checked). */
-    check_cpu_affinity_set(fplog, cr, hw_opt, hwinfo->nthreads_hw_avail, TRUE);
-
-    /* Set the CPU affinity */
-    set_cpu_affinity(fplog,cr,hw_opt,nthreads_pme,hwinfo,inputrec);
-
-    /* Initiate PME if necessary,
-     * either on all nodes or on dedicated PME nodes only. */
-    if (EEL_PME(inputrec->coulombtype))
-    {
-        if (mdatoms)
-        {
-            nChargePerturbed = mdatoms->nChargePerturbed;
-        }
-        if (cr->npmenodes > 0)
-        {
-            /* The PME only nodes need to know nChargePerturbed */
-            gmx_bcast_sim(sizeof(nChargePerturbed),&nChargePerturbed,cr);
-        }
-
-        if (cr->duty & DUTY_PME)
-        {
-            status = gmx_pme_init(pmedata,cr,npme_major,npme_minor,inputrec,
-                                  mtop ? mtop->natoms : 0,nChargePerturbed,
-                                  (Flags & MD_REPRODUCIBLE),nthreads_pme);
-            if (status != 0) 
-            {
-                gmx_fatal(FARGS,"Error %d initializing PME",status);
-            }
-        }
-    }
-
-
-    if (integrator[inputrec->eI].func == do_md
-        ||
-        integrator[inputrec->eI].func == do_md_openmm
-        )
-    {
-        /* Turn on signal handling on all nodes */
-        /*
-         * (A user signal from the PME nodes (if any)
-         * is communicated to the PP nodes.
-         */
-        signal_handler_install();
-    }
-
-    if (cr->duty & DUTY_PP)
-    {
-        if (inputrec->ePull != epullNO)
-        {
-            /* Initialize pull code */
-            init_pull(fplog,inputrec,nfile,fnm,mtop,cr,oenv, inputrec->fepvals->init_lambda,
-                      EI_DYNAMICS(inputrec->eI) && MASTER(cr),Flags);
-        }
-        
-        if (inputrec->bRot)
-        {
-           /* Initialize enforced rotation code */
-           init_rot(fplog,inputrec,nfile,fnm,cr,state->x,box,mtop,oenv,
-                    bVerbose,Flags);
-        }
-
-        constr = init_constraints(fplog,mtop,inputrec,ed,state,cr);
-
-        if (DOMAINDECOMP(cr))
-        {
-            dd_init_bondeds(fplog,cr->dd,mtop,vsite,constr,inputrec,
-                            Flags & MD_DDBONDCHECK,fr->cginfo_mb);
-
-            set_dd_parameters(fplog,cr->dd,dlb_scale,inputrec,fr,&ddbox);
-
-            setup_dd_grid(fplog,cr->dd);
-        }
-
-        /* Now do whatever the user wants us to do (how flexible...) */
-        integrator[inputrec->eI].func(fplog,cr,nfile,fnm,
-                                      oenv,bVerbose,bCompact,
-                                      nstglobalcomm,
-                                      vsite,constr,
-                                      nstepout,inputrec,mtop,
-                                      fcd,state,
-                                      mdatoms,nrnb,wcycle,ed,fr,
-                                      repl_ex_nst,repl_ex_nex,repl_ex_seed,
-                                      membed,
-                                      cpt_period,max_hours,
-                                      deviceOptions,
-                                      Flags,
-                                      &runtime);
-
-        if (inputrec->ePull != epullNO)
-        {
-            finish_pull(fplog,inputrec->pull);
-        }
-        
-        if (inputrec->bRot)
-        {
-            finish_rot(inputrec->rot);
-        }
-
-    } 
-    else 
-    {
-        /* do PME only */
-        gmx_pmeonly(*pmedata,cr,nrnb,wcycle,ewaldcoeff,FALSE,inputrec);
-    }
-
-    if (EI_DYNAMICS(inputrec->eI) || EI_TPI(inputrec->eI))
-    {
-        /* Some timing stats */  
-        if (SIMMASTER(cr))
-        {
-            if (runtime.proc == 0)
-            {
-                runtime.proc = runtime.real;
-            }
-        }
-        else
-        {
-            runtime.real = 0;
-        }
-    }
-
-    wallcycle_stop(wcycle,ewcRUN);
-
-    /* Finish up, write some stuff
-     * if rerunMD, don't write last frame again 
-     */
-    finish_run(fplog,cr,ftp2fn(efSTO,nfile,fnm),
-               inputrec,nrnb,wcycle,&runtime,
-               fr != NULL && fr->nbv != NULL && fr->nbv->bUseGPU ?
-                 nbnxn_cuda_get_timings(fr->nbv->cu_nbv) : NULL,
-               nthreads_pp, 
-               EI_DYNAMICS(inputrec->eI) && !MULTISIM(cr));
-
-    if ((cr->duty & DUTY_PP) && fr->nbv != NULL && fr->nbv->bUseGPU)
-    {
-        char gpu_err_str[STRLEN];
-
-        /* free GPU memory and uninitialize GPU (by destroying the context) */
-        nbnxn_cuda_free(fplog, fr->nbv->cu_nbv);
-
-        if (!free_gpu(gpu_err_str))
-        {
-            gmx_warning("On node %d failed to free GPU #%d: %s",
-                        cr->nodeid, get_current_gpu_device_id(), gpu_err_str);
-        }
-    }
-
-    if (opt2bSet("-membed",nfile,fnm))
-    {
-        sfree(membed);
-    }
-
-#ifdef GMX_THREAD_MPI
-    if (PAR(cr) && SIMMASTER(cr))
-#endif
-    {
-        gmx_hardware_info_free(hwinfo);
-    }
-
-    /* Does what it says */  
-    print_date_and_time(fplog,cr->nodeid,"Finished mdrun",&runtime);
-
-    /* Close logfile already here if we were appending to it */
-    if (MASTER(cr) && (Flags & MD_APPENDFILES))
-    {
-        gmx_log_close(fplog);
-    }  
-
-    rc=(int)gmx_get_stop_condition();
-
-#ifdef GMX_THREAD_MPI
-    /* we need to join all threads. The sub-threads join when they
-       exit this function, but the master thread needs to be told to 
-       wait for that. */
-    if (PAR(cr) && MASTER(cr))
-    {
-        tMPI_Finalize();
-    }
-#endif
-
-    return rc;
-}
index 2ef54e21f33423ee7629c41be2f8d4eb4c21db2e..301665f0a18fd44db3b1446d312f4077752665b2 100644 (file)
@@ -71,13 +71,26 @@ class AbstractAnalysisData::Impl
 
         Impl();
 
+        //! Returns whether any data set has more than one column.
+        bool isMultiColumn() const;
+
+        /*! \brief
+         * Checks whether a module is compatible with the data properties.
+         *
+         * \param[in] module Module to check.
+         * \throws    APIError if \p module is not compatible with the data.
+         *
+         * Does not check the actual data (e.g., missing values), but only the
+         * dimensionality and other preset properties of the data.
+         */
+        void checkModuleProperties(const AnalysisDataModuleInterface &module) const;
+
         /*! \brief
          * Present data already added to the data object to a module.
          *
          * \param[in] data   Data object to read data from.
          * \param[in] module Module to present the data to.
-         * \throws    APIError if \p module is not compatible with the data
-         *      object.
+         * \throws    APIError if \p module is not compatible with the data.
          * \throws    APIError if all data is not available through
          *      getDataFrame().
          * \throws    unspecified Any exception thrown by \p module in its data
@@ -90,6 +103,10 @@ class AbstractAnalysisData::Impl
         void presentData(AbstractAnalysisData        *data,
                          AnalysisDataModuleInterface *module);
 
+        //! Column counts for each data set in the data.
+        std::vector<int>        columnCounts_;
+        //! Whether the data is multipoint.
+        bool                    bMultipoint_;
         //! List of modules added to the data.
         ModuleList              modules_;
         //! true if all modules support missing data.
@@ -111,10 +128,45 @@ class AbstractAnalysisData::Impl
 };
 
 AbstractAnalysisData::Impl::Impl()
-    : bAllowMissing_(true), bDataStart_(false), bInData_(false), bInFrame_(false),
+    : bMultipoint_(false), bAllowMissing_(true),
+      bDataStart_(false), bInData_(false), bInFrame_(false),
       currIndex_(-1), nframes_(0)
 {
+    columnCounts_.push_back(0);
+}
+
+bool
+AbstractAnalysisData::Impl::isMultiColumn() const
+{
+    std::vector<int>::const_iterator i;
+    for (i = columnCounts_.begin(); i != columnCounts_.end(); ++i)
+    {
+        if (*i > 1)
+        {
+            return true;
+        }
+    }
+    return false;
+}
+
+//! Helper macro for testing module flags.
+#define TEST_MODULE_FLAG(flags, flagname) \
+    ((flags) & AnalysisDataModuleInterface::flagname)
+void
+AbstractAnalysisData::Impl::checkModuleProperties(
+        const AnalysisDataModuleInterface &module) const
+{
+    const int flags = module.flags();
+    if ((!TEST_MODULE_FLAG(flags, efAllowMulticolumn) && isMultiColumn()) ||
+        (!TEST_MODULE_FLAG(flags, efAllowMultipoint)  && bMultipoint_) ||
+        ( TEST_MODULE_FLAG(flags, efOnlyMultipoint)   && !bMultipoint_) ||
+        (!TEST_MODULE_FLAG(flags, efAllowMultipleDataSets)
+         && columnCounts_.size() > 1U))
+    {
+        GMX_THROW(APIError("Data module not compatible with data object properties"));
+    }
 }
+#undef TEST_MODULE_FLAGS
 
 void
 AbstractAnalysisData::Impl::presentData(AbstractAnalysisData        *data,
@@ -152,7 +204,7 @@ AbstractAnalysisData::Impl::presentData(AbstractAnalysisData        *data,
  */
 /*! \cond libapi */
 AbstractAnalysisData::AbstractAnalysisData()
-    : impl_(new Impl()), columnCount_(0), bMultiPoint_(false)
+    : impl_(new Impl())
 {
 }
 //! \endcond
@@ -161,6 +213,33 @@ AbstractAnalysisData::~AbstractAnalysisData()
 {
 }
 
+bool
+AbstractAnalysisData::isMultipoint() const
+{
+    return impl_->bMultipoint_;
+}
+
+int
+AbstractAnalysisData::dataSetCount() const
+{
+    return impl_->columnCounts_.size();
+}
+
+int
+AbstractAnalysisData::columnCount(int dataSet) const
+{
+    GMX_ASSERT(dataSet >= 0 && dataSet < dataSetCount(),
+               "Out of range data set index");
+    return impl_->columnCounts_[dataSet];
+}
+
+int
+AbstractAnalysisData::columnCount() const
+{
+    GMX_ASSERT(dataSetCount() == 1,
+               "Convenience method not available for multiple data sets");
+    return columnCount(0);
+}
 
 int
 AbstractAnalysisData::frameCount() const
@@ -207,12 +286,7 @@ AbstractAnalysisData::requestStorage(int nframes)
 void
 AbstractAnalysisData::addModule(AnalysisDataModulePointer module)
 {
-    if ((columnCount() > 1 && !(module->flags() & AnalysisDataModuleInterface::efAllowMulticolumn))
-        || (isMultipoint() && !(module->flags() & AnalysisDataModuleInterface::efAllowMultipoint))
-        || (!isMultipoint() && (module->flags() & AnalysisDataModuleInterface::efOnlyMultipoint)))
-    {
-        GMX_THROW(APIError("Data module not compatible with data object properties"));
-    }
+    impl_->checkModuleProperties(*module);
 
     if (impl_->bDataStart_)
     {
@@ -232,7 +306,7 @@ void
 AbstractAnalysisData::addColumnModule(int col, int span,
                                       AnalysisDataModulePointer module)
 {
-    GMX_RELEASE_ASSERT(col >= 0 && span >= 1 && col + span <= columnCount_,
+    GMX_RELEASE_ASSERT(col >= 0 && span >= 1,
                        "Invalid columns specified for a column module");
     if (impl_->bDataStart_)
     {
@@ -249,12 +323,7 @@ AbstractAnalysisData::addColumnModule(int col, int span,
 void
 AbstractAnalysisData::applyModule(AnalysisDataModuleInterface *module)
 {
-    if ((columnCount() > 1 && !(module->flags() & AnalysisDataModuleInterface::efAllowMulticolumn))
-        || (isMultipoint() && !(module->flags() & AnalysisDataModuleInterface::efAllowMultipoint))
-        || (!isMultipoint() && (module->flags() & AnalysisDataModuleInterface::efOnlyMultipoint)))
-    {
-        GMX_THROW(APIError("Data module not compatible with data object properties"));
-    }
+    impl_->checkModuleProperties(*module);
     GMX_RELEASE_ASSERT(impl_->bDataStart_ && !impl_->bInData_,
                        "Data module can only be applied to ready data");
 
@@ -263,25 +332,31 @@ AbstractAnalysisData::applyModule(AnalysisDataModuleInterface *module)
 
 /*! \cond libapi */
 void
-AbstractAnalysisData::setColumnCount(int columnCount)
+AbstractAnalysisData::setDataSetCount(int dataSetCount)
 {
+    GMX_RELEASE_ASSERT(dataSetCount > 0, "Invalid data column count");
+    GMX_RELEASE_ASSERT(!impl_->bDataStart_,
+                       "Data set count cannot be changed after data has been added");
+    impl_->columnCounts_.resize(dataSetCount);
+}
+
+void
+AbstractAnalysisData::setColumnCount(int dataSet, int columnCount)
+{
+    GMX_RELEASE_ASSERT(dataSet >= 0 && dataSet < dataSetCount(),
+                       "Out of range data set index");
     GMX_RELEASE_ASSERT(columnCount > 0, "Invalid data column count");
-    GMX_RELEASE_ASSERT(columnCount_ == 0 || impl_->modules_.empty(),
-                       "Data column count cannot be changed after modules are added");
     GMX_RELEASE_ASSERT(!impl_->bDataStart_,
                        "Data column count cannot be changed after data has been added");
-    columnCount_ = columnCount;
+    impl_->columnCounts_[dataSet] = columnCount;
 }
 
-
 void
 AbstractAnalysisData::setMultipoint(bool multipoint)
 {
-    GMX_RELEASE_ASSERT(impl_->modules_.empty(),
-                       "Data type cannot be changed after modules are added");
     GMX_RELEASE_ASSERT(!impl_->bDataStart_,
                        "Data type cannot be changed after data has been added");
-    bMultiPoint_ = multipoint;
+    impl_->bMultipoint_ = multipoint;
 }
 
 
@@ -294,16 +369,17 @@ AbstractAnalysisData::notifyDataStart()
 {
     GMX_RELEASE_ASSERT(!impl_->bDataStart_,
                        "notifyDataStart() called more than once");
-    GMX_RELEASE_ASSERT(columnCount_ > 0, "Data column count is not set");
+    for (int d = 0; d < dataSetCount(); ++d)
+    {
+        GMX_RELEASE_ASSERT(columnCount(d) > 0,
+                           "Data column count is not set");
+    }
     impl_->bDataStart_ = impl_->bInData_ = true;
 
     Impl::ModuleList::const_iterator i;
     for (i = impl_->modules_.begin(); i != impl_->modules_.end(); ++i)
     {
-        if (columnCount_ > 1 && !((*i)->flags() & AnalysisDataModuleInterface::efAllowMulticolumn))
-        {
-            GMX_THROW(APIError("Data module not compatible with data object properties"));
-        }
+        impl_->checkModuleProperties(**i);
         (*i)->dataStarted(this);
     }
 }
@@ -333,7 +409,8 @@ AbstractAnalysisData::notifyPointsAdd(const AnalysisDataPointSetRef &points) con
 {
     GMX_ASSERT(impl_->bInData_, "notifyDataStart() not called");
     GMX_ASSERT(impl_->bInFrame_, "notifyFrameStart() not called");
-    GMX_ASSERT(points.lastColumn() < columnCount(), "Invalid columns");
+    GMX_ASSERT(points.lastColumn() < columnCount(points.dataSetIndex()),
+               "Invalid columns");
     GMX_ASSERT(points.frameIndex() == impl_->currIndex_,
                "Points do not correspond to current frame");
     if (!impl_->bAllowMissing_ && !points.allPresent())
index ea0ff3041a52e228ffffb75ed06bd31ad173c5b5..3a9a8de7ecf2c9fc59527a87b7decce399a4fe63 100644 (file)
@@ -65,9 +65,9 @@ typedef boost::shared_ptr<AnalysisDataModuleInterface> AnalysisDataModulePointer
  * Abstract base class for all objects that provide data.
  *
  * The public interface includes methods for querying the data (isMultipoint(),
- * columnCount(), frameCount(), tryGetDataFrame(), getDataFrame(),
- * requestStorage()) and methods for using modules for processing the data
- * (addModule(), addColumnModule(), applyModule()).
+ * dataSetCount(), columnCount(), frameCount(), tryGetDataFrame(),
+ * getDataFrame(), requestStorage()) and methods for using modules for
+ * processing the data (addModule(), addColumnModule(), applyModule()).
  *
  * Notice that even for non-const objects, the interface does not provide any
  * means of altering the data.  It is only possible to add modules, making it
@@ -77,9 +77,10 @@ typedef boost::shared_ptr<AnalysisDataModuleInterface> AnalysisDataModulePointer
  *
  * \if libapi
  * This class also provides protected methods for use in derived classes.
- * The properties returned by isMultipoint() and columnCount() must be set using
- * setMultipoint() and setColumnCount(), and notify*() methods must be used to
- * report when data becomes available for modules to process it.
+ * The properties returned by isMultipoint(), dataSetCount(), and columnCount()
+ * must be set using setMultipoint(), setDataSetCount(), and setColumnCount(),
+ * and notify*() methods must be used to report when data becomes available for
+ * modules to process it.
  * There are also two protected pure virtual methods that need to be
  * implemented to provide access to stored data: requestStorageInternal() and
  * tryGetDataFrameInternal().
@@ -135,13 +136,31 @@ class AbstractAnalysisData
          *
          * Does not throw.
          */
-        bool isMultipoint() const { return bMultiPoint_; }
+        bool isMultipoint() const;
         /*! \brief
-         * Returns the number of columns in the data.
+         * Returns the number of data sets in the data object.
+         *
+         * \returns The number of data sets in the data.
+         *
+         * If the number is not yet known, returns 0.
+         * The returned value does not change after modules have been notified
+         * of data start, but may change multiple times before that, depending
+         * on the actual data class.
+         * \if libapi
+         * Derived classes should set the number of columns with
+         * setDataSetCount(), within the above limitations.
+         * \endif
          *
+         * Does not throw.
+         */
+        int dataSetCount() const;
+        /*! \brief
+         * Returns the number of columns in a data set.
+         *
+         * \param[in] dataSet Zero-based index of the data set to query.
          * \returns The number of columns in the data.
          *
-         * If the number of columns is yet known, returns 0.
+         * If the number of columns is not yet known, returns 0.
          * The returned value does not change after modules have been notified
          * of data start, but may change multiple times before that, depending
          * on the actual data class.
@@ -152,7 +171,20 @@ class AbstractAnalysisData
          *
          * Does not throw.
          */
-        int columnCount() const { return columnCount_; }
+        int columnCount(int dataSet) const;
+        /*! \brief
+         * Returns the number of columns in the data.
+         *
+         * \returns The number of columns in the data.
+         *
+         * This is a convenience method for data objects with a single data set.
+         * Can only be called if dataSetCount() == 1.
+         *
+         * Does not throw.
+         *
+         * \see columnCount(int)
+         */
+        int columnCount() const;
         /*! \brief
          * Returns the total number of frames in the data.
          *
@@ -239,10 +271,17 @@ class AbstractAnalysisData
          * \param     module  Module to add.
          * \throws    APIError in same situations as addModule().
          *
+         * Currently, all data sets are filtered using the same column mask.
+         *
          * \todo
          * This method doesn't currently work in all cases with multipoint
-         * data.  In particular, if the added module requests storage and uses
-         * getDataFrame(), it will behave unpredictably (most likely asserts).
+         * data or with multiple data sets.  In particular, if the added module
+         * requests storage and uses getDataFrame(), it will behave
+         * unpredictably (most likely asserts).
+         *
+         * \todo
+         * Generalize this method to multiple data sets (e.g., for adding
+         * modules that only process a single data set).
          *
          * \see addModule()
          */
@@ -277,33 +316,52 @@ class AbstractAnalysisData
         AbstractAnalysisData();
 
         /*! \brief
-         * Sets the number of columns.
+         * Sets the number of data sets.
+         *
+         * \param[in] dataSetCount  Number of data sets (must be > 0).
+         *
+         * It not called, the data object has a single data set.
+         * Can be called only before notifyDataStart().
+         * Multiple calls are allowed before that point; the last call takes
+         * effect.
+         *
+         * Does not throw, but this may change with the todo item in
+         * setColumnCount().
+         *
+         * \see dataSetCount()
+         */
+        void setDataSetCount(int dataSetCount);
+        /*! \brief
+         * Sets the number of columns for a data set.
          *
-         * \param[in] columnCount  Number of columns in the data (must be > 0).
+         * \param[in] dataSet      Zero-based index of the data set.
+         * \param[in] columnCount  Number of columns in \p dataSet (must be > 0).
          *
-         * Can be called only before notifyDataStart(), otherwise asserts.
-         * Multiple calls are only allowed if all of them occur before
-         * addModule() has been called, otherwise asserts (a single call
-         * can occur after addModule() if no calls have been made earlier).
+         * Must be called at least once before notifyDataStart() for each data
+         * set.
+         * Can be called only before notifyDataStart().
+         * Multiple calls are allowed before that point; the last call takes
+         * effect.
          *
          * Does not throw, but this may change with the below todo item.
          *
          * \todo
-         * Consider whether the semantics with respect to addModule() and
-         * notifyDataStart(), and the performed checks, are suitable for all
-         * purposes.
+         * Consider whether the call should check the modules that have already
+         * been added (currently it is only done in notifyDataStart()).
          *
          * \see columnCount()
          */
-        void setColumnCount(int columnCount);
+        void setColumnCount(int dataSet, int columnCount);
         /*! \brief
          * Sets whether the data has multiple points per column in a frame.
          *
          * \param[in] multipoint  Whether multiple points per column are
          *     possible.
          *
-         * Can be called only before addModule() or notifyDataStart(),
-         * otherwise asserts.
+         * If not called, only a single point per column is allowed.
+         * Can be called only before notifyDataStart().
+         * Multiple calls are allowed before that point; the last call takes
+         * effect.
          *
          * Does not throw, but this may change with the todo item in
          * setColumnCount().
@@ -425,8 +483,6 @@ class AbstractAnalysisData
         class Impl;
 
         PrivateImplPointer<Impl> impl_;
-        int                      columnCount_;
-        bool                     bMultiPoint_;
 
         /*! \brief
          * Needed to provide access to notification methods.
index 2ec211576956197d42a54203e8e5aacbf1c32937..105a7b59fe1cb23b992e72388145447bc8ba0bd5 100644 (file)
@@ -125,12 +125,20 @@ AnalysisData::~AnalysisData()
 
 
 void
-AnalysisData::setColumnCount(int ncol)
+AnalysisData::setDataSetCount(int dataSetCount)
 {
-    GMX_RELEASE_ASSERT(ncol > 0, "Number of columns must be positive");
     GMX_RELEASE_ASSERT(impl_->handles_.empty(),
                        "Cannot change data dimensionality after creating handles");
-    AbstractAnalysisData::setColumnCount(ncol);
+    AbstractAnalysisData::setDataSetCount(dataSetCount);
+}
+
+
+void
+AnalysisData::setColumnCount(int dataSet, int columnCount)
+{
+    GMX_RELEASE_ASSERT(impl_->handles_.empty(),
+                       "Cannot change data dimensionality after creating handles");
+    AbstractAnalysisData::setColumnCount(dataSet, columnCount);
 }
 
 
@@ -226,6 +234,16 @@ AnalysisDataHandle::startFrame(int index, real x, real dx)
 }
 
 
+void
+AnalysisDataHandle::selectDataSet(int index)
+{
+    GMX_RELEASE_ASSERT(impl_ != NULL, "Invalid data handle used");
+    GMX_RELEASE_ASSERT(impl_->currentFrame_ != NULL,
+                       "selectDataSet() called without calling startFrame()");
+    impl_->currentFrame_->selectDataSet(index);
+}
+
+
 void
 AnalysisDataHandle::setPoint(int column, real value, bool bPresent)
 {
index bb5f570e0cd878305d5289064cba18c5a2918d57..451cee4a598b74e37def4d65d150258c7ce08e1e 100644 (file)
@@ -56,8 +56,8 @@ class AnalysisDataParallelOptions;
  *
  * This is the main class used to implement parallelizable data processing in
  * analysis tools.  It is used by first creating an object and setting its
- * properties using setColumnCount() and setMultipoint(), and attaching
- * necessary modules using addModule() etc.  Then one or more
+ * properties using setDataSetCount(), setColumnCount() and setMultipoint(),
+ * and attaching necessary modules using addModule() etc.  Then one or more
  * AnalysisDataHandle objects can be created using startData().  Each data
  * handle can then be independently used to provide data frames (each frame
  * must be provided by a single handle, but different frames can be freely
@@ -96,18 +96,32 @@ class AnalysisData : public AbstractAnalysisData
         virtual ~AnalysisData();
 
         /*! \brief
-         * Sets the number of columns in the data.
+         * Sets the number of data sets.
          *
-         * \param[in] ncol  Number of columns in the data (must be > 0).
+         * \param[in] dataSetCount  Number of data sets (must be > 0).
          *
-         * Must be called before startData(), and can be called multiple times
-         * before modules are added.
          * Must not be called after startData() has been called.
+         * If not called, a single data set is assumed.
+         * If called multiple times, the last call takes effect.
          *
          * Does not currently throw, but this may change for the case that
          * modules have already been added.
          */
-        void setColumnCount(int ncol);
+        void setDataSetCount(int dataSetCount);
+        /*! \brief
+         * Sets the number of columns in a data set.
+         *
+         * \param[in] dataSet      Zero-based data set index.
+         * \param[in] columnCount  Number of columns in the data (must be > 0).
+         *
+         * Must be called before startData() for each data set.
+         * Must not be called after startData() has been called.
+         * If called multiple times for a data set, the last call takes effect.
+         *
+         * Does not currently throw, but this may change for the case that
+         * modules have already been added.
+         */
+        void setColumnCount(int dataSet, int columnCount);
         /*! \brief
          * Sets whether the data contains multiple points per column per frame.
          *
@@ -116,8 +130,7 @@ class AnalysisData : public AbstractAnalysisData
          *
          * If this method is not called, the data is not multipoint.
          *
-         * Must not be called after modules have been added or startData() has
-         * been called.
+         * Must not be called after startData() has been called.
          *
          * Does not currently throw, but this may change for the case that
          * modules have already been added.
@@ -190,15 +203,18 @@ class AnalysisDataHandleImpl;
  * called.
  *
  * For simple (non-multipoint) data, within a frame values can be set using
- * setPoint() and setPoints().  Setting the same column multiple times
- * overrides previously set values.  When the frame is finished, attached
- * modules are notified.
+ * selectDataSet(), setPoint() and setPoints().  Setting the same column in the
+ * same data set multiple times overrides previously set values.
+ * When the frame is finished, attached modules are notified.
  *
  * Multipoint data works otherwise similarly, but requires finishPointSet() to
  * be called for each set of points for which the modules need to be notified.
  * Each point set starts empty (after startFrame() or finishPointSet()), and
- * values can be set using setPoint()/setPoints().  finishPointSet() must also
- * be called for the last point set just before finishFrame().
+ * values can be set using setPoint()/setPoints().
+ * A single point set can contain values only for a single data set, which must
+ * be selected with selectDataSet() before setting any values.
+ * finishPointSet() must also be called for the last point set just before
+ * finishFrame().
  *
  * This class works like a pointer type: copying and assignment is lightweight,
  * and all copies work interchangeably, accessing the same internal handle.
@@ -244,6 +260,18 @@ class AnalysisDataHandle
          * is not finished).
          */
         void startFrame(int index, real x, real dx = 0.0);
+        /*! \brief
+         * Selects a data set for subsequent setPoint()/setPoints() calls.
+         *
+         * \param[in] index  Zero-based data set index.
+         *
+         * After startFrame(), the first data set is always selected.
+         * The set value is remembered until the end of the current frame, also
+         * across finishPointSet() calls.
+         *
+         * Does not throw.
+         */
+        void selectDataSet(int index);
         /*! \brief
          * Set a value for a single column for the current frame.
          *
index 4e5b5f3cdc6786f5af4971adb0b574c2d00d6cd6..f8eca8ccaf119288d22348792b6c868b9a20c57c 100644 (file)
@@ -51,7 +51,7 @@ namespace gmx
 {
 
 AbstractAnalysisArrayData::AbstractAnalysisArrayData()
-    : rowCount_(0), pointSetInfo_(0, 0, 0), xstart_(0.0), xstep_(1.0),
+    : rowCount_(0), pointSetInfo_(0, 0, 0, 0), xstart_(0.0), xstep_(1.0),
       bReady_(false)
 {
 }
@@ -89,8 +89,8 @@ AbstractAnalysisArrayData::setColumnCount(int ncols)
 {
     GMX_RELEASE_ASSERT(!isAllocated(),
                        "Cannot change column count after data has been allocated");
-    AbstractAnalysisData::setColumnCount(ncols);
-    pointSetInfo_ = AnalysisDataPointSetInfo(0, ncols, 0);
+    AbstractAnalysisData::setColumnCount(0, ncols);
+    pointSetInfo_ = AnalysisDataPointSetInfo(0, ncols, 0, 0);
 }
 
 
index be0a8785700bae3f25aed5ef1186c91d38c03ecb..f4f66096f4ccbdfbd7a22c45370986f831958660 100644 (file)
@@ -66,7 +66,7 @@ namespace gmx
  * accessed before it is available.
  *
  * \todo
- * Add methods to take full advantage of AnalysisDataValue features.
+ * Add support for multiple data sets.
  *
  * \inlibraryapi
  * \ingroup module_analysisdata
@@ -96,12 +96,12 @@ class AbstractAnalysisArrayData : public AbstractAnalysisData
             return xstart() + row * xstep();
         }
         //! Returns a given array element.
-        real value(int row, int col) const
+        const AnalysisDataValue &value(int row, int col) const
         {
             GMX_ASSERT(row >= 0 && row < rowCount(), "Row index out of range");
             GMX_ASSERT(col >= 0 && col < columnCount(), "Column index out of range");
             GMX_ASSERT(isAllocated(), "Data array not allocated");
-            return value_[row * columnCount() + col].value();
+            return value_[row * columnCount() + col];
         }
 
     protected:
@@ -154,25 +154,12 @@ class AbstractAnalysisArrayData : public AbstractAnalysisData
          */
         void setXAxis(real start, real step);
         //! Returns a reference to a given array element.
-        real &value(int row, int col)
+        AnalysisDataValue &value(int row, int col)
         {
             GMX_ASSERT(row >= 0 && row < rowCount(), "Row index out of range");
             GMX_ASSERT(col >= 0 && col < columnCount(), "Column index out of range");
             GMX_ASSERT(isAllocated(), "Data array not allocated");
-            return value_[row * columnCount() + col].value();
-        }
-        /*! \brief
-         * Sets the value of an element in the array.
-         *
-         * \param[in] row  Zero-based row index for the value.
-         * \param[in] col  Zero-based column index for the value.
-         * \param[in] val  Value to set in the given location.
-         *
-         * Does not throw.
-         */
-        void setValue(int row, int col, real val)
-        {
-            value(row, col) = val;
+            return value_[row * columnCount() + col];
         }
         /*! \brief
          * Notifies modules of the data.
@@ -246,7 +233,6 @@ class AnalysisArrayData : public AbstractAnalysisArrayData
         using AbstractAnalysisArrayData::allocateValues;
         using AbstractAnalysisArrayData::setXAxis;
         using AbstractAnalysisArrayData::value;
-        using AbstractAnalysisArrayData::setValue;
         using AbstractAnalysisArrayData::valuesReady;
 
         // Copy and assign disallowed by base.
index 51663a71d7f61dc74eea1c6e018e88d8080d792d..1f386234750a9fcc1915c9685c65cb393ff0ab8d 100644 (file)
@@ -71,7 +71,9 @@ AnalysisDataPointSetRef::AnalysisDataPointSetRef(
         const AnalysisDataFrameHeader  &header,
         const AnalysisDataPointSetInfo &pointSetInfo,
         const AnalysisDataValuesRef    &values)
-    : header_(header), firstColumn_(pointSetInfo.firstColumn()),
+    : header_(header),
+      dataSetIndex_(pointSetInfo.dataSetIndex()),
+      firstColumn_(pointSetInfo.firstColumn()),
       values_(&*values.begin() + pointSetInfo.valueOffset(),
               pointSetInfo.valueCount())
 {
@@ -83,7 +85,8 @@ AnalysisDataPointSetRef::AnalysisDataPointSetRef(
 AnalysisDataPointSetRef::AnalysisDataPointSetRef(
         const AnalysisDataFrameHeader        &header,
         const std::vector<AnalysisDataValue> &values)
-    : header_(header), firstColumn_(0), values_(values.begin(), values.end())
+    : header_(header), dataSetIndex_(0), firstColumn_(0),
+      values_(values.begin(), values.end())
 {
     GMX_ASSERT(header_.isValid(),
                "Invalid point set reference should not be constructed");
@@ -92,7 +95,8 @@ AnalysisDataPointSetRef::AnalysisDataPointSetRef(
 
 AnalysisDataPointSetRef::AnalysisDataPointSetRef(
         const AnalysisDataPointSetRef &points, int firstColumn, int columnCount)
-    : header_(points.header()), firstColumn_(0)
+    : header_(points.header()), dataSetIndex_(points.dataSetIndex()),
+      firstColumn_(0)
 {
     GMX_ASSERT(firstColumn >= 0, "Invalid first column");
     GMX_ASSERT(columnCount >= 0, "Invalid column count");
index 1205fe98e0c00100206c41bd41c87ececa8b5e9e..a4562de9d776e781491f723ee804834482ecf76a 100644 (file)
@@ -297,25 +297,29 @@ class AnalysisDataPointSetInfo
     public:
         //! Construct point set data object with the given values.
         AnalysisDataPointSetInfo(int valueOffset, int valueCount,
-                                 int firstColumn)
+                                 int dataSetIndex, int firstColumn)
             : valueOffset_(valueOffset), valueCount_(valueCount),
-              firstColumn_(firstColumn)
+              dataSetIndex_(dataSetIndex), firstColumn_(firstColumn)
         {
-            GMX_ASSERT(valueOffset >= 0, "Negative value offsets are invalid");
-            GMX_ASSERT(valueCount  >= 0, "Negative value counts are invalid");
-            GMX_ASSERT(firstColumn >= 0, "Negative column indices are invalid");
+            GMX_ASSERT(valueOffset  >= 0, "Negative value offsets are invalid");
+            GMX_ASSERT(valueCount   >= 0, "Negative value counts are invalid");
+            GMX_ASSERT(dataSetIndex >= 0, "Negative data set indices are invalid");
+            GMX_ASSERT(firstColumn  >= 0, "Negative column indices are invalid");
         }
 
         //! Returns the offset of the first value in the referenced value array.
         int valueOffset() const { return valueOffset_; }
         //! Returns the number of values in this point set.
         int valueCount() const { return valueCount_; }
+        //! Returns the data set index for this point set.
+        int dataSetIndex() const { return dataSetIndex_; }
         //! Returns the index of the first column in this point set.
         int firstColumn() const { return firstColumn_; }
 
     private:
         int                     valueOffset_;
         int                     valueCount_;
+        int                     dataSetIndex_;
         int                     firstColumn_;
 };
 
@@ -415,6 +419,11 @@ class AnalysisDataPointSetRef
         {
             return header_.dx();
         }
+        //! Returns zero-based index of the dataset that this set is part of.
+        int dataSetIndex() const
+        {
+            return dataSetIndex_;
+        }
         //! Returns zero-based index of the first column included in this set.
         int firstColumn() const
         {
@@ -487,6 +496,7 @@ class AnalysisDataPointSetRef
 
     private:
         AnalysisDataFrameHeader header_;
+        int                     dataSetIndex_;
         int                     firstColumn_;
         AnalysisDataValuesRef   values_;
 };
index b04bea345d6eb38ca5df2ce45c0ec83fb398cbc3..9ca0f7b3e85fad3f1199b43aa3e29b975b914b67 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2010,2011,2012, by the GROMACS development team, led by
+ * Copyright (c) 2010,2011,2012,2013, 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.
@@ -82,13 +82,15 @@ class AnalysisDataModuleInterface
          */
         enum {
             //! The module can process multipoint data.
-            efAllowMultipoint    = 0x01,
+            efAllowMultipoint           = 1<<0,
             //! The module does not make sense for non-multipoint data.
-            efOnlyMultipoint     = 0x02,
+            efOnlyMultipoint            = 1<<1,
             //! The module can process data with more than one column.
-            efAllowMulticolumn   = 0x04,
+            efAllowMulticolumn          = 1<<2,
             //! The module can process data with missing points.
-            efAllowMissing       = 0x08,
+            efAllowMissing              = 1<<3,
+            //! The module can process data with multiple data sets.
+            efAllowMultipleDataSets     = 1<<4
         };
 
         virtual ~AnalysisDataModuleInterface() {};
index 8eb4a342c800d485858dd8f33444657e1190ca5c..5b015ccc96f9e1cda0ba2666025fc707edb7eaf8 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2010,2011,2012, by the GROMACS development team, led by
+ * Copyright (c) 2010,2011,2012,2013, 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.
@@ -51,9 +51,8 @@ AnalysisDataProxy::AnalysisDataProxy(int firstColumn, int columnSpan,
                                      AbstractAnalysisData *data)
     : source_(*data), firstColumn_(firstColumn), columnSpan_(columnSpan)
 {
-    GMX_RELEASE_ASSERT(data, "Source data must not be NULL");
+    GMX_RELEASE_ASSERT(data != NULL, "Source data must not be NULL");
     GMX_RELEASE_ASSERT(firstColumn >= 0 && columnSpan > 0, "Invalid proxy column");
-    setColumnCount(columnSpan);
     setMultipoint(source_.isMultipoint());
 }
 
@@ -80,7 +79,8 @@ AnalysisDataProxy::requestStorageInternal(int nframes)
 int
 AnalysisDataProxy::flags() const
 {
-    return efAllowMultipoint | efAllowMulticolumn | efAllowMissing;
+    return efAllowMultipoint | efAllowMulticolumn | efAllowMissing
+           | efAllowMultipleDataSets;
 }
 
 
@@ -88,8 +88,11 @@ void
 AnalysisDataProxy::dataStarted(AbstractAnalysisData *data)
 {
     GMX_RELEASE_ASSERT(data == &source_, "Source data mismatch");
-    GMX_RELEASE_ASSERT(firstColumn_ + columnSpan_ <= source_.columnCount(),
-                       "Invalid column(s) specified");
+    setDataSetCount(data->dataSetCount());
+    for (int i = 0; i < data->dataSetCount(); ++i)
+    {
+        setColumnCount(i, columnSpan_);
+    }
     notifyDataStart();
 }
 
index 1b80d95430284930e39c0122d346400b84ad63a4..94d443e9adf72fa688b7088126d798efa0382cb8 100644 (file)
@@ -107,8 +107,6 @@ class AnalysisDataStorage::Impl
 
         Impl();
 
-        //! Returns the number of columns in the attached data.
-        int columnCount() const;
         //! Returns whether the storage is set to use multipoint data.
         bool isMultipoint() const;
         /*! \brief
@@ -349,7 +347,8 @@ class AnalysisDataStorageFrameData
         /*! \brief
          * Adds a new point set to this frame.
          */
-        void addPointSet(int firstColumn, ValueIterator begin, ValueIterator end);
+        void addPointSet(int dataSetIndex, int firstColumn,
+                         ValueIterator begin, ValueIterator end);
         /*! \brief
          * Finalizes the frame during AnalysisDataStorage::finishFrame().
          *
@@ -401,14 +400,6 @@ AnalysisDataStorage::Impl::Impl()
 }
 
 
-int
-AnalysisDataStorage::Impl::columnCount() const
-{
-    GMX_ASSERT(data_ != NULL, "columnCount() called too early");
-    return data_->columnCount();
-}
-
-
 bool
 AnalysisDataStorage::Impl::isMultipoint() const
 {
@@ -489,7 +480,7 @@ AnalysisDataStorage::Impl::getFrameBuilder()
 {
     if (builders_.empty())
     {
-        return FrameBuilderPointer(new AnalysisDataStorageFrame(columnCount()));
+        return FrameBuilderPointer(new AnalysisDataStorageFrame(*data_));
     }
     FrameBuilderPointer builder(move(builders_.back()));
     builders_.pop_back();
@@ -596,8 +587,14 @@ AnalysisDataStorageFrameData::AnalysisDataStorageFrameData(
     // so initialize it only once here.
     if (!baseData().isMultipoint())
     {
-        int columnCount = baseData().columnCount();
-        pointSets_.push_back(AnalysisDataPointSetInfo(0, columnCount, 0));
+        int offset = 0;
+        for (int i = 0; i < baseData().dataSetCount(); ++i)
+        {
+            int columnCount = baseData().columnCount(i);
+            pointSets_.push_back(
+                    AnalysisDataPointSetInfo(offset, columnCount, i, 0));
+            offset += columnCount;
+        }
     }
 }
 
@@ -625,17 +622,19 @@ AnalysisDataStorageFrameData::startFrame(
     header_         = header;
     builder_        = move(builder);
     builder_->data_ = this;
+    builder_->selectDataSet(0);
 }
 
 
 void
-AnalysisDataStorageFrameData::addPointSet(int firstColumn,
+AnalysisDataStorageFrameData::addPointSet(int dataSetIndex, int firstColumn,
                                           ValueIterator begin, ValueIterator end)
 {
     const int valueCount  = end - begin;
     if (storageImpl().shouldNotifyImmediately())
     {
-        AnalysisDataPointSetInfo pointSetInfo(0, valueCount, firstColumn);
+        AnalysisDataPointSetInfo pointSetInfo(0, valueCount,
+                                              dataSetIndex, firstColumn);
         storageImpl().notifyPointSet(
                 AnalysisDataPointSetRef(header(), pointSetInfo,
                                         AnalysisDataValuesRef(begin, end)));
@@ -643,7 +642,8 @@ AnalysisDataStorageFrameData::addPointSet(int firstColumn,
     else
     {
         pointSets_.push_back(
-                AnalysisDataPointSetInfo(values_.size(), valueCount, firstColumn));
+                AnalysisDataPointSetInfo(values_.size(), valueCount,
+                                         dataSetIndex, firstColumn));
         std::copy(begin, end, std::back_inserter(values_));
     }
 }
@@ -655,7 +655,7 @@ AnalysisDataStorageFrameData::finishFrame(bool bMultipoint)
     status_ = eFinished;
     if (!bMultipoint)
     {
-        GMX_RELEASE_ASSERT(pointSets_.size() == 1U,
+        GMX_RELEASE_ASSERT(static_cast<int>(pointSets_.size()) == baseData().dataSetCount(),
                            "Point sets created for non-multipoint data");
         values_ = builder_->values_;
         builder_->clearValues();
@@ -687,9 +687,17 @@ AnalysisDataStorageFrameData::pointSet(int index) const
  * AnalysisDataStorageFrame
  */
 
-AnalysisDataStorageFrame::AnalysisDataStorageFrame(int columnCount)
-    : data_(NULL), values_(columnCount), bPointSetInProgress_(false)
+AnalysisDataStorageFrame::AnalysisDataStorageFrame(
+        const AbstractAnalysisData &data)
+    : data_(NULL), currentDataSet_(0), currentOffset_(0),
+      columnCount_(data.columnCount(0)), bPointSetInProgress_(false)
 {
+    int totalColumnCount = 0;
+    for (int i = 0; i < data.dataSetCount(); ++i)
+    {
+        totalColumnCount += data.columnCount(i);
+    }
+    values_.resize(totalColumnCount);
 }
 
 
@@ -713,6 +721,26 @@ AnalysisDataStorageFrame::clearValues()
 }
 
 
+void
+AnalysisDataStorageFrame::selectDataSet(int index)
+{
+    GMX_RELEASE_ASSERT(data_ != NULL, "Invalid frame accessed");
+    const AbstractAnalysisData &baseData = data_->baseData();
+    GMX_RELEASE_ASSERT(index >= 0 && index < baseData.dataSetCount(),
+                       "Out of range data set index");
+    GMX_RELEASE_ASSERT(!baseData.isMultipoint() || !bPointSetInProgress_,
+                       "Point sets in multipoint data cannot span data sets");
+    currentDataSet_ = index;
+    currentOffset_  = 0;
+    // TODO: Consider precalculating.
+    for (int i = 0; i < index; ++i)
+    {
+        currentOffset_ += baseData.columnCount(i);
+    }
+    columnCount_    = baseData.columnCount(index);
+}
+
+
 void
 AnalysisDataStorageFrame::finishPointSet()
 {
@@ -721,18 +749,25 @@ AnalysisDataStorageFrame::finishPointSet()
                        "Should not be called for non-multipoint data");
     if (bPointSetInProgress_)
     {
-        std::vector<AnalysisDataValue>::const_iterator begin = values_.begin();
-        std::vector<AnalysisDataValue>::const_iterator end   = values_.end();
+        std::vector<AnalysisDataValue>::const_iterator begin
+            = values_.begin() + currentOffset_;
+        std::vector<AnalysisDataValue>::const_iterator end
+            = begin + columnCount_;
+        int firstColumn = 0;
         while (begin != end && !begin->isSet())
         {
             ++begin;
+            ++firstColumn;
         }
         while (end != begin && !(end-1)->isSet())
         {
             --end;
         }
-        int firstColumn = (begin != end) ? begin - values_.begin() : 0;
-        data_->addPointSet(firstColumn, begin, end);
+        if (begin == end)
+        {
+            firstColumn = 0;
+        }
+        data_->addPointSet(currentDataSet_, firstColumn, begin, end);
     }
     clearValues();
 }
index 650a613b0fd11f0485958aec2782c727e3643ba4..26ab9640b6230d4df629abc2598098a8a964ed9e 100644 (file)
@@ -87,8 +87,23 @@ class AnalysisDataStorageFrame
          */
         ~AnalysisDataStorageFrame();
 
+        /*! \brief
+         * Select data set that all other methods operate on.
+         *
+         * \param[in] index  Zero-based data set index to select.
+         *
+         * With multipoint data, a single point set can only contain values in
+         * a single data set.
+         * With non-multipoint data, arbitrary sequences of selectDataSet() and
+         * setValue() are supported.  The full frame is notified to the modules
+         * once it is finished.
+         *
+         * Does not throw.
+         */
+        void selectDataSet(int index);
+
         //! Returns number of columns for the frame.
-        int columnCount() const { return values_.size(); }
+        int columnCount() const { return columnCount_; }
 
         /*! \brief
          * Sets value for a column.
@@ -106,7 +121,7 @@ class AnalysisDataStorageFrame
         {
             GMX_ASSERT(column >= 0 && column < columnCount(),
                        "Invalid column index");
-            values_[column].setValue(value, bPresent);
+            values_[currentOffset_ + column].setValue(value, bPresent);
             bPointSetInProgress_ = true;
         }
         /*! \brief
@@ -126,7 +141,7 @@ class AnalysisDataStorageFrame
         {
             GMX_ASSERT(column >= 0 && column < columnCount(),
                        "Invalid column index");
-            values_[column].setValue(value, error, bPresent);
+            values_[currentOffset_ + column].setValue(value, error, bPresent);
             bPointSetInProgress_ = true;
         }
         /*! \brief
@@ -144,7 +159,7 @@ class AnalysisDataStorageFrame
         {
             GMX_ASSERT(column >= 0 && column < columnCount(),
                        "Invalid column index");
-            return values_[column].value();
+            return values_[currentOffset_ + column].value();
         }
         /*! \brief
          * Access value for a column.
@@ -160,7 +175,7 @@ class AnalysisDataStorageFrame
         {
             GMX_ASSERT(column >= 0 && column < columnCount(),
                        "Invalid column index");
-            return values_[column].value();
+            return values_[currentOffset_ + column].value();
         }
         /*! \brief
          * Mark point set as finished for multipoint data.
@@ -193,9 +208,10 @@ class AnalysisDataStorageFrame
         /*! \brief
          * Create a new storage frame.
          *
-         * \param[in] columnCount  Number of columns for the frame.
+         * \param[in] data  Data object for which the frame is for
+         *      (used for data set and column counts).
          */
-        explicit AnalysisDataStorageFrame(int columnCount);
+        explicit AnalysisDataStorageFrame(const AbstractAnalysisData &data);
 
         //! Clear all column values from the frame.
         void clearValues();
@@ -205,6 +221,13 @@ class AnalysisDataStorageFrame
         //! Values for the currently in-progress point set.
         std::vector<AnalysisDataValue>          values_;
 
+        //! Index of the currently active dataset.
+        int                                     currentDataSet_;
+        //! Offset of the first value in \a values_ for the current data set.
+        int                                     currentOffset_;
+        //! Number of columns in the current data set.
+        int                                     columnCount_;
+
         //! Whether any values have been set in the current point set.
         bool                                    bPointSetInProgress_;
 
index 9640b224a98f6061836e5e8f4979e0652eba0019..9a19fa799665a3dce1602ddc14101ca77a149c3d 100644 (file)
@@ -43,6 +43,9 @@
 
 #include <cmath>
 
+#include <algorithm>
+#include <vector>
+
 #include "gromacs/analysisdata/dataframe.h"
 #include "gromacs/analysisdata/datastorage.h"
 
@@ -58,32 +61,56 @@ namespace gmx
 class AnalysisDataAverageModule::Impl
 {
     public:
-        //! Averaging helper object.
-        AnalysisDataFrameAverager averager_;
+        Impl() : bDataSets_(false) {}
+
+        //! Averaging helper objects for each input data set.
+        std::vector<AnalysisDataFrameAverager>  averagers_;
+        //! Whether to average all columns in a data set into a single value.
+        bool                                    bDataSets_;
 };
 
 AnalysisDataAverageModule::AnalysisDataAverageModule()
     : impl_(new Impl())
 {
-    setColumnCount(2);
 }
 
 AnalysisDataAverageModule::~AnalysisDataAverageModule()
 {
 }
 
-int
-AnalysisDataAverageModule::flags() const
+void AnalysisDataAverageModule::setAverageDataSets(bool bDataSets)
 {
-    return efAllowMultipoint | efAllowMulticolumn | efAllowMissing;
+    impl_->bDataSets_ = bDataSets;
+}
+
+int AnalysisDataAverageModule::flags() const
+{
+    return efAllowMultipoint | efAllowMulticolumn | efAllowMissing
+           | efAllowMultipleDataSets;
 }
 
 void
 AnalysisDataAverageModule::dataStarted(AbstractAnalysisData *data)
 {
-    const int valueCount = data->columnCount();
-    impl_->averager_.setColumnCount(valueCount);
-    setRowCount(valueCount);
+    if (impl_->bDataSets_)
+    {
+        setColumnCount(1);
+        setRowCount(data->dataSetCount());
+        impl_->averagers_.resize(1);
+        impl_->averagers_[0].setColumnCount(data->dataSetCount());
+    }
+    else
+    {
+        setColumnCount(data->dataSetCount());
+        impl_->averagers_.resize(data->dataSetCount());
+        int rowCount = 0;
+        for (int i = 0; i < data->dataSetCount(); ++i)
+        {
+            impl_->averagers_[i].setColumnCount(data->columnCount(i));
+            rowCount = std::max(rowCount, data->columnCount(i));
+        }
+        setRowCount(rowCount);
+    }
 }
 
 void
@@ -94,7 +121,21 @@ AnalysisDataAverageModule::frameStarted(const AnalysisDataFrameHeader & /*header
 void
 AnalysisDataAverageModule::pointsAdded(const AnalysisDataPointSetRef &points)
 {
-    impl_->averager_.addPoints(points);
+    if (impl_->bDataSets_)
+    {
+        const int dataSet = points.dataSetIndex();
+        for (int i = 0; i < points.columnCount(); ++i)
+        {
+            if (points.present(i))
+            {
+                impl_->averagers_[0].addValue(dataSet, points.y(i));
+            }
+        }
+    }
+    else
+    {
+        impl_->averagers_[points.dataSetIndex()].addPoints(points);
+    }
 }
 
 void
@@ -105,26 +146,55 @@ AnalysisDataAverageModule::frameFinished(const AnalysisDataFrameHeader & /*heade
 void
 AnalysisDataAverageModule::dataFinished()
 {
-    impl_->averager_.finish();
     allocateValues();
-    for (int i = 0; i < rowCount(); ++i)
+    for (int i = 0; i < columnCount(); ++i)
     {
-        setValue(i, 0, impl_->averager_.average(i));
-        setValue(i, 1, sqrt(impl_->averager_.variance(i)));
+        impl_->averagers_[i].finish();
+        int j = 0;
+        for (; j < impl_->averagers_[i].columnCount(); ++j)
+        {
+            value(j, i).setValue(impl_->averagers_[i].average(j),
+                                 std::sqrt(impl_->averagers_[i].variance(j)));
+        }
+        for (; j < rowCount(); ++j)
+        {
+            value(j, i).setValue(0.0, 0.0, false);
+        }
     }
     valuesReady();
 }
 
-real
-AnalysisDataAverageModule::average(int index) const
+real AnalysisDataAverageModule::average(int dataSet, int column) const
 {
-    return value(index, 0);
+    if (impl_->bDataSets_)
+    {
+        GMX_ASSERT(column == 0,
+                   "Column should be zero with setAverageDataSets(true)");
+        std::swap(dataSet, column);
+    }
+    return value(column, dataSet).value();
 }
 
-real
-AnalysisDataAverageModule::stddev(int index) const
+real AnalysisDataAverageModule::standardDeviation(int dataSet, int column) const
 {
-    return value(index, 1);
+    if (impl_->bDataSets_)
+    {
+        GMX_ASSERT(column == 0,
+                   "Column should be zero with setAverageDataSets(true)");
+        std::swap(dataSet, column);
+    }
+    return value(column, dataSet).error();
+}
+
+int AnalysisDataAverageModule::sampleCount(int dataSet, int column) const
+{
+    if (impl_->bDataSets_)
+    {
+        GMX_ASSERT(column == 0,
+                   "Column should be zero with setAverageDataSets(true)");
+        std::swap(dataSet, column);
+    }
+    return impl_->averagers_[dataSet].sampleCount(column);
 }
 
 
@@ -137,14 +207,13 @@ class AnalysisDataFrameAverageModule::Impl
     public:
         //! Storage implementation object.
         AnalysisDataStorage     storage_;
-        //! Number of samples in a frame.
-        int                     sampleCount_;
+        //! Number of samples in a frame for each data set.
+        std::vector<int>        sampleCount_;
 };
 
 AnalysisDataFrameAverageModule::AnalysisDataFrameAverageModule()
     : impl_(new Impl())
 {
-    setColumnCount(1);
 }
 
 AnalysisDataFrameAverageModule::~AnalysisDataFrameAverageModule()
@@ -154,12 +223,15 @@ AnalysisDataFrameAverageModule::~AnalysisDataFrameAverageModule()
 int
 AnalysisDataFrameAverageModule::flags() const
 {
-    return efAllowMultipoint | efAllowMulticolumn | efAllowMissing;
+    return efAllowMultipoint | efAllowMulticolumn | efAllowMissing
+           | efAllowMultipleDataSets;
 }
 
 void
 AnalysisDataFrameAverageModule::dataStarted(AbstractAnalysisData *data)
 {
+    setColumnCount(0, data->dataSetCount());
+    impl_->sampleCount_.resize(data->dataSetCount());
     notifyDataStart();
     impl_->storage_.startDataStorage(this);
 }
@@ -167,23 +239,29 @@ AnalysisDataFrameAverageModule::dataStarted(AbstractAnalysisData *data)
 void
 AnalysisDataFrameAverageModule::frameStarted(const AnalysisDataFrameHeader &header)
 {
-    impl_->sampleCount_ = 0;
     AnalysisDataStorageFrame &frame = impl_->storage_.startFrame(header);
-    frame.setValue(0, 0.0);
+    for (int i = 0; i < columnCount(); ++i)
+    {
+        impl_->sampleCount_[i] = 0;
+        frame.setValue(i, 0.0);
+    }
 }
 
 void
 AnalysisDataFrameAverageModule::pointsAdded(const AnalysisDataPointSetRef &points)
 {
-    AnalysisDataStorageFrame &frame =
+    const int                 dataSet = points.dataSetIndex();
+    AnalysisDataStorageFrame &frame   =
         impl_->storage_.currentFrame(points.frameIndex());
     for (int i = 0; i < points.columnCount(); ++i)
     {
         if (points.present(i))
         {
-            const real y = points.y(i);
-            frame.value(0)      += y;
-            impl_->sampleCount_ += 1;
+            // TODO: Consider using AnalysisDataFrameAverager
+            const real y     = points.y(i);
+            const real delta = y - frame.value(dataSet);
+            impl_->sampleCount_[dataSet] += 1;
+            frame.value(dataSet)         += delta / impl_->sampleCount_[dataSet];
         }
     }
 }
@@ -191,13 +269,6 @@ AnalysisDataFrameAverageModule::pointsAdded(const AnalysisDataPointSetRef &point
 void
 AnalysisDataFrameAverageModule::frameFinished(const AnalysisDataFrameHeader &header)
 {
-    AnalysisDataStorageFrame &frame =
-        impl_->storage_.currentFrame(header.index());
-    const int                 samples = impl_->sampleCount_;
-    if (samples > 0)
-    {
-        frame.value(0) /= samples;
-    }
     impl_->storage_.finishFrame(header.index());
 }
 
index 999fb01f99a6699e2ce0a2a7714ef17522b6bc82..e0480999ea22c09cd154cad72646007d09d2e105 100644 (file)
@@ -57,16 +57,21 @@ namespace gmx
  * Data module for independently averaging each column in input data.
  *
  * Computes the average and standard deviation independently for each column in
- * the input data.  Multipoint data and missing data points are both supported.
+ * the input data.  Multipoint data, multiple data sets, and missing data
+ * points are all supported.
  * The average is always calculated over all frames and data points for a
  * column.
  *
- * Output data contains a frame for each column in the input data.
- * The first column of each output frame is the average of the corresponding
- * input column.  The second output column is the standard deviation of the
- * corresponding input column.
- * average() and stddev() methods are also provided for convenient access to
- * these properties.
+ * Output data contains a column for each data set in the input data, and a
+ * frame for each column in the input data.  If different data sets have
+ * different number of columns, the frame count accomodates the largest data
+ * set.  Other columns are padded with zero values that are additionally marked
+ * as missing.
+ * Each value in the output data is the average of the corresponding
+ * input column in the corresponding input data set.  The error value for each
+ * value provides the standard deviation of the corresponding input column.
+ * average(), standardDeviation(), and sampleCount() methods are also
+ * provided for convenient access to these properties.
  *
  * The output data becomes available only after the input data has been
  * finished.
@@ -83,6 +88,20 @@ class AnalysisDataAverageModule : public AbstractAnalysisArrayData,
 
         using AbstractAnalysisArrayData::setXAxis;
 
+        /*! \brief
+         * Sets the averaging to happen over entire data sets.
+         *
+         * If \p bDataSets is false (the default), the module averages each
+         * column separately.  The output will have a column for each data set,
+         * and a row for each column.
+         *
+         * If \p bDataSets is true, the module averages all values within
+         * a single data set into a single average/standard deviation.
+         * The output will have only one column, with one row for each data
+         * set.
+         */
+        void setAverageDataSets(bool bDataSets);
+
         virtual int flags() const;
 
         virtual void dataStarted(AbstractAnalysisData *data);
@@ -91,10 +110,29 @@ class AnalysisDataAverageModule : public AbstractAnalysisArrayData,
         virtual void frameFinished(const AnalysisDataFrameHeader &header);
         virtual void dataFinished();
 
-        //! Convenience access to the average of a data column.
-        real average(int index) const;
-        //! Convenience access to the standard deviation of a data column.
-        real stddev(int index) const;
+        /*! \brief
+         * Convenience access to the average of a data column.
+         *
+         * Note that the interpretation of the parameters follows their naming:
+         * with \c setAverageDataSets(false), \p dataSet corresponds to a
+         * column in the output, but with \c setAverageDataSets(false) it
+         * corresponds to an output row.  In both cases, it selects the data
+         * set; with \c setAverageDataSets(false), \p column should always be
+         * zero as there is only one value per data set.
+         */
+        real average(int dataSet, int column) const;
+        /*! \brief
+         * Convenience access to the standard deviation of a data column.
+         *
+         * See average() for the interpretation of the parameters.
+         */
+        real standardDeviation(int dataSet, int column) const;
+        /*! \brief
+         * Access the number of samples for a data column.
+         *
+         * See average() for the interpretation of the parameters.
+         */
+        int sampleCount(int dataSet, int column) const;
 
     private:
         class Impl;
@@ -109,13 +147,15 @@ typedef boost::shared_ptr<AnalysisDataAverageModule>
 /*! \brief
  * Data module for averaging of columns for each frame.
  *
- * Output data has the same number of frames as the input data, but only one
- * column.
- * Each frame in the output contains the average of the column values in the
- * corresponding frame of the input data.
+ * Output data has the same number of frames as the input data.
+ * The number of columns in the output data is the same as the number of data
+ * sets in the input data.
+ * Each frame in the output contains the average of the column values for each
+ * data set in the corresponding frame of the input data.
  *
- * Multipoint data and missing data points are both supported. The average
- * is always calculated over all data points present in a column.
+ * Multipoint data and missing data points are both supported.  The average
+ * is always calculated over all data points present in a column for a data
+ * set.
  *
  * \inpublicapi
  * \ingroup module_analysisdata
index 2dd5836e3d07cd65557112c810b454c000467caf..bb13359465685fc02b8f90cff4d5c2b605097784 100644 (file)
@@ -178,7 +178,7 @@ AnalysisDataDisplacementModule::dataStarted(AbstractAnalysisData *data)
 
     int ncol = _impl->nmax / _impl->ndim + 1;
     _impl->currValues_.reserve(ncol);
-    setColumnCount(ncol);
+    setColumnCount(0, ncol);
 }
 
 
index 54c8504b2e8bd8680b50e1564c651c79d5822d76..7025b29b273afc98fb5aefa41426bda796880784 100644 (file)
@@ -77,6 +77,11 @@ class AnalysisDataFrameAverager
     public:
         AnalysisDataFrameAverager() : bFinished_(false) {}
 
+        /*! \brief
+         * Returns the number of columns in this averager.
+         */
+        int columnCount() const { return values_.size(); }
+
         /*! \brief
          * Sets the number of columns in the input data.
          *
@@ -123,7 +128,7 @@ class AnalysisDataFrameAverager
          */
         real average(int index) const
         {
-            GMX_ASSERT(index >= 0 && index <= static_cast<int>(values_.size()),
+            GMX_ASSERT(index >= 0 && index < columnCount(),
                        "Invalid column index");
             GMX_ASSERT(bFinished_,
                        "Values available only after finished() has been called");
@@ -136,7 +141,7 @@ class AnalysisDataFrameAverager
          */
         real variance(int index) const
         {
-            GMX_ASSERT(index >= 0 && index <= static_cast<int>(values_.size()),
+            GMX_ASSERT(index >= 0 && index < columnCount(),
                        "Invalid column index");
             GMX_ASSERT(bFinished_,
                        "Values available only after finished() has been called");
index 766ce363f8ea4258fc7e0af0564b642b8cce3881..5360430716a577afe4245ad8b814758673fa6523 100644 (file)
@@ -44,6 +44,7 @@
 #include <cmath>
 
 #include <limits>
+#include <vector>
 
 #include "gromacs/analysisdata/dataframe.h"
 #include "gromacs/analysisdata/datastorage.h"
@@ -293,24 +294,22 @@ AbstractAverageHistogram::resampleDoubleBinWidth(bool bIntegerBins) const
         for (int c = 0; c < columnCount(); ++c)
         {
             real  v1, v2;
+            real  e1, e2;
             if (bFirstHalfBin)
             {
-                v1 = value(0, c);
+                v1 = value(0, c).value();
+                e1 = value(0, c).error();
                 v2 = 0;
+                e2 = 0;
             }
             else
             {
-                v1 = value(j, c);
-                v2 = value(j + 1, c);
-            }
-            if (c == 1)
-            {
-                dest->setValue(i, c, sqrt(v1 * v1 + v2 * v2));
-            }
-            else
-            {
-                dest->setValue(i, c, v1 + v2);
+                v1 = value(j, c).value();
+                e1 = value(j, c).error();
+                v2 = value(j + 1, c).value();
+                e2 = value(j + 1, c).error();
             }
+            dest->value(i, c).setValue(v1 + v2, std::sqrt(e1 * e1 + e2 * e2));
         }
         if (bFirstHalfBin)
         {
@@ -337,33 +336,49 @@ AbstractAverageHistogram::clone() const
 void
 AbstractAverageHistogram::normalizeProbability()
 {
-    real sum = 0;
-    for (int i = 0; i < rowCount(); ++i)
+    for (int c = 0; c < columnCount(); ++c)
     {
-        sum += value(i, 0);
+        real sum = 0;
+        for (int i = 0; i < rowCount(); ++i)
+        {
+            sum += value(i, c).value();
+        }
+        scaleSingle(c, 1.0 / (sum * xstep()));
     }
-    scale(1.0 / (sum * xstep()));
 }
 
 
 void
-AbstractAverageHistogram::scale(real norm)
+AbstractAverageHistogram::scaleSingle(int index, real factor)
 {
     for (int i = 0; i < rowCount(); ++i)
     {
-        value(i, 0) *= norm;
-        value(i, 1) *= norm;
+        value(i, index).value() *= factor;
+        value(i, index).error() *= factor;
     }
 }
 
 
 void
-AbstractAverageHistogram::scaleVector(real norm[])
+AbstractAverageHistogram::scaleAll(real factor)
 {
-    for (int i = 0; i < rowCount(); ++i)
+    for (int i = 0; i < columnCount(); ++i)
     {
-        value(i, 0) *= norm[i];
-        value(i, 1) *= norm[i];
+        scaleSingle(i, factor);
+    }
+}
+
+
+void
+AbstractAverageHistogram::scaleAllByVector(real factor[])
+{
+    for (int c = 0; c < columnCount(); ++c)
+    {
+        for (int i = 0; i < rowCount(); ++i)
+        {
+            value(i, c).value() *= factor[i];
+            value(i, c).error() *= factor[i];
+        }
     }
 }
 
@@ -405,15 +420,14 @@ class BasicAverageHistogramModule : public AbstractAverageHistogram,
         virtual void dataFinished();
 
     private:
-        //! Averaging helper object.
-        AnalysisDataFrameAverager averager_;
+        //! Averaging helper objects for each input data set.
+        std::vector<AnalysisDataFrameAverager> averagers_;
 
         // Copy and assign disallowed by base.
 };
 
 BasicAverageHistogramModule::BasicAverageHistogramModule()
 {
-    setColumnCount(2);
 }
 
 
@@ -421,23 +435,27 @@ BasicAverageHistogramModule::BasicAverageHistogramModule(
         const AnalysisHistogramSettings &settings)
     : AbstractAverageHistogram(settings)
 {
-    setColumnCount(2);
 }
 
 
 int
 BasicAverageHistogramModule::flags() const
 {
-    return efAllowMulticolumn;
+    return efAllowMulticolumn | efAllowMultipleDataSets;
 }
 
 
 void
 BasicAverageHistogramModule::dataStarted(AbstractAnalysisData *data)
 {
-    GMX_RELEASE_ASSERT(rowCount() == data->columnCount(),
-                       "Inconsistent data sizes, something is wrong in the initialization");
-    averager_.setColumnCount(rowCount());
+    setColumnCount(data->dataSetCount());
+    averagers_.resize(data->dataSetCount());
+    for (int i = 0; i < data->dataSetCount(); ++i)
+    {
+        GMX_RELEASE_ASSERT(rowCount() == data->columnCount(i),
+                           "Inconsistent data sizes, something is wrong in the initialization");
+        averagers_[i].setColumnCount(data->columnCount(i));
+    }
 }
 
 
@@ -450,7 +468,7 @@ BasicAverageHistogramModule::frameStarted(const AnalysisDataFrameHeader & /*head
 void
 BasicAverageHistogramModule::pointsAdded(const AnalysisDataPointSetRef &points)
 {
-    averager_.addPoints(points);
+    averagers_[points.dataSetIndex()].addPoints(points);
 }
 
 
@@ -463,12 +481,15 @@ BasicAverageHistogramModule::frameFinished(const AnalysisDataFrameHeader & /*hea
 void
 BasicAverageHistogramModule::dataFinished()
 {
-    averager_.finish();
     allocateValues();
-    for (int i = 0; i < rowCount(); ++i)
+    for (int i = 0; i < columnCount(); ++i)
     {
-        setValue(i, 0, averager_.average(i));
-        setValue(i, 1, sqrt(averager_.variance(i)));
+        averagers_[i].finish();
+        for (int j = 0; j < rowCount(); ++j)
+        {
+            value(j, i).setValue(averagers_[i].average(j),
+                                 std::sqrt(averagers_[i].variance(j)));
+        }
     }
 }
 
@@ -502,7 +523,7 @@ class BasicHistogramImpl
         /*! \brief
          * Initializes data storage frame when a new frame starts.
          */
-        void initFrame(AnalysisDataStorageFrame *frame);
+        void initFrame(int dataSetCount, AnalysisDataStorageFrame *frame);
 
         //! Storage implementation object.
         AnalysisDataStorage                  storage_;
@@ -537,12 +558,17 @@ void BasicHistogramImpl::init(const AnalysisHistogramSettings &settings)
 
 
 void
-BasicHistogramImpl::initFrame(AnalysisDataStorageFrame *frame)
+BasicHistogramImpl::initFrame(int dataSetCount, AnalysisDataStorageFrame *frame)
 {
-    for (int i = 0; i < frame->columnCount(); ++i)
+    for (int s = 0; s < dataSetCount; ++s)
     {
-        frame->setValue(i, 0.0);
+        frame->selectDataSet(s);
+        for (int i = 0; i < frame->columnCount(); ++i)
+        {
+            frame->setValue(i, 0.0);
+        }
     }
+    frame->selectDataSet(0);
 }
 
 }   // namespace internal
@@ -593,7 +619,8 @@ AnalysisDataSimpleHistogramModule::settings() const
 int
 AnalysisDataSimpleHistogramModule::flags() const
 {
-    return efAllowMulticolumn | efAllowMultipoint;
+    return efAllowMulticolumn | efAllowMultipoint | efAllowMissing
+           | efAllowMultipleDataSets;
 }
 
 
@@ -601,7 +628,11 @@ void
 AnalysisDataSimpleHistogramModule::dataStarted(AbstractAnalysisData *data)
 {
     addModule(impl_->averager_);
-    setColumnCount(settings().binCount());
+    setDataSetCount(data->dataSetCount());
+    for (int i = 0; i < data->dataSetCount(); ++i)
+    {
+        setColumnCount(i, settings().binCount());
+    }
     notifyDataStart();
     impl_->storage_.startDataStorage(this);
 }
@@ -611,7 +642,7 @@ void
 AnalysisDataSimpleHistogramModule::frameStarted(const AnalysisDataFrameHeader &header)
 {
     AnalysisDataStorageFrame &frame = impl_->storage_.startFrame(header);
-    impl_->initFrame(&frame);
+    impl_->initFrame(dataSetCount(), &frame);
 }
 
 
@@ -620,12 +651,16 @@ AnalysisDataSimpleHistogramModule::pointsAdded(const AnalysisDataPointSetRef &po
 {
     AnalysisDataStorageFrame &frame =
         impl_->storage_.currentFrame(points.frameIndex());
+    frame.selectDataSet(points.dataSetIndex());
     for (int i = 0; i < points.columnCount(); ++i)
     {
-        int bin = settings().findBin(points.y(i));
-        if (bin != -1)
+        if (points.present(i))
         {
-            frame.value(bin) += 1;
+            const int bin = settings().findBin(points.y(i));
+            if (bin != -1)
+            {
+                frame.value(bin) += 1;
+            }
         }
     }
 }
@@ -704,7 +739,7 @@ AnalysisDataWeightedHistogramModule::settings() const
 int
 AnalysisDataWeightedHistogramModule::flags() const
 {
-    return efAllowMulticolumn | efAllowMultipoint;
+    return efAllowMulticolumn | efAllowMultipoint | efAllowMultipleDataSets;
 }
 
 
@@ -712,7 +747,11 @@ void
 AnalysisDataWeightedHistogramModule::dataStarted(AbstractAnalysisData *data)
 {
     addModule(impl_->averager_);
-    setColumnCount(settings().binCount());
+    setDataSetCount(data->dataSetCount());
+    for (int i = 0; i < data->dataSetCount(); ++i)
+    {
+        setColumnCount(i, settings().binCount());
+    }
     notifyDataStart();
     impl_->storage_.startDataStorage(this);
 }
@@ -722,7 +761,7 @@ void
 AnalysisDataWeightedHistogramModule::frameStarted(const AnalysisDataFrameHeader &header)
 {
     AnalysisDataStorageFrame &frame = impl_->storage_.startFrame(header);
-    impl_->initFrame(&frame);
+    impl_->initFrame(dataSetCount(), &frame);
 }
 
 
@@ -738,6 +777,7 @@ AnalysisDataWeightedHistogramModule::pointsAdded(const AnalysisDataPointSetRef &
     {
         AnalysisDataStorageFrame &frame =
             impl_->storage_.currentFrame(points.frameIndex());
+        frame.selectDataSet(points.dataSetIndex());
         for (int i = 1; i < points.columnCount(); ++i)
         {
             frame.value(bin) += points.y(i);
@@ -788,9 +828,9 @@ class AnalysisDataBinAverageModule::Impl
         }
 
         //! Histogram settings.
-        AnalysisHistogramSettings  settings_;
-        //! Averaging helper object.
-        AnalysisDataFrameAverager  averager_;
+        AnalysisHistogramSettings               settings_;
+        //! Averaging helper objects for each input data set.
+        std::vector<AnalysisDataFrameAverager>  averagers_;
 };
 
 AnalysisDataBinAverageModule::AnalysisDataBinAverageModule()
@@ -804,7 +844,6 @@ AnalysisDataBinAverageModule::AnalysisDataBinAverageModule(
         const AnalysisHistogramSettings &settings)
     : impl_(new Impl(settings))
 {
-    setColumnCount(3);
     setRowCount(settings.binCount());
     setXAxis(settings.firstEdge() + 0.5 * settings.binWidth(),
              settings.binWidth());
@@ -836,14 +875,19 @@ AnalysisDataBinAverageModule::settings() const
 int
 AnalysisDataBinAverageModule::flags() const
 {
-    return efAllowMulticolumn | efAllowMultipoint;
+    return efAllowMulticolumn | efAllowMultipoint | efAllowMultipleDataSets;
 }
 
 
 void
-AnalysisDataBinAverageModule::dataStarted(AbstractAnalysisData * /*data*/)
+AnalysisDataBinAverageModule::dataStarted(AbstractAnalysisData *data)
 {
-    impl_->averager_.setColumnCount(rowCount());
+    setColumnCount(data->dataSetCount());
+    impl_->averagers_.resize(data->dataSetCount());
+    for (int i = 0; i < data->dataSetCount(); ++i)
+    {
+        impl_->averagers_[i].setColumnCount(rowCount());
+    }
 }
 
 
@@ -863,9 +907,10 @@ AnalysisDataBinAverageModule::pointsAdded(const AnalysisDataPointSetRef &points)
     int bin = settings().findBin(points.y(0));
     if (bin != -1)
     {
+        AnalysisDataFrameAverager &averager = impl_->averagers_[points.dataSetIndex()];
         for (int i = 1; i < points.columnCount(); ++i)
         {
-            impl_->averager_.addValue(bin, points.y(i));
+            averager.addValue(bin, points.y(i));
         }
     }
 }
@@ -880,13 +925,16 @@ AnalysisDataBinAverageModule::frameFinished(const AnalysisDataFrameHeader & /*he
 void
 AnalysisDataBinAverageModule::dataFinished()
 {
-    impl_->averager_.finish();
     allocateValues();
-    for (int i = 0; i < settings().binCount(); ++i)
+    for (int i = 0; i < columnCount(); ++i)
     {
-        setValue(i, 0, impl_->averager_.average(i));
-        setValue(i, 1, std::sqrt(impl_->averager_.variance(i)));
-        setValue(i, 2, impl_->averager_.sampleCount(i));
+        AnalysisDataFrameAverager &averager = impl_->averagers_[i];
+        averager.finish();
+        for (int j = 0; j < rowCount(); ++j)
+        {
+            value(j, i).setValue(averager.average(j),
+                                 std::sqrt(averager.variance(j)));
+        }
     }
     valuesReady();
 }
index aa002e45c5f2319a55743db5ff6531f574d25b1a..58d18bd42abe8ea8b4ed4befaaeef2e14fd27e43 100644 (file)
@@ -259,6 +259,9 @@ typedef gmx_unique_ptr<AbstractAverageHistogram>::type
  * the main use of the object is to postprocess the histogram once the
  * calculation is finished.
  *
+ * This class can represent multiple histograms in one object: each column in
+ * the data is an independent histogram.
+ *
  * \inpublicapi
  * \ingroup module_analysisdata
  */
@@ -292,10 +295,12 @@ class AbstractAverageHistogram : public AbstractAnalysisArrayData
         AverageHistogramPointer clone() const;
         //! Normalizes the histogram such that the integral over it is one.
         void normalizeProbability();
-        //! Scales the value of each bin by an uniform scaling factor.
-        void scale(real norm);
+        //! Scales a single histogram by a uniform scaling factor.
+        void scaleSingle(int index, real factor);
+        //! Scales all histograms by a uniform scaling factor.
+        void scaleAll(real factor);
         //! Scales the value of each bin by a different scaling factor.
-        void scaleVector(real norm[]);
+        void scaleAllByVector(real factor[]);
         /*! \brief
          * Notifies attached modules of the histogram data.
          *
@@ -330,10 +335,13 @@ class AbstractAverageHistogram : public AbstractAnalysisArrayData
 /*! \brief
  * Data module for per-frame histograms.
  *
- * Output data contains the same number of frames as the input data.
- * Each frame contains the histogram for the points in that frame.
- * All input columns are averaged into the same histogram.
- * The number of columns equals the number of bins in the histogram.
+ * Output data contains the same number of frames and data sets as the input
+ * data.  Each frame contains the histogram(s) for the points in that frame.
+ * Each input data set is processed independently into the corresponding output
+ * data set.  Missing values are ignored.
+ * All input columns for a data set are averaged into the same histogram.
+ * The number of columns for all data sets equals the number of bins in the
+ * histogram.
  *
  * \inpublicapi
  * \ingroup module_analysisdata
@@ -392,13 +400,17 @@ class AnalysisDataSimpleHistogramModule : public AbstractAnalysisData,
 /*! \brief
  * Data module for per-frame weighted histograms.
  *
- * Output data contains the same number of frames as the input data.
- * Each frame contains the histogram for the points in that frame, interpreted
- * such that the first column passed to pointsAdded() determines the bin and
- * the rest give weights to be added to that bin (input data should have at
- * least two colums, and at least two columns should be added at the same time).
- * All input columns are averaged into the same histogram.
- * The number of columns equals the number of bins in the histogram.
+ * Output data contains the same number of frames and data sets as the input
+ * data.  Each frame contains the histogram(s) for the points in that frame,
+ * interpreted such that the first column passed to pointsAdded() determines
+ * the bin and the rest give weights to be added to that bin (input data should
+ * have at least two colums, and at least two columns should be added at the
+ * same time).
+ * Each input data set is processed independently into the corresponding output
+ * data set.
+ * All input columns for a data set are averaged into the same histogram.
+ * The number of columns for all data sets equals the number of bins in the
+ * histogram.
  *
  * \inpublicapi
  * \ingroup module_analysisdata
@@ -444,14 +456,14 @@ class AnalysisDataWeightedHistogramModule : public AbstractAnalysisData,
  * Data module for bin averages.
  *
  * Output data contains one row for each bin; see AbstractAverageHistogram.
- * Output data contains three columns: the first is the average over all frames
- * for that bin, the second is the standard deviation of the values, and the
- * third is the number of samples in that bin.
+ * Output data contains one column for each input data set.
+ * The value in a column is the average over all frames of that data set for
+ * that bin.
  * The input data is interpreted such that the first column passed to
  * pointsAdded() determines the bin and the rest give values to be added to
  * that bin (input data should have at least two colums, and at least two
  * columns should be added at the same time).
- * All input columns are averaged into the same histogram.
+ * All input columns for a data set are averaged into the same histogram.
  *
  * \inpublicapi
  * \ingroup module_analysisdata
diff --git a/src/gromacs/analysisdata/modules/lifetime.cpp b/src/gromacs/analysisdata/modules/lifetime.cpp
new file mode 100644 (file)
index 0000000..9426ffe
--- /dev/null
@@ -0,0 +1,275 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2013, 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.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, 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 http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+/*! \internal \file
+ * \brief
+ * Implements gmx::AnalysisDataLifetimeModule.
+ *
+ * \author Teemu Murtola <teemu.murtola@gmail.com>
+ * \ingroup module_analysisdata
+ */
+#include "lifetime.h"
+
+#include <cmath>
+
+#include <deque>
+#include <vector>
+
+#include "gromacs/analysisdata/dataframe.h"
+#include "gromacs/analysisdata/datastorage.h"
+
+namespace gmx
+{
+
+/********************************************************************
+ * AnalysisDataLifetimeModule
+ */
+
+/*! \internal \brief
+ * Private implementation class for AnalysisDataLifetimeModule.
+ *
+ * \ingroup module_analysisdata
+ */
+class AnalysisDataLifetimeModule::Impl
+{
+    public:
+        //! Container type for storing a histogram during the calculation.
+        typedef std::deque<int> LifetimeHistogram;
+
+        //! Initializes the implementation class with empty/default values.
+        Impl() : firstx_(0.0), lastx_(0.0), frameCount_(0), bCumulative_(false)
+        {
+        }
+
+        /*! \brief
+         * Increments a lifetime histogram with a single lifetime.
+         *
+         * \param[in] dataSet   Index of the histogram to increment.
+         * \param[in] lifetime  Lifetime to add to the histogram.
+         */
+        void addLifetime(int dataSet, int lifetime)
+        {
+            if (lifetime > 0)
+            {
+                LifetimeHistogram &histogram = lifetimeHistograms_[dataSet];
+                if (histogram.size() < static_cast<unsigned>(lifetime))
+                {
+                    histogram.resize(lifetime, 0);
+                }
+                ++histogram[lifetime - 1];
+            }
+        }
+
+        //! X value of the first frame (used for determining output spacing).
+        real                            firstx_;
+        //! X value of the last frame (used for determining output spacing).
+        real                            lastx_;
+        //! Total number of frames (used for normalization and output spacing).
+        int                             frameCount_;
+        //! Whether to add subintervals of longer intervals explicitly.
+        bool                            bCumulative_;
+        /*! \brief
+         * Length of current continuously present interval for each data column.
+         *
+         * While frame N has been processed, stores the length of an interval
+         * for each data column where that column has been continuously present
+         * up to and including frame N.
+         */
+        std::vector<std::vector<int> >  currentLifetimes_;
+        /*! \brief
+         * Accumulated lifetime histograms for each data set.
+         */
+        std::vector<LifetimeHistogram>  lifetimeHistograms_;
+};
+
+AnalysisDataLifetimeModule::AnalysisDataLifetimeModule()
+    : impl_(new Impl())
+{
+}
+
+AnalysisDataLifetimeModule::~AnalysisDataLifetimeModule()
+{
+}
+
+void AnalysisDataLifetimeModule::setCumulative(bool bCumulative)
+{
+    impl_->bCumulative_ = bCumulative;
+}
+
+int AnalysisDataLifetimeModule::flags() const
+{
+    return efAllowMulticolumn | efAllowMissing | efAllowMultipleDataSets;
+}
+
+void
+AnalysisDataLifetimeModule::dataStarted(AbstractAnalysisData *data)
+{
+    impl_->currentLifetimes_.reserve(data->dataSetCount());
+    impl_->lifetimeHistograms_.reserve(data->dataSetCount());
+    for (int i = 0; i < data->dataSetCount(); ++i)
+    {
+        impl_->currentLifetimes_.push_back(std::vector<int>(data->columnCount(i), 0));
+        impl_->lifetimeHistograms_.push_back(std::deque<int>());
+    }
+}
+
+void
+AnalysisDataLifetimeModule::frameStarted(const AnalysisDataFrameHeader &header)
+{
+    if (header.index() == 0)
+    {
+        impl_->firstx_ = header.x();
+    }
+    impl_->lastx_ = header.x();
+    ++impl_->frameCount_;
+    // TODO: Check the input for even spacing.
+}
+
+void
+AnalysisDataLifetimeModule::pointsAdded(const AnalysisDataPointSetRef &points)
+{
+    const int dataSet = points.dataSetIndex();
+    // This assumption is strictly not necessary, but this is how the
+    // framework works currently, and makes the code below simpler.
+    GMX_ASSERT(points.firstColumn() == 0
+               && points.lastColumn() == static_cast<int>(impl_->currentLifetimes_[dataSet].size()) - 1,
+               "Point set should cover all columns");
+    for (int i = 0; i < points.columnCount(); ++i)
+    {
+        // TODO: Perhaps add control over how this is determined?
+        const bool bPresent = points.present(i) && points.y(i) > 0.0;
+        if (bPresent)
+        {
+            ++impl_->currentLifetimes_[dataSet][i];
+        }
+        else if (impl_->currentLifetimes_[dataSet][i] > 0)
+        {
+            impl_->addLifetime(dataSet, impl_->currentLifetimes_[dataSet][i]);
+            impl_->currentLifetimes_[dataSet][i] = 0;
+        }
+    }
+}
+
+void
+AnalysisDataLifetimeModule::frameFinished(const AnalysisDataFrameHeader & /*header*/)
+{
+}
+
+void
+AnalysisDataLifetimeModule::dataFinished()
+{
+    // Need to process the elements present in the last frame explicitly.
+    for (size_t i = 0; i < impl_->currentLifetimes_.size(); ++i)
+    {
+        for (size_t j = 0; j < impl_->currentLifetimes_[i].size(); ++j)
+        {
+            impl_->addLifetime(i, impl_->currentLifetimes_[i][j]);
+        }
+    }
+    impl_->currentLifetimes_.clear();
+
+    if (impl_->bCumulative_)
+    {
+        // Sum up subintervals of longer intervals into the histograms
+        // if explicitly requested.
+        std::vector<Impl::LifetimeHistogram>::iterator histogram;
+        for (histogram  = impl_->lifetimeHistograms_.begin();
+             histogram != impl_->lifetimeHistograms_.end();
+             ++histogram)
+        {
+            Impl::LifetimeHistogram::iterator shorter, longer;
+            for (shorter = histogram->begin(); shorter != histogram->end(); ++shorter)
+            {
+                int subIntervalCount = 2;
+                for (longer = shorter + 1; longer != histogram->end();
+                     ++longer, ++subIntervalCount)
+                {
+                    // Interval of length shorter contains (longer - shorter + 1)
+                    // continuous intervals of length longer.
+                    *shorter += subIntervalCount * (*longer);
+                }
+            }
+        }
+    }
+
+    // X spacing is determined by averaging from the first and last frame
+    // instead of first two frames to avoid rounding issues.
+    const real spacing =
+        (impl_->frameCount_ > 1)
+        ? (impl_->lastx_ - impl_->firstx_) / (impl_->frameCount_ - 1)
+        : 0.0;
+    setXAxis(0.0, spacing);
+
+    // Determine output dimensionality to cover all the histograms.
+    setColumnCount(impl_->lifetimeHistograms_.size());
+    std::vector<Impl::LifetimeHistogram>::const_iterator histogram;
+    size_t maxLifetime = 1;
+    for (histogram  = impl_->lifetimeHistograms_.begin();
+         histogram != impl_->lifetimeHistograms_.end();
+         ++histogram)
+    {
+        maxLifetime = std::max(maxLifetime, histogram->size());
+    }
+    setRowCount(maxLifetime);
+
+    // Fill up the output data from the histograms.
+    allocateValues();
+    int column = 0;
+    for (histogram  = impl_->lifetimeHistograms_.begin();
+         histogram != impl_->lifetimeHistograms_.end();
+         ++histogram, ++column)
+    {
+        int row = 0;
+        Impl::LifetimeHistogram::const_iterator i;
+        for (i = histogram->begin(); i != histogram->end(); ++i, ++row)
+        {
+            // Normalize by the number of frames, taking into account the
+            // length of the interval (interval of length N cannot start in
+            // N-1 last frames).  row is always smaller than frameCount_
+            // because of the histograms have at most frameCount_ entries.
+            const real normalized = *i / static_cast<real>(impl_->frameCount_ - row);
+            value(row, column).setValue(normalized);
+        }
+        // Pad the rest of the histogram with zeros to match the longest
+        // histogram.
+        for (; row < rowCount(); ++row)
+        {
+            value(row, column).setValue(0.0);
+        }
+    }
+    impl_->lifetimeHistograms_.clear();
+    valuesReady();
+}
+
+} // namespace gmx
diff --git a/src/gromacs/analysisdata/modules/lifetime.h b/src/gromacs/analysisdata/modules/lifetime.h
new file mode 100644 (file)
index 0000000..4e225dc
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2013, 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.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, 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 http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+/*! \file
+ * \brief
+ * Declares gmx::AnalysisDataLifetimeModule.
+ *
+ * \author Teemu Murtola <teemu.murtola@gmail.com>
+ * \inpublicapi
+ * \ingroup module_analysisdata
+ */
+#ifndef GMX_ANALYSISDATA_MODULES_LIFETIME_H
+#define GMX_ANALYSISDATA_MODULES_LIFETIME_H
+
+#include "../arraydata.h"
+#include "../datamodule.h"
+#include "../../utility/common.h"
+
+namespace gmx
+{
+
+/*! \brief
+ * Data module for computing lifetime histograms for columns in input data.
+ *
+ * The input data set is treated as a boolean array: each value that is present
+ * (AnalysisDataValue::isPresent() returns true) and is >0 is treated as
+ * present, other values are treated as absent.
+ * For each input data set, analyzes the columns to identify the intervals
+ * where a column is continuously present.
+ * Produces a histogram from the lengths of these intervals.
+ * Input data should have frames with evenly spaced x values.
+ *
+ * Output data contains one column for each data set in the input data.
+ * This column gives the lifetime histogram for the corresponding data set.
+ * x axis in the output is spaced the same as in the input data, and extends
+ * as long as required to cover all the histograms.
+ * Histograms are padded with zeros as required to be of the same length.
+ * setCumulative() can be used to alter the handling of subintervals in the
+ * output histogram.
+ *
+ * The output data becomes available only after the input data has been
+ * finished.
+ *
+ * \inpublicapi
+ * \ingroup module_analysisdata
+ */
+class AnalysisDataLifetimeModule : public AbstractAnalysisArrayData,
+                                   public AnalysisDataModuleInterface
+{
+    public:
+        AnalysisDataLifetimeModule();
+        virtual ~AnalysisDataLifetimeModule();
+
+        /*! \brief
+         * Sets a cumulative histogram mode.
+         *
+         * \param[in] bCumulative If true, all subintervals of a long
+         *   interval are also explicitly added into the histogram.
+         *
+         * Does not throw.
+         */
+        void setCumulative(bool bCumulative);
+
+        virtual int flags() const;
+
+        virtual void dataStarted(AbstractAnalysisData *data);
+        virtual void frameStarted(const AnalysisDataFrameHeader &header);
+        virtual void pointsAdded(const AnalysisDataPointSetRef &points);
+        virtual void frameFinished(const AnalysisDataFrameHeader &header);
+        virtual void dataFinished();
+
+    private:
+        class Impl;
+
+        PrivateImplPointer<Impl> impl_;
+};
+
+//! Smart pointer to manage an AnalysisDataLifetimeModule object.
+typedef boost::shared_ptr<AnalysisDataLifetimeModule>
+    AnalysisDataLifetimeModulePointer;
+
+} // namespace gmx
+
+#endif
index b3db5ea4faa2964fa26dc32808e93d159030e11e..c716bed0000ff8d87b3b918cbacad7df32433b42 100644 (file)
@@ -54,8 +54,8 @@
 #include "gromacs/legacyheaders/vec.h"
 #include "gromacs/legacyheaders/xvgr.h"
 
-#include "gromacs/options/basicoptions.h"
 #include "gromacs/analysisdata/dataframe.h"
+#include "gromacs/options/basicoptions.h"
 #include "gromacs/options/options.h"
 #include "gromacs/options/timeunitmanager.h"
 #include "gromacs/selection/selectioncollection.h"
@@ -119,7 +119,8 @@ class AbstractPlotModule::Impl
         FILE                     *fp_;
 
         bool                      bPlain_;
-        bool                      gOmitX_;
+        bool                      bOmitX_;
+        bool                      bErrorsAsSeparateColumn_;
         std::string               title_;
         std::string               subtitle_;
         std::string               xlabel_;
@@ -131,8 +132,8 @@ class AbstractPlotModule::Impl
 };
 
 AbstractPlotModule::Impl::Impl(const AnalysisDataPlotSettings &settings)
-    : settings_(settings), fp_(NULL), bPlain_(false), gOmitX_(false),
-      xscale_(1.0)
+    : settings_(settings), fp_(NULL), bPlain_(false), bOmitX_(false),
+      bErrorsAsSeparateColumn_(false), xscale_(1.0)
 {
     strcpy(xformat_, "%11.3f");
     strcpy(yformat_, " %8.3f");
@@ -203,10 +204,17 @@ AbstractPlotModule::setPlainOutput(bool bPlain)
 }
 
 
+void
+AbstractPlotModule::setErrorsAsSeparateColumn(bool bSeparate)
+{
+    impl_->bErrorsAsSeparateColumn_ = bSeparate;
+}
+
+
 void
 AbstractPlotModule::setOmitX(bool bOmitX)
 {
-    impl_->gOmitX_ = bOmitX;
+    impl_->bOmitX_ = bOmitX;
 }
 
 
@@ -292,12 +300,13 @@ AbstractPlotModule::setYFormat(int width, int precision, char format)
 int
 AbstractPlotModule::flags() const
 {
-    return efAllowMulticolumn | efAllowMultipoint;
+    return efAllowMissing | efAllowMulticolumn | efAllowMultipoint
+           | efAllowMultipleDataSets;
 }
 
 
 void
-AbstractPlotModule::dataStarted(AbstractAnalysisData *data)
+AbstractPlotModule::dataStarted(AbstractAnalysisData * /*data*/)
 {
     if (!impl_->filename_.empty())
     {
@@ -352,7 +361,7 @@ AbstractPlotModule::frameStarted(const AnalysisDataFrameHeader &frame)
     {
         return;
     }
-    if (!impl_->gOmitX_)
+    if (!impl_->bOmitX_)
     {
         std::fprintf(impl_->fp_, impl_->xformat_, frame.x() * impl_->xscale_);
     }
@@ -385,10 +394,16 @@ AbstractPlotModule::isFileOpen() const
 
 
 void
-AbstractPlotModule::writeValue(real value) const
+AbstractPlotModule::writeValue(const AnalysisDataValue &value) const
 {
     GMX_ASSERT(isFileOpen(), "File not opened, but write attempted");
-    std::fprintf(impl_->fp_, impl_->yformat_, value);
+    const real y = value.isSet() ? value.value() : 0.0;
+    std::fprintf(impl_->fp_, impl_->yformat_, y);
+    if (impl_->bErrorsAsSeparateColumn_)
+    {
+        const real dy = value.isSet() ? value.error() : 0.0;
+        std::fprintf(impl_->fp_, impl_->yformat_, dy);
+    }
 }
 //! \endcond
 
@@ -416,7 +431,7 @@ AnalysisDataPlotModule::pointsAdded(const AnalysisDataPointSetRef &points)
     }
     for (int i = 0; i < points.columnCount(); ++i)
     {
-        writeValue(points.y(i));
+        writeValue(points.values()[i]);
     }
 }
 
@@ -488,7 +503,7 @@ AnalysisDataVectorPlotModule::setWriteMask(bool bWrite[DIM + 1])
 void
 AnalysisDataVectorPlotModule::pointsAdded(const AnalysisDataPointSetRef &points)
 {
-    if (points.firstColumn() % DIM != 0)
+    if (points.firstColumn() % DIM != 0 || points.columnCount() % DIM != 0)
     {
         GMX_THROW(APIError("Partial data points"));
     }
@@ -502,13 +517,14 @@ AnalysisDataVectorPlotModule::pointsAdded(const AnalysisDataPointSetRef &points)
         {
             if (bWrite_[i])
             {
-                writeValue(points.y(i + d));
+                writeValue(points.values()[i + d]);
             }
         }
         if (bWrite_[DIM])
         {
-            rvec y = { points.y(i), points.y(i + 1), points.y(i + 2) };
-            writeValue(norm(y));
+            const rvec        y = { points.y(i), points.y(i + 1), points.y(i + 2) };
+            AnalysisDataValue value(norm(y));
+            writeValue(value);
         }
     }
 }
index f0fd168d6e676571712919cad5bf0850d5d53338..1f0983ba3fc273cb59259298cb59685c8058e53d 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2010,2011,2012, by the GROMACS development team, led by
+ * Copyright (c) 2010,2011,2012,2013, 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.
@@ -54,6 +54,7 @@
 namespace gmx
 {
 
+class AnalysisDataValue;
 class Options;
 class SelectionCollection;
 
@@ -124,15 +125,18 @@ class AnalysisDataPlotSettings
  * straightforward plotting).
  *
  * By default, the data is written into an xvgr file, according to the
- * options read from the Options object given to the constructor.
+ * options read from the AnalysisDataPlotSettings object given to the
+ * constructor.
  * For non-xvgr data, it's possible to skip all headers by calling
  * setPlainOutput().
  *
- * Multipoint data is supported, in which case all the points are written to
- * the output, in the order in which they are added to the data.  A single
- * output line corresponds to a single frame.  In most cases with multipoint
- * data, setPlainOutput() should be called since the output does not make sense
- * as an xvgr file, but this is not enforced.
+ * A single output line corresponds to a single frame.  In most cases with
+ * multipoint data, setPlainOutput() should be called since the output does not
+ * make sense as an xvgr file, but this is not enforced.
+ *
+ * Multipoint data and multiple data sets are both supported, in which case all
+ * the points are written to the output, in the order in which they are added
+ * to the data.
  *
  * \ingroup module_analysisdata
  */
@@ -159,6 +163,10 @@ class AbstractPlotModule : public AnalysisDataModuleInterface
          * methods have any effect on the output.
          */
         void setPlainOutput(bool bPlain);
+        /*! \brief
+         * Plot errors as a separate output column after each value column.
+         */
+        void setErrorsAsSeparateColumn(bool bSeparate);
         /*! \brief
          * Omit the X coordinates from the output.
          *
@@ -237,7 +245,7 @@ class AbstractPlotModule : public AnalysisDataModuleInterface
          *
          * Must not be called if isFileOpen() returns false.
          */
-        void writeValue(real value) const;
+        void writeValue(const AnalysisDataValue &value) const;
         //! \endcond
 
     private:
index 1d607cce4c7ff8fdb2a188f9dfa25ae31bd07dd6..9c9bef91bab5c4e069567e9b774fe6b7ab58bcd7 100644 (file)
@@ -1,7 +1,7 @@
 #
 # This file is part of the GROMACS molecular simulation package.
 #
-# Copyright (c) 2011,2012, by the GROMACS development team, led by
+# Copyright (c) 2011,2012,2013, 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.
@@ -36,4 +36,5 @@ gmx_add_unit_test(AnalysisDataUnitTests analysisdata-test
                   analysisdata.cpp
                   arraydata.cpp
                   average.cpp
-                  histogram.cpp)
+                  histogram.cpp
+                  lifetime.cpp)
index 008dce536e342675380b8ba92891817350cf8ee3..2448bdba101da10da4c7d481abcfe6e1b64d4731 100644 (file)
@@ -73,20 +73,33 @@ namespace
 TEST(AnalysisDataInitializationTest, BasicInitialization)
 {
     gmx::AnalysisData data;
+    EXPECT_EQ(1, data.dataSetCount());
+    EXPECT_EQ(0, data.columnCount(0));
     EXPECT_EQ(0, data.columnCount());
     EXPECT_FALSE(data.isMultipoint());
     EXPECT_EQ(0, data.frameCount());
 
-    data.setColumnCount(1);
+    data.setColumnCount(0, 1);
+    EXPECT_EQ(1, data.columnCount(0));
     EXPECT_EQ(1, data.columnCount());
     EXPECT_FALSE(data.isMultipoint());
 
-    data.setColumnCount(3);
+    data.setDataSetCount(2);
+    EXPECT_EQ(2, data.dataSetCount());
+    data.setColumnCount(0, 3);
+    EXPECT_EQ(3, data.columnCount(0));
+    EXPECT_EQ(0, data.columnCount(1));
+    data.setColumnCount(1, 2);
+    EXPECT_EQ(3, data.columnCount(0));
+    EXPECT_EQ(2, data.columnCount(1));
+
+    data.setDataSetCount(1);
+    EXPECT_EQ(1, data.dataSetCount());
     data.setMultipoint(true);
     EXPECT_EQ(3, data.columnCount());
     EXPECT_TRUE(data.isMultipoint());
 
-    data.setColumnCount(1);
+    data.setColumnCount(0, 1);
     EXPECT_EQ(1, data.columnCount());
     EXPECT_TRUE(data.isMultipoint());
 }
@@ -98,7 +111,7 @@ TEST(AnalysisDataInitializationTest, BasicInitialization)
 TEST(AnalysisDataInitializationTest, ChecksMultiColumnModules)
 {
     gmx::AnalysisData data;
-    data.setColumnCount(2);
+    data.setColumnCount(0, 2);
 
     MockAnalysisDataModulePointer mod1(new MockAnalysisDataModule(0));
     EXPECT_THROW_GMX(data.addModule(mod1), gmx::APIError);
@@ -112,10 +125,10 @@ TEST(AnalysisDataInitializationTest, ChecksMultiColumnModules)
  * Tests that checking for compatibility of modules with multipoint data
  * works.
  */
-TEST(AnalysisDataInitializationTest, ChecksMultiPointModules)
+TEST(AnalysisDataInitializationTest, ChecksMultipointModules)
 {
     gmx::AnalysisData data;
-    data.setColumnCount(1);
+    data.setColumnCount(0, 1);
     data.setMultipoint(true);
 
     MockAnalysisDataModulePointer mod1(new MockAnalysisDataModule(0));
@@ -141,8 +154,9 @@ class SimpleInputData
             return singleton.data_;
         }
 
-        SimpleInputData() : data_(3, false)
+        SimpleInputData() : data_(1, false)
         {
+            data_.setColumnCount(0, 3);
             data_.addFrameWithValues(1.0,  0.0, 1.0, 2.0);
             data_.addFrameWithValues(2.0,  1.0, 1.0, 1.0);
             data_.addFrameWithValues(3.0,  2.0, 0.0, 0.0);
@@ -152,6 +166,36 @@ class SimpleInputData
         AnalysisDataTestInput  data_;
 };
 
+// Input data with multiple data sets for gmx::AnalysisData tests.
+class DataSetsInputData
+{
+    public:
+        static const AnalysisDataTestInput &get()
+        {
+            static DataSetsInputData singleton;
+            return singleton.data_;
+        }
+
+        DataSetsInputData() : data_(2, false)
+        {
+            using gmx::test::AnalysisDataTestInputFrame;
+            data_.setColumnCount(0, 3);
+            data_.setColumnCount(1, 2);
+            AnalysisDataTestInputFrame &frame1 = data_.addFrame(1.0);
+            frame1.addPointSetWithValues(0, 0, 0.0, 1.0, 2.0);
+            frame1.addPointSetWithValues(1, 0, 2.1, 1.1);
+            AnalysisDataTestInputFrame &frame2 = data_.addFrame(2.0);
+            frame2.addPointSetWithValues(0, 0, 1.0, 1.0, 1.0);
+            frame2.addPointSetWithValues(1, 0, 0.1, 2.1);
+            AnalysisDataTestInputFrame &frame3 = data_.addFrame(3.0);
+            frame3.addPointSetWithValues(0, 0, 2.0, 0.0, 0.0);
+            frame3.addPointSetWithValues(1, 0, 1.1, 1.1);
+        }
+
+    private:
+        AnalysisDataTestInput  data_;
+};
+
 // Input data for multipoint gmx::AnalysisData tests.
 class MultipointInputData
 {
@@ -162,21 +206,55 @@ class MultipointInputData
             return singleton.data_;
         }
 
-        MultipointInputData() : data_(3, true)
+        MultipointInputData() : data_(1, true)
+        {
+            using gmx::test::AnalysisDataTestInputFrame;
+            data_.setColumnCount(0, 3);
+            AnalysisDataTestInputFrame &frame1 = data_.addFrame(1.0);
+            frame1.addPointSetWithValues(0, 0, 0.0, 1.0, 2.0);
+            frame1.addPointSetWithValues(0, 0, 1.1, 2.1, 1.1);
+            frame1.addPointSetWithValues(0, 0, 2.2, 1.2, 0.2);
+            AnalysisDataTestInputFrame &frame2 = data_.addFrame(2.0);
+            frame2.addPointSetWithValues(0, 1, 1.0, 1.0);
+            frame2.addPointSetWithValues(0, 0, 2.1, 1.1, 0.1);
+            frame2.addPointSetWithValues(0, 2, 1.2);
+            AnalysisDataTestInputFrame &frame3 = data_.addFrame(3.0);
+            frame3.addPointSetWithValues(0, 0, 2.0, 0.0, 0.0);
+            frame3.addPointSetWithValues(0, 0, 3.1, 2.1);
+            frame3.addPointSetWithValues(0, 1, 2.2, 1.2);
+        }
+
+    private:
+        AnalysisDataTestInput  data_;
+};
+
+// Input data with multiple multipoint data sets for gmx::AnalysisData tests.
+class MultipointDataSetsInputData
+{
+    public:
+        static const AnalysisDataTestInput &get()
+        {
+            static MultipointDataSetsInputData singleton;
+            return singleton.data_;
+        }
+
+        MultipointDataSetsInputData() : data_(2, true)
         {
             using gmx::test::AnalysisDataTestInputFrame;
+            data_.setColumnCount(0, 3);
+            data_.setColumnCount(1, 2);
             AnalysisDataTestInputFrame &frame1 = data_.addFrame(1.0);
-            frame1.addPointSetWithValues(0, 0.0, 1.0, 2.0);
-            frame1.addPointSetWithValues(0, 1.1, 2.1, 1.1);
-            frame1.addPointSetWithValues(0, 2.2, 1.2, 0.2);
+            frame1.addPointSetWithValues(0, 0, 0.0, 1.0, 2.0);
+            frame1.addPointSetWithValues(0, 1, 2.1, 1.1);
+            frame1.addPointSetWithValues(1, 0, 2.01, 1.01);
+            frame1.addPointSetWithValues(1, 1, 0.11);
             AnalysisDataTestInputFrame &frame2 = data_.addFrame(2.0);
-            frame2.addPointSetWithValues(1, 1.0, 1.0);
-            frame2.addPointSetWithValues(0, 2.1, 1.1, 0.1);
-            frame2.addPointSetWithValues(2, 1.2);
+            frame2.addPointSetWithValues(0, 0, 1.0, 1.0, 1.0);
+            frame2.addPointSetWithValues(0, 0, 0.1, 2.1);
+            frame2.addPointSetWithValues(1, 1, 1.01);
             AnalysisDataTestInputFrame &frame3 = data_.addFrame(3.0);
-            frame3.addPointSetWithValues(0, 2.0, 0.0, 0.0);
-            frame3.addPointSetWithValues(0, 3.1, 2.1);
-            frame3.addPointSetWithValues(1, 2.2, 1.2);
+            frame3.addPointSetWithValues(0, 0, 2.0, 0.0, 0.0);
+            frame3.addPointSetWithValues(0, 1, 1.1);
         }
 
     private:
@@ -239,7 +317,11 @@ typedef AnalysisDataCommonTest<SimpleInputData>     AnalysisDataSimpleTest;
 //! Test fixture for tests that are only applicable to multipoint data.
 typedef AnalysisDataCommonTest<MultipointInputData> AnalysisDataMultipointTest;
 //! List of input data types for tests applicable to all types of data.
-typedef ::testing::Types<SimpleInputData, MultipointInputData> AllInputDataTypes;
+typedef ::testing::Types<SimpleInputData,
+                         DataSetsInputData,
+                         MultipointInputData,
+                         MultipointDataSetsInputData>
+    AllInputDataTypes;
 TYPED_TEST_CASE(AnalysisDataCommonTest, AllInputDataTypes);
 
 /*
index 1e861432bf0ddd65ac6adb3cff99e801c3bdd627..258212a26712cf8e8b47a34e101ef1bb09f27b4e 100644 (file)
@@ -73,8 +73,9 @@ class SimpleInputData
             return singleton.data_;
         }
 
-        SimpleInputData() : data_(3, false)
+        SimpleInputData() : data_(1, false)
         {
+            data_.setColumnCount(0, 3);
             data_.addFrameWithValues(1.0,  0.0, 1.0, 2.0);
             data_.addFrameWithValues(2.0,  1.0, 1.0, 1.0);
             data_.addFrameWithValues(3.0,  2.0, 0.0, 0.0);
index e45d1c256f2fcc4406260c94fedd49833017883a..1528dcd07936540c316ed988d4d1d44df3094a1c 100644 (file)
@@ -69,8 +69,9 @@ class SimpleInputData
             return singleton.data_;
         }
 
-        SimpleInputData() : data_(3, false)
+        SimpleInputData() : data_(1, false)
         {
+            data_.setColumnCount(0, 3);
             data_.addFrameWithValues(1.0,  0.0, 1.0, 2.0);
             data_.addFrameWithValues(2.0,  1.0, 1.0, 1.0);
             data_.addFrameWithValues(3.0,  2.0, 0.0, 0.0);
@@ -90,18 +91,52 @@ class MultipointInputData
             return singleton.data_;
         }
 
-        MultipointInputData() : data_(3, true)
+        MultipointInputData() : data_(1, true)
         {
             using gmx::test::AnalysisDataTestInputFrame;
+            data_.setColumnCount(0, 3);
             AnalysisDataTestInputFrame &frame1 = data_.addFrame(1.0);
-            frame1.addPointSetWithValues(0, 0.0, 1.0, 2.0);
-            frame1.addPointSetWithValues(0, 1.0, 0.0);
-            frame1.addPointSetWithValues(0, 2.0);
+            frame1.addPointSetWithValues(0, 0, 0.0, 1.0, 2.0);
+            frame1.addPointSetWithValues(0, 0, 1.0, 0.0);
+            frame1.addPointSetWithValues(0, 0, 2.0);
             AnalysisDataTestInputFrame &frame2 = data_.addFrame(2.0);
-            frame2.addPointSetWithValues(0, 1.0, 1.0);
-            frame2.addPointSetWithValues(0, 2.0);
+            frame2.addPointSetWithValues(0, 0, 1.0, 1.0);
+            frame2.addPointSetWithValues(0, 0, 2.0);
             AnalysisDataTestInputFrame &frame3 = data_.addFrame(3.0);
-            frame3.addPointSetWithValues(0, 2.0, 0.0, 0.0);
+            frame3.addPointSetWithValues(0, 0, 2.0, 0.0, 0.0);
+        }
+
+    private:
+        AnalysisDataTestInput  data_;
+};
+
+// Input data with multiple data sets for gmx::AnalysisDataAverageModule tests.
+class MultiDataSetInputData
+{
+    public:
+        static const AnalysisDataTestInput &get()
+        {
+            static MultiDataSetInputData singleton;
+            return singleton.data_;
+        }
+
+        MultiDataSetInputData() : data_(2, true)
+        {
+            using gmx::test::AnalysisDataTestInputFrame;
+            data_.setColumnCount(0, 3);
+            data_.setColumnCount(1, 2);
+            AnalysisDataTestInputFrame &frame1 = data_.addFrame(1.0);
+            frame1.addPointSetWithValues(0, 0, 0.0, 1.0, 2.0);
+            frame1.addPointSetWithValues(0, 0, 1.0, 0.0);
+            frame1.addPointSetWithValues(1, 0, 2.0, 1.0);
+            frame1.addPointSetWithValues(1, 1, 2.0);
+            AnalysisDataTestInputFrame &frame2 = data_.addFrame(2.0);
+            frame2.addPointSetWithValues(0, 0, 1.0, 1.0);
+            frame2.addPointSetWithValues(0, 2, 2.0);
+            frame2.addPointSetWithValues(1, 0, 1.0, 0.0);
+            AnalysisDataTestInputFrame &frame3 = data_.addFrame(3.0);
+            frame3.addPointSetWithValues(0, 0, 2.0, 0.0, 0.0);
+            frame3.addPointSetWithValues(1, 0, 0.0, 2.0);
         }
 
     private:
@@ -148,6 +183,39 @@ TEST_F(AverageModuleTest, HandlesMultipointData)
     ASSERT_NO_THROW_GMX(presentAllData(input, &data));
 }
 
+TEST_F(AverageModuleTest, HandlesMultipleDataSets)
+{
+    const AnalysisDataTestInput &input = MultiDataSetInputData::get();
+    gmx::AnalysisData            data;
+    ASSERT_NO_THROW_GMX(setupDataObject(input, &data));
+
+    gmx::AnalysisDataAverageModulePointer module(
+            new gmx::AnalysisDataAverageModule);
+    data.addModule(module);
+
+    ASSERT_NO_THROW_GMX(addStaticCheckerModule(input, &data));
+    ASSERT_NO_THROW_GMX(addReferenceCheckerModule("InputData", &data));
+    ASSERT_NO_THROW_GMX(addReferenceCheckerModule("Average", module.get()));
+    ASSERT_NO_THROW_GMX(presentAllData(input, &data));
+}
+
+TEST_F(AverageModuleTest, HandlesDataSetAveraging)
+{
+    const AnalysisDataTestInput &input = MultiDataSetInputData::get();
+    gmx::AnalysisData            data;
+    ASSERT_NO_THROW_GMX(setupDataObject(input, &data));
+
+    gmx::AnalysisDataAverageModulePointer module(
+            new gmx::AnalysisDataAverageModule);
+    module->setAverageDataSets(true);
+    data.addModule(module);
+
+    ASSERT_NO_THROW_GMX(addStaticCheckerModule(input, &data));
+    ASSERT_NO_THROW_GMX(addReferenceCheckerModule("InputData", &data));
+    ASSERT_NO_THROW_GMX(addReferenceCheckerModule("Average", module.get()));
+    ASSERT_NO_THROW_GMX(presentAllData(input, &data));
+}
+
 TEST_F(AverageModuleTest, CanCustomizeXAxis)
 {
     const AnalysisDataTestInput &input = SimpleInputData::get();
@@ -187,4 +255,20 @@ TEST_F(FrameAverageModuleTest, BasicTest)
     ASSERT_NO_THROW_GMX(presentAllData(input, &data));
 }
 
+TEST_F(FrameAverageModuleTest, HandlesMultipleDataSets)
+{
+    const AnalysisDataTestInput &input = MultiDataSetInputData::get();
+    gmx::AnalysisData            data;
+    ASSERT_NO_THROW_GMX(setupDataObject(input, &data));
+
+    gmx::AnalysisDataFrameAverageModulePointer module(
+            new gmx::AnalysisDataFrameAverageModule);
+    data.addModule(module);
+
+    ASSERT_NO_THROW_GMX(addStaticCheckerModule(input, &data));
+    ASSERT_NO_THROW_GMX(addReferenceCheckerModule("InputData", &data));
+    ASSERT_NO_THROW_GMX(addReferenceCheckerModule("FrameAverage", module.get()));
+    ASSERT_NO_THROW_GMX(presentAllData(input, &data));
+}
+
 } // namespace
index 7f9622ada81805ab1dd0c4849d45d3036e0a2943..5182e74c6e128f11f2ef98b9e88676fcb599252a 100644 (file)
@@ -164,18 +164,19 @@ class SimpleInputData
         SimpleInputData() : data_(1, true)
         {
             using gmx::test::AnalysisDataTestInputFrame;
+            data_.setColumnCount(0, 1);
             AnalysisDataTestInputFrame &frame1 = data_.addFrame(1.0);
-            frame1.addPointSetWithValues(0, 0.7);
-            frame1.addPointSetWithValues(0, 1.1);
-            frame1.addPointSetWithValues(0, 2.3);
-            frame1.addPointSetWithValues(0, 2.9);
+            frame1.addPointSetWithValues(0, 0, 0.7);
+            frame1.addPointSetWithValues(0, 0, 1.1);
+            frame1.addPointSetWithValues(0, 0, 2.3);
+            frame1.addPointSetWithValues(0, 0, 2.9);
             AnalysisDataTestInputFrame &frame2 = data_.addFrame(2.0);
-            frame2.addPointSetWithValues(0, 1.3);
-            frame2.addPointSetWithValues(0, 2.2);
+            frame2.addPointSetWithValues(0, 0, 1.3);
+            frame2.addPointSetWithValues(0, 0, 2.2);
             AnalysisDataTestInputFrame &frame3 = data_.addFrame(3.0);
-            frame3.addPointSetWithValues(0, 3.3);
-            frame3.addPointSetWithValues(0, 1.2);
-            frame3.addPointSetWithValues(0, 1.3);
+            frame3.addPointSetWithValues(0, 0, 3.3);
+            frame3.addPointSetWithValues(0, 0, 1.2);
+            frame3.addPointSetWithValues(0, 0, 1.3);
         }
 
     private:
@@ -232,30 +233,64 @@ TEST_F(SimpleHistogramModuleTest, ComputesCorrectlyWithAll)
 typedef gmx::test::AnalysisDataTestFixture WeightedHistogramModuleTest;
 
 // Input data for both weighted histogram and bin average module tests.
-class WeightedInputData
+class WeightedSimpleInputData
 {
     public:
         static const AnalysisDataTestInput &get()
         {
-            static WeightedInputData singleton;
+            static WeightedSimpleInputData singleton;
             return singleton.data_;
         }
 
-        WeightedInputData() : data_(2, true)
+        WeightedSimpleInputData() : data_(1, true)
         {
             using gmx::test::AnalysisDataTestInputFrame;
+            data_.setColumnCount(0, 2);
             AnalysisDataTestInputFrame &frame1 = data_.addFrame(1.0);
-            frame1.addPointSetWithValues(0, 0.7, 0.5);
-            frame1.addPointSetWithValues(0, 1.1, 1.0);
-            frame1.addPointSetWithValues(0, 2.3, 1.0);
-            frame1.addPointSetWithValues(0, 2.9, 2.0);
+            frame1.addPointSetWithValues(0, 0, 0.7, 0.5);
+            frame1.addPointSetWithValues(0, 0, 1.1, 1.0);
+            frame1.addPointSetWithValues(0, 0, 2.3, 1.0);
+            frame1.addPointSetWithValues(0, 0, 2.9, 2.0);
             AnalysisDataTestInputFrame &frame2 = data_.addFrame(2.0);
-            frame2.addPointSetWithValues(0, 1.3, 1.0);
-            frame2.addPointSetWithValues(0, 2.2, 3.0);
+            frame2.addPointSetWithValues(0, 0, 1.3, 1.0);
+            frame2.addPointSetWithValues(0, 0, 2.2, 3.0);
             AnalysisDataTestInputFrame &frame3 = data_.addFrame(3.0);
-            frame3.addPointSetWithValues(0, 3.3, 0.5);
-            frame3.addPointSetWithValues(0, 1.2, 2.0);
-            frame3.addPointSetWithValues(0, 1.3, 1.0);
+            frame3.addPointSetWithValues(0, 0, 3.3, 0.5);
+            frame3.addPointSetWithValues(0, 0, 1.2, 2.0);
+            frame3.addPointSetWithValues(0, 0, 1.3, 1.0);
+        }
+
+    private:
+        AnalysisDataTestInput  data_;
+};
+
+// Input data for both weighted histogram and bin average module tests.
+class WeightedDataSetInputData
+{
+    public:
+        static const AnalysisDataTestInput &get()
+        {
+            static WeightedDataSetInputData singleton;
+            return singleton.data_;
+        }
+
+        WeightedDataSetInputData() : data_(2, true)
+        {
+            using gmx::test::AnalysisDataTestInputFrame;
+            data_.setColumnCount(0, 2);
+            data_.setColumnCount(1, 2);
+            AnalysisDataTestInputFrame &frame1 = data_.addFrame(1.0);
+            frame1.addPointSetWithValues(0, 0, 0.7, 0.5);
+            frame1.addPointSetWithValues(0, 0, 1.1, 1.0);
+            frame1.addPointSetWithValues(1, 0, 2.3, 1.0);
+            frame1.addPointSetWithValues(1, 0, 2.9, 2.0);
+            AnalysisDataTestInputFrame &frame2 = data_.addFrame(2.0);
+            frame2.addPointSetWithValues(0, 0, 1.3, 1.0);
+            frame2.addPointSetWithValues(1, 0, 2.2, 3.0);
+            AnalysisDataTestInputFrame &frame3 = data_.addFrame(3.0);
+            frame3.addPointSetWithValues(0, 0, 3.3, 0.5);
+            frame3.addPointSetWithValues(0, 0, 1.2, 2.0);
+            frame3.addPointSetWithValues(1, 0, 1.3, 1.0);
         }
 
     private:
@@ -264,7 +299,7 @@ class WeightedInputData
 
 TEST_F(WeightedHistogramModuleTest, ComputesCorrectly)
 {
-    const AnalysisDataTestInput &input = WeightedInputData::get();
+    const AnalysisDataTestInput &input = WeightedSimpleInputData::get();
     gmx::AnalysisData            data;
     ASSERT_NO_THROW_GMX(setupDataObject(input, &data));
 
@@ -285,7 +320,7 @@ TEST_F(WeightedHistogramModuleTest, ComputesCorrectly)
 
 TEST_F(WeightedHistogramModuleTest, ComputesCorrectlyWithAll)
 {
-    const AnalysisDataTestInput &input = WeightedInputData::get();
+    const AnalysisDataTestInput &input = WeightedSimpleInputData::get();
     gmx::AnalysisData            data;
     ASSERT_NO_THROW_GMX(setupDataObject(input, &data));
 
@@ -304,6 +339,27 @@ TEST_F(WeightedHistogramModuleTest, ComputesCorrectlyWithAll)
 }
 
 
+TEST_F(WeightedHistogramModuleTest, HandlesMultipleDataSets)
+{
+    const AnalysisDataTestInput &input = WeightedDataSetInputData::get();
+    gmx::AnalysisData            data;
+    ASSERT_NO_THROW_GMX(setupDataObject(input, &data));
+
+    gmx::AnalysisDataWeightedHistogramModulePointer module(
+            new gmx::AnalysisDataWeightedHistogramModule(
+                    gmx::histogramFromRange(1.0, 3.0).binCount(4)));
+    data.addModule(module);
+
+    ASSERT_NO_THROW_GMX(addStaticCheckerModule(input, &data));
+    ASSERT_NO_THROW_GMX(addReferenceCheckerModule("InputData", &data));
+    ASSERT_NO_THROW_GMX(addReferenceCheckerModule("Histogram", module.get()));
+    ASSERT_NO_THROW_GMX(addReferenceCheckerModule("HistogramAverage",
+                                                  &module->averager()));
+    ASSERT_NO_THROW_GMX(presentAllData(input, &data));
+    ASSERT_NO_THROW_GMX(module->averager().done());
+}
+
+
 /********************************************************************
  * Tests for gmx::AnalysisDataBinAverageModule.
  */
@@ -313,7 +369,7 @@ typedef gmx::test::AnalysisDataTestFixture BinAverageModuleTest;
 
 TEST_F(BinAverageModuleTest, ComputesCorrectly)
 {
-    const AnalysisDataTestInput &input = WeightedInputData::get();
+    const AnalysisDataTestInput &input = WeightedSimpleInputData::get();
     gmx::AnalysisData            data;
     ASSERT_NO_THROW_GMX(setupDataObject(input, &data));
 
@@ -331,7 +387,7 @@ TEST_F(BinAverageModuleTest, ComputesCorrectly)
 
 TEST_F(BinAverageModuleTest, ComputesCorrectlyWithAll)
 {
-    const AnalysisDataTestInput &input = WeightedInputData::get();
+    const AnalysisDataTestInput &input = WeightedSimpleInputData::get();
     gmx::AnalysisData            data;
     ASSERT_NO_THROW_GMX(setupDataObject(input, &data));
 
@@ -347,6 +403,24 @@ TEST_F(BinAverageModuleTest, ComputesCorrectlyWithAll)
 }
 
 
+TEST_F(BinAverageModuleTest, HandlesMultipleDataSets)
+{
+    const AnalysisDataTestInput &input = WeightedDataSetInputData::get();
+    gmx::AnalysisData            data;
+    ASSERT_NO_THROW_GMX(setupDataObject(input, &data));
+
+    gmx::AnalysisDataBinAverageModulePointer module(
+            new gmx::AnalysisDataBinAverageModule(
+                    gmx::histogramFromRange(1.0, 3.0).binCount(4)));
+    data.addModule(module);
+
+    ASSERT_NO_THROW_GMX(addStaticCheckerModule(input, &data));
+    ASSERT_NO_THROW_GMX(addReferenceCheckerModule("InputData", &data));
+    ASSERT_NO_THROW_GMX(addReferenceCheckerModule("HistogramAverage", module.get()));
+    ASSERT_NO_THROW_GMX(presentAllData(input, &data));
+}
+
+
 /********************************************************************
  * Tests for gmx::AbstractAverageHistogram.
  *
@@ -367,15 +441,16 @@ class AverageInputData
             return singleton.data_;
         }
 
-        AverageInputData() : data_(2, false)
+        AverageInputData() : data_(1, false)
         {
-            data_.addFrameWithValues(1.0,  2.0, 1.0);
-            data_.addFrameWithValues(1.5,  1.0, 1.0);
-            data_.addFrameWithValues(2.0,  3.0, 2.0);
-            data_.addFrameWithValues(2.5,  4.0, 2.0);
-            data_.addFrameWithValues(3.0,  2.0, 1.0);
-            data_.addFrameWithValues(3.5,  0.0, 3.0);
-            data_.addFrameWithValues(4.0,  1.0, 3.0);
+            data_.setColumnCount(0, 1);
+            data_.addFrameWithValueAndError(1.0,  2.0, 1.0);
+            data_.addFrameWithValueAndError(1.5,  1.0, 1.0);
+            data_.addFrameWithValueAndError(2.0,  3.0, 2.0);
+            data_.addFrameWithValueAndError(2.5,  4.0, 2.0);
+            data_.addFrameWithValueAndError(3.0,  2.0, 1.0);
+            data_.addFrameWithValueAndError(3.5,  0.0, 3.0);
+            data_.addFrameWithValueAndError(4.0,  1.0, 3.0);
         }
 
     private:
@@ -402,7 +477,7 @@ class MockAverageHistogram : public gmx::AbstractAverageHistogram
         using AbstractAverageHistogram::setColumnCount;
         using AbstractAverageHistogram::setRowCount;
         using AbstractAverageHistogram::allocateValues;
-        using AbstractAverageHistogram::setValue;
+        using AbstractAverageHistogram::value;
 };
 
 
diff --git a/src/gromacs/analysisdata/tests/lifetime.cpp b/src/gromacs/analysisdata/tests/lifetime.cpp
new file mode 100644 (file)
index 0000000..fb7f8e1
--- /dev/null
@@ -0,0 +1,172 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2013, 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.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, 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 http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+/*! \internal \file
+ * \brief
+ * Tests for functionality of analysis data lifetime module.
+ *
+ * These tests check that gmx::AnalysisDataLifetimeModule computes lifetimes
+ * correctly with simple input data.
+ * Checking is done using gmx::test::AnalysisDataTestFixture and reference
+ * data.  Also the input data is written to the reference data to catch
+ * out-of-date reference.
+ *
+ * \author Teemu Murtola <teemu.murtola@gmail.com>
+ * \ingroup module_analysisdata
+ */
+#include <gtest/gtest.h>
+
+#include "gromacs/analysisdata/analysisdata.h"
+#include "gromacs/analysisdata/modules/lifetime.h"
+
+#include "testutils/datatest.h"
+#include "testutils/testasserts.h"
+
+using gmx::test::AnalysisDataTestInput;
+
+namespace
+{
+
+// Simple input data for gmx::AnalysisDataLifetimeModule tests.
+class SimpleInputData
+{
+    public:
+        static const AnalysisDataTestInput &get()
+        {
+            static SimpleInputData singleton;
+            return singleton.data_;
+        }
+
+        SimpleInputData() : data_(1, false)
+        {
+            data_.setColumnCount(0, 3);
+            data_.addFrameWithValues(1.0,  1.0, 1.0, 1.0);
+            data_.addFrameWithValues(2.0,  1.0, 0.0, 1.0);
+            data_.addFrameWithValues(3.0,  0.0, 1.0, 1.0);
+        }
+
+    private:
+        AnalysisDataTestInput  data_;
+};
+
+// Input data with multiple data sets for gmx::AnalysisDataLifetimeModule tests.
+class MultiDataSetInputData
+{
+    public:
+        static const AnalysisDataTestInput &get()
+        {
+            static MultiDataSetInputData singleton;
+            return singleton.data_;
+        }
+
+        MultiDataSetInputData() : data_(2, false)
+        {
+            using gmx::test::AnalysisDataTestInputFrame;
+            data_.setColumnCount(0, 2);
+            data_.setColumnCount(1, 2);
+            AnalysisDataTestInputFrame &frame1 = data_.addFrame(1.0);
+            frame1.addPointSetWithValues(0, 0, 1.0, 1.0);
+            frame1.addPointSetWithValues(1, 0, 0.0, 0.0);
+            AnalysisDataTestInputFrame &frame2 = data_.addFrame(2.0);
+            frame2.addPointSetWithValues(0, 0, 1.0, 0.0);
+            frame2.addPointSetWithValues(1, 0, 1.0, 0.0);
+            AnalysisDataTestInputFrame &frame3 = data_.addFrame(3.0);
+            frame3.addPointSetWithValues(0, 0, 1.0, 0.0);
+            frame3.addPointSetWithValues(1, 0, 1.0, 1.0);
+        }
+
+    private:
+        AnalysisDataTestInput  data_;
+};
+
+
+/********************************************************************
+ * Tests for gmx::AnalysisDataLifetimeModule.
+ */
+
+//! Test fixture for gmx::AnalysisDataLifetimeModule.
+typedef gmx::test::AnalysisDataTestFixture LifetimeModuleTest;
+
+TEST_F(LifetimeModuleTest, BasicTest)
+{
+    const AnalysisDataTestInput &input = SimpleInputData::get();
+    gmx::AnalysisData            data;
+    ASSERT_NO_THROW_GMX(setupDataObject(input, &data));
+
+    gmx::AnalysisDataLifetimeModulePointer module(
+            new gmx::AnalysisDataLifetimeModule);
+    module->setCumulative(false);
+    data.addModule(module);
+
+    ASSERT_NO_THROW_GMX(addStaticCheckerModule(input, &data));
+    ASSERT_NO_THROW_GMX(addReferenceCheckerModule("InputData", &data));
+    ASSERT_NO_THROW_GMX(addReferenceCheckerModule("Lifetime", module.get()));
+    ASSERT_NO_THROW_GMX(presentAllData(input, &data));
+}
+
+TEST_F(LifetimeModuleTest, CumulativeTest)
+{
+    const AnalysisDataTestInput &input = SimpleInputData::get();
+    gmx::AnalysisData            data;
+    ASSERT_NO_THROW_GMX(setupDataObject(input, &data));
+
+    gmx::AnalysisDataLifetimeModulePointer module(
+            new gmx::AnalysisDataLifetimeModule);
+    module->setCumulative(true);
+    data.addModule(module);
+
+    ASSERT_NO_THROW_GMX(addStaticCheckerModule(input, &data));
+    ASSERT_NO_THROW_GMX(addReferenceCheckerModule("InputData", &data));
+    ASSERT_NO_THROW_GMX(addReferenceCheckerModule("Lifetime", module.get()));
+    ASSERT_NO_THROW_GMX(presentAllData(input, &data));
+}
+
+TEST_F(LifetimeModuleTest, HandlesMultipleDataSets)
+{
+    const AnalysisDataTestInput &input = MultiDataSetInputData::get();
+    gmx::AnalysisData            data;
+    ASSERT_NO_THROW_GMX(setupDataObject(input, &data));
+
+    gmx::AnalysisDataLifetimeModulePointer module(
+            new gmx::AnalysisDataLifetimeModule);
+    module->setCumulative(false);
+    data.addModule(module);
+
+    ASSERT_NO_THROW_GMX(addStaticCheckerModule(input, &data));
+    ASSERT_NO_THROW_GMX(addReferenceCheckerModule("InputData", &data));
+    ASSERT_NO_THROW_GMX(addReferenceCheckerModule("Lifetime", module.get()));
+    ASSERT_NO_THROW_GMX(presentAllData(input, &data));
+}
+
+} // namespace
index 1d30d5fce83e6da968fdd38e067ac8d6c2e0f37e..ad573c417e06a357acb91b6a7d840e9d22aa091a 100644 (file)
@@ -5,84 +5,70 @@
     <DataFrame Name="Frame0">
       <Real Name="X">1.000000</Real>
       <DataValues>
-        <Int Name="Count">2</Int>
+        <Int Name="Count">1</Int>
         <DataValue>
           <Real Name="Value">2.000000</Real>
-        </DataValue>
-        <DataValue>
-          <Real Name="Value">1.000000</Real>
+          <Real Name="Error">1.000000</Real>
         </DataValue>
       </DataValues>
     </DataFrame>
     <DataFrame Name="Frame1">
       <Real Name="X">1.500000</Real>
       <DataValues>
-        <Int Name="Count">2</Int>
-        <DataValue>
-          <Real Name="Value">1.000000</Real>
-        </DataValue>
+        <Int Name="Count">1</Int>
         <DataValue>
           <Real Name="Value">1.000000</Real>
+          <Real Name="Error">1.000000</Real>
         </DataValue>
       </DataValues>
     </DataFrame>
     <DataFrame Name="Frame2">
       <Real Name="X">2.000000</Real>
       <DataValues>
-        <Int Name="Count">2</Int>
+        <Int Name="Count">1</Int>
         <DataValue>
           <Real Name="Value">3.000000</Real>
-        </DataValue>
-        <DataValue>
-          <Real Name="Value">2.000000</Real>
+          <Real Name="Error">2.000000</Real>
         </DataValue>
       </DataValues>
     </DataFrame>
     <DataFrame Name="Frame3">
       <Real Name="X">2.500000</Real>
       <DataValues>
-        <Int Name="Count">2</Int>
+        <Int Name="Count">1</Int>
         <DataValue>
           <Real Name="Value">4.000000</Real>
-        </DataValue>
-        <DataValue>
-          <Real Name="Value">2.000000</Real>
+          <Real Name="Error">2.000000</Real>
         </DataValue>
       </DataValues>
     </DataFrame>
     <DataFrame Name="Frame4">
       <Real Name="X">3.000000</Real>
       <DataValues>
-        <Int Name="Count">2</Int>
+        <Int Name="Count">1</Int>
         <DataValue>
           <Real Name="Value">2.000000</Real>
-        </DataValue>
-        <DataValue>
-          <Real Name="Value">1.000000</Real>
+          <Real Name="Error">1.000000</Real>
         </DataValue>
       </DataValues>
     </DataFrame>
     <DataFrame Name="Frame5">
       <Real Name="X">3.500000</Real>
       <DataValues>
-        <Int Name="Count">2</Int>
+        <Int Name="Count">1</Int>
         <DataValue>
           <Real Name="Value">0.000000</Real>
-        </DataValue>
-        <DataValue>
-          <Real Name="Value">3.000000</Real>
+          <Real Name="Error">3.000000</Real>
         </DataValue>
       </DataValues>
     </DataFrame>
     <DataFrame Name="Frame6">
       <Real Name="X">4.000000</Real>
       <DataValues>
-        <Int Name="Count">2</Int>
+        <Int Name="Count">1</Int>
         <DataValue>
           <Real Name="Value">1.000000</Real>
-        </DataValue>
-        <DataValue>
-          <Real Name="Value">3.000000</Real>
+          <Real Name="Error">3.000000</Real>
         </DataValue>
       </DataValues>
     </DataFrame>
     <DataFrame Name="Frame0">
       <Real Name="X">1.500000</Real>
       <DataValues>
-        <Int Name="Count">2</Int>
+        <Int Name="Count">1</Int>
         <DataValue>
           <Real Name="Value">3.000000</Real>
-        </DataValue>
-        <DataValue>
-          <Real Name="Value">1.414214</Real>
+          <Real Name="Error">1.414214</Real>
         </DataValue>
       </DataValues>
     </DataFrame>
     <DataFrame Name="Frame1">
       <Real Name="X">2.500000</Real>
       <DataValues>
-        <Int Name="Count">2</Int>
+        <Int Name="Count">1</Int>
         <DataValue>
           <Real Name="Value">7.000000</Real>
-        </DataValue>
-        <DataValue>
-          <Real Name="Value">2.828427</Real>
+          <Real Name="Error">2.828427</Real>
         </DataValue>
       </DataValues>
     </DataFrame>
     <DataFrame Name="Frame2">
       <Real Name="X">3.500000</Real>
       <DataValues>
-        <Int Name="Count">2</Int>
+        <Int Name="Count">1</Int>
         <DataValue>
           <Real Name="Value">2.000000</Real>
-        </DataValue>
-        <DataValue>
-          <Real Name="Value">3.162278</Real>
+          <Real Name="Error">3.162278</Real>
         </DataValue>
       </DataValues>
     </DataFrame>
index 999553a915cacf8545acfe829403016aa42c4fb7..c0c325330dd867c005bb48235a9f01deefb4dd3f 100644 (file)
@@ -5,84 +5,70 @@
     <DataFrame Name="Frame0">
       <Real Name="X">1.000000</Real>
       <DataValues>
-        <Int Name="Count">2</Int>
+        <Int Name="Count">1</Int>
         <DataValue>
           <Real Name="Value">2.000000</Real>
-        </DataValue>
-        <DataValue>
-          <Real Name="Value">1.000000</Real>
+          <Real Name="Error">1.000000</Real>
         </DataValue>
       </DataValues>
     </DataFrame>
     <DataFrame Name="Frame1">
       <Real Name="X">1.500000</Real>
       <DataValues>
-        <Int Name="Count">2</Int>
-        <DataValue>
-          <Real Name="Value">1.000000</Real>
-        </DataValue>
+        <Int Name="Count">1</Int>
         <DataValue>
           <Real Name="Value">1.000000</Real>
+          <Real Name="Error">1.000000</Real>
         </DataValue>
       </DataValues>
     </DataFrame>
     <DataFrame Name="Frame2">
       <Real Name="X">2.000000</Real>
       <DataValues>
-        <Int Name="Count">2</Int>
+        <Int Name="Count">1</Int>
         <DataValue>
           <Real Name="Value">3.000000</Real>
-        </DataValue>
-        <DataValue>
-          <Real Name="Value">2.000000</Real>
+          <Real Name="Error">2.000000</Real>
         </DataValue>
       </DataValues>
     </DataFrame>
     <DataFrame Name="Frame3">
       <Real Name="X">2.500000</Real>
       <DataValues>
-        <Int Name="Count">2</Int>
+        <Int Name="Count">1</Int>
         <DataValue>
           <Real Name="Value">4.000000</Real>
-        </DataValue>
-        <DataValue>
-          <Real Name="Value">2.000000</Real>
+          <Real Name="Error">2.000000</Real>
         </DataValue>
       </DataValues>
     </DataFrame>
     <DataFrame Name="Frame4">
       <Real Name="X">3.000000</Real>
       <DataValues>
-        <Int Name="Count">2</Int>
+        <Int Name="Count">1</Int>
         <DataValue>
           <Real Name="Value">2.000000</Real>
-        </DataValue>
-        <DataValue>
-          <Real Name="Value">1.000000</Real>
+          <Real Name="Error">1.000000</Real>
         </DataValue>
       </DataValues>
     </DataFrame>
     <DataFrame Name="Frame5">
       <Real Name="X">3.500000</Real>
       <DataValues>
-        <Int Name="Count">2</Int>
+        <Int Name="Count">1</Int>
         <DataValue>
           <Real Name="Value">0.000000</Real>
-        </DataValue>
-        <DataValue>
-          <Real Name="Value">3.000000</Real>
+          <Real Name="Error">3.000000</Real>
         </DataValue>
       </DataValues>
     </DataFrame>
     <DataFrame Name="Frame6">
       <Real Name="X">4.000000</Real>
       <DataValues>
-        <Int Name="Count">2</Int>
+        <Int Name="Count">1</Int>
         <DataValue>
           <Real Name="Value">1.000000</Real>
-        </DataValue>
-        <DataValue>
-          <Real Name="Value">3.000000</Real>
+          <Real Name="Error">3.000000</Real>
         </DataValue>
       </DataValues>
     </DataFrame>
     <DataFrame Name="Frame0">
       <Real Name="X">1.000000</Real>
       <DataValues>
-        <Int Name="Count">2</Int>
+        <Int Name="Count">1</Int>
         <DataValue>
           <Real Name="Value">2.000000</Real>
-        </DataValue>
-        <DataValue>
-          <Real Name="Value">1.000000</Real>
+          <Real Name="Error">1.000000</Real>
         </DataValue>
       </DataValues>
     </DataFrame>
     <DataFrame Name="Frame1">
       <Real Name="X">2.000000</Real>
       <DataValues>
-        <Int Name="Count">2</Int>
+        <Int Name="Count">1</Int>
         <DataValue>
           <Real Name="Value">4.000000</Real>
-        </DataValue>
-        <DataValue>
-          <Real Name="Value">2.236068</Real>
+          <Real Name="Error">2.236068</Real>
         </DataValue>
       </DataValues>
     </DataFrame>
     <DataFrame Name="Frame2">
       <Real Name="X">3.000000</Real>
       <DataValues>
-        <Int Name="Count">2</Int>
+        <Int Name="Count">1</Int>
         <DataValue>
           <Real Name="Value">6.000000</Real>
-        </DataValue>
-        <DataValue>
-          <Real Name="Value">2.236068</Real>
+          <Real Name="Error">2.236068</Real>
         </DataValue>
       </DataValues>
     </DataFrame>
     <DataFrame Name="Frame3">
       <Real Name="X">4.000000</Real>
       <DataValues>
-        <Int Name="Count">2</Int>
+        <Int Name="Count">1</Int>
         <DataValue>
           <Real Name="Value">1.000000</Real>
-        </DataValue>
-        <DataValue>
-          <Real Name="Value">4.242640</Real>
+          <Real Name="Error">4.242640</Real>
         </DataValue>
       </DataValues>
     </DataFrame>
index 2b50ff2d6477a5b221208c1e7dec1fdc5f494a4f..4943ebb1d1ac06e949cf99c086442e5cfdefa7fb 100644 (file)
@@ -8,15 +8,12 @@
         <Int Name="Count">3</Int>
         <DataValue>
           <Real Name="Value">0.000000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
         <DataValue>
           <Real Name="Value">1.000000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
         <DataValue>
           <Real Name="Value">2.000000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
       </DataValues>
     </DataFrame>
         <Int Name="Count">3</Int>
         <DataValue>
           <Real Name="Value">1.000000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
         <DataValue>
           <Real Name="Value">1.000000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
         <DataValue>
           <Real Name="Value">1.000000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
       </DataValues>
     </DataFrame>
         <Int Name="Count">3</Int>
         <DataValue>
           <Real Name="Value">2.000000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
         <DataValue>
           <Real Name="Value">0.000000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
         <DataValue>
           <Real Name="Value">0.000000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
       </DataValues>
     </DataFrame>
     <DataFrame Name="Frame0">
       <Real Name="X">0.000000</Real>
       <DataValues>
-        <Int Name="Count">2</Int>
-        <DataValue>
-          <Real Name="Value">1.000000</Real>
-        </DataValue>
+        <Int Name="Count">1</Int>
         <DataValue>
           <Real Name="Value">1.000000</Real>
+          <Real Name="Error">1.000000</Real>
         </DataValue>
       </DataValues>
     </DataFrame>
     <DataFrame Name="Frame1">
       <Real Name="X">1.000000</Real>
       <DataValues>
-        <Int Name="Count">2</Int>
+        <Int Name="Count">1</Int>
         <DataValue>
           <Real Name="Value">0.666667</Real>
-        </DataValue>
-        <DataValue>
-          <Real Name="Value">0.577350</Real>
+          <Real Name="Error">0.577350</Real>
         </DataValue>
       </DataValues>
     </DataFrame>
     <DataFrame Name="Frame2">
       <Real Name="X">2.000000</Real>
       <DataValues>
-        <Int Name="Count">2</Int>
-        <DataValue>
-          <Real Name="Value">1.000000</Real>
-        </DataValue>
+        <Int Name="Count">1</Int>
         <DataValue>
           <Real Name="Value">1.000000</Real>
+          <Real Name="Error">1.000000</Real>
         </DataValue>
       </DataValues>
     </DataFrame>
index b04f97188d6721eac300c2790a0ef40338c3c4f1..5e642ffaa9964b5234720c81c182d7b00f245a7a 100644 (file)
@@ -8,15 +8,12 @@
         <Int Name="Count">3</Int>
         <DataValue>
           <Real Name="Value">0.000000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
         <DataValue>
           <Real Name="Value">1.000000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
         <DataValue>
           <Real Name="Value">2.000000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
       </DataValues>
     </DataFrame>
         <Int Name="Count">3</Int>
         <DataValue>
           <Real Name="Value">1.000000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
         <DataValue>
           <Real Name="Value">1.000000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
         <DataValue>
           <Real Name="Value">1.000000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
       </DataValues>
     </DataFrame>
         <Int Name="Count">3</Int>
         <DataValue>
           <Real Name="Value">2.000000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
         <DataValue>
           <Real Name="Value">0.000000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
         <DataValue>
           <Real Name="Value">0.000000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
       </DataValues>
     </DataFrame>
     <DataFrame Name="Frame0">
       <Real Name="X">0.500000</Real>
       <DataValues>
-        <Int Name="Count">2</Int>
-        <DataValue>
-          <Real Name="Value">1.000000</Real>
-        </DataValue>
+        <Int Name="Count">1</Int>
         <DataValue>
           <Real Name="Value">1.000000</Real>
+          <Real Name="Error">1.000000</Real>
         </DataValue>
       </DataValues>
     </DataFrame>
     <DataFrame Name="Frame1">
       <Real Name="X">1.000000</Real>
       <DataValues>
-        <Int Name="Count">2</Int>
+        <Int Name="Count">1</Int>
         <DataValue>
           <Real Name="Value">0.666667</Real>
-        </DataValue>
-        <DataValue>
-          <Real Name="Value">0.577350</Real>
+          <Real Name="Error">0.577350</Real>
         </DataValue>
       </DataValues>
     </DataFrame>
     <DataFrame Name="Frame2">
       <Real Name="X">1.500000</Real>
       <DataValues>
-        <Int Name="Count">2</Int>
-        <DataValue>
-          <Real Name="Value">1.000000</Real>
-        </DataValue>
+        <Int Name="Count">1</Int>
         <DataValue>
           <Real Name="Value">1.000000</Real>
+          <Real Name="Error">1.000000</Real>
         </DataValue>
       </DataValues>
     </DataFrame>
diff --git a/src/gromacs/analysisdata/tests/refdata/AverageModuleTest_HandlesDataSetAveraging.xml b/src/gromacs/analysisdata/tests/refdata/AverageModuleTest_HandlesDataSetAveraging.xml
new file mode 100644 (file)
index 0000000..9a1b60d
--- /dev/null
@@ -0,0 +1,135 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <AnalysisData Name="InputData">
+    <DataFrame Name="Frame0">
+      <Real Name="X">1.000000</Real>
+      <DataValues>
+        <Int Name="Count">3</Int>
+        <Int Name="DataSet">0</Int>
+        <DataValue>
+          <Real Name="Value">0.000000</Real>
+        </DataValue>
+        <DataValue>
+          <Real Name="Value">1.000000</Real>
+        </DataValue>
+        <DataValue>
+          <Real Name="Value">2.000000</Real>
+        </DataValue>
+      </DataValues>
+      <DataValues>
+        <Int Name="Count">2</Int>
+        <Int Name="DataSet">0</Int>
+        <Int Name="FirstColumn">0</Int>
+        <Int Name="LastColumn">1</Int>
+        <DataValue>
+          <Real Name="Value">1.000000</Real>
+        </DataValue>
+        <DataValue>
+          <Real Name="Value">0.000000</Real>
+        </DataValue>
+      </DataValues>
+      <DataValues>
+        <Int Name="Count">2</Int>
+        <Int Name="DataSet">1</Int>
+        <DataValue>
+          <Real Name="Value">2.000000</Real>
+        </DataValue>
+        <DataValue>
+          <Real Name="Value">1.000000</Real>
+        </DataValue>
+      </DataValues>
+      <DataValues>
+        <Int Name="Count">1</Int>
+        <Int Name="DataSet">1</Int>
+        <Int Name="FirstColumn">1</Int>
+        <Int Name="LastColumn">1</Int>
+        <DataValue>
+          <Real Name="Value">2.000000</Real>
+        </DataValue>
+      </DataValues>
+    </DataFrame>
+    <DataFrame Name="Frame1">
+      <Real Name="X">2.000000</Real>
+      <DataValues>
+        <Int Name="Count">2</Int>
+        <Int Name="DataSet">0</Int>
+        <Int Name="FirstColumn">0</Int>
+        <Int Name="LastColumn">1</Int>
+        <DataValue>
+          <Real Name="Value">1.000000</Real>
+        </DataValue>
+        <DataValue>
+          <Real Name="Value">1.000000</Real>
+        </DataValue>
+      </DataValues>
+      <DataValues>
+        <Int Name="Count">1</Int>
+        <Int Name="DataSet">0</Int>
+        <Int Name="FirstColumn">2</Int>
+        <Int Name="LastColumn">2</Int>
+        <DataValue>
+          <Real Name="Value">2.000000</Real>
+        </DataValue>
+      </DataValues>
+      <DataValues>
+        <Int Name="Count">2</Int>
+        <Int Name="DataSet">1</Int>
+        <DataValue>
+          <Real Name="Value">1.000000</Real>
+        </DataValue>
+        <DataValue>
+          <Real Name="Value">0.000000</Real>
+        </DataValue>
+      </DataValues>
+    </DataFrame>
+    <DataFrame Name="Frame2">
+      <Real Name="X">3.000000</Real>
+      <DataValues>
+        <Int Name="Count">3</Int>
+        <Int Name="DataSet">0</Int>
+        <DataValue>
+          <Real Name="Value">2.000000</Real>
+        </DataValue>
+        <DataValue>
+          <Real Name="Value">0.000000</Real>
+        </DataValue>
+        <DataValue>
+          <Real Name="Value">0.000000</Real>
+        </DataValue>
+      </DataValues>
+      <DataValues>
+        <Int Name="Count">2</Int>
+        <Int Name="DataSet">1</Int>
+        <DataValue>
+          <Real Name="Value">0.000000</Real>
+        </DataValue>
+        <DataValue>
+          <Real Name="Value">2.000000</Real>
+        </DataValue>
+      </DataValues>
+    </DataFrame>
+  </AnalysisData>
+  <AnalysisData Name="Average">
+    <DataFrame Name="Frame0">
+      <Real Name="X">0.000000</Real>
+      <DataValues>
+        <Int Name="Count">1</Int>
+        <DataValue>
+          <Real Name="Value">0.909091</Real>
+          <Real Name="Error">0.831209</Real>
+        </DataValue>
+      </DataValues>
+    </DataFrame>
+    <DataFrame Name="Frame1">
+      <Real Name="X">1.000000</Real>
+      <DataValues>
+        <Int Name="Count">1</Int>
+        <DataValue>
+          <Real Name="Value">1.142857</Real>
+          <Real Name="Error">0.899735</Real>
+        </DataValue>
+      </DataValues>
+    </DataFrame>
+  </AnalysisData>
+</ReferenceData>
diff --git a/src/gromacs/analysisdata/tests/refdata/AverageModuleTest_HandlesMultipleDataSets.xml b/src/gromacs/analysisdata/tests/refdata/AverageModuleTest_HandlesMultipleDataSets.xml
new file mode 100644 (file)
index 0000000..95a24e3
--- /dev/null
@@ -0,0 +1,158 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <AnalysisData Name="InputData">
+    <DataFrame Name="Frame0">
+      <Real Name="X">1.000000</Real>
+      <DataValues>
+        <Int Name="Count">3</Int>
+        <Int Name="DataSet">0</Int>
+        <DataValue>
+          <Real Name="Value">0.000000</Real>
+        </DataValue>
+        <DataValue>
+          <Real Name="Value">1.000000</Real>
+        </DataValue>
+        <DataValue>
+          <Real Name="Value">2.000000</Real>
+        </DataValue>
+      </DataValues>
+      <DataValues>
+        <Int Name="Count">2</Int>
+        <Int Name="DataSet">0</Int>
+        <Int Name="FirstColumn">0</Int>
+        <Int Name="LastColumn">1</Int>
+        <DataValue>
+          <Real Name="Value">1.000000</Real>
+        </DataValue>
+        <DataValue>
+          <Real Name="Value">0.000000</Real>
+        </DataValue>
+      </DataValues>
+      <DataValues>
+        <Int Name="Count">2</Int>
+        <Int Name="DataSet">1</Int>
+        <DataValue>
+          <Real Name="Value">2.000000</Real>
+        </DataValue>
+        <DataValue>
+          <Real Name="Value">1.000000</Real>
+        </DataValue>
+      </DataValues>
+      <DataValues>
+        <Int Name="Count">1</Int>
+        <Int Name="DataSet">1</Int>
+        <Int Name="FirstColumn">1</Int>
+        <Int Name="LastColumn">1</Int>
+        <DataValue>
+          <Real Name="Value">2.000000</Real>
+        </DataValue>
+      </DataValues>
+    </DataFrame>
+    <DataFrame Name="Frame1">
+      <Real Name="X">2.000000</Real>
+      <DataValues>
+        <Int Name="Count">2</Int>
+        <Int Name="DataSet">0</Int>
+        <Int Name="FirstColumn">0</Int>
+        <Int Name="LastColumn">1</Int>
+        <DataValue>
+          <Real Name="Value">1.000000</Real>
+        </DataValue>
+        <DataValue>
+          <Real Name="Value">1.000000</Real>
+        </DataValue>
+      </DataValues>
+      <DataValues>
+        <Int Name="Count">1</Int>
+        <Int Name="DataSet">0</Int>
+        <Int Name="FirstColumn">2</Int>
+        <Int Name="LastColumn">2</Int>
+        <DataValue>
+          <Real Name="Value">2.000000</Real>
+        </DataValue>
+      </DataValues>
+      <DataValues>
+        <Int Name="Count">2</Int>
+        <Int Name="DataSet">1</Int>
+        <DataValue>
+          <Real Name="Value">1.000000</Real>
+        </DataValue>
+        <DataValue>
+          <Real Name="Value">0.000000</Real>
+        </DataValue>
+      </DataValues>
+    </DataFrame>
+    <DataFrame Name="Frame2">
+      <Real Name="X">3.000000</Real>
+      <DataValues>
+        <Int Name="Count">3</Int>
+        <Int Name="DataSet">0</Int>
+        <DataValue>
+          <Real Name="Value">2.000000</Real>
+        </DataValue>
+        <DataValue>
+          <Real Name="Value">0.000000</Real>
+        </DataValue>
+        <DataValue>
+          <Real Name="Value">0.000000</Real>
+        </DataValue>
+      </DataValues>
+      <DataValues>
+        <Int Name="Count">2</Int>
+        <Int Name="DataSet">1</Int>
+        <DataValue>
+          <Real Name="Value">0.000000</Real>
+        </DataValue>
+        <DataValue>
+          <Real Name="Value">2.000000</Real>
+        </DataValue>
+      </DataValues>
+    </DataFrame>
+  </AnalysisData>
+  <AnalysisData Name="Average">
+    <DataFrame Name="Frame0">
+      <Real Name="X">0.000000</Real>
+      <DataValues>
+        <Int Name="Count">2</Int>
+        <DataValue>
+          <Real Name="Value">1.000000</Real>
+          <Real Name="Error">0.816497</Real>
+        </DataValue>
+        <DataValue>
+          <Real Name="Value">1.000000</Real>
+          <Real Name="Error">1.000000</Real>
+        </DataValue>
+      </DataValues>
+    </DataFrame>
+    <DataFrame Name="Frame1">
+      <Real Name="X">1.000000</Real>
+      <DataValues>
+        <Int Name="Count">2</Int>
+        <DataValue>
+          <Real Name="Value">0.500000</Real>
+          <Real Name="Error">0.577350</Real>
+        </DataValue>
+        <DataValue>
+          <Real Name="Value">1.250000</Real>
+          <Real Name="Error">0.957427</Real>
+        </DataValue>
+      </DataValues>
+    </DataFrame>
+    <DataFrame Name="Frame2">
+      <Real Name="X">2.000000</Real>
+      <DataValues>
+        <Int Name="Count">2</Int>
+        <DataValue>
+          <Real Name="Value">1.333333</Real>
+          <Real Name="Error">1.154701</Real>
+        </DataValue>
+        <DataValue>
+          <Real Name="Value">0.000000</Real>
+          <Real Name="Error">0.000000</Real>
+          <Bool Name="Present">false</Bool>
+        </DataValue>
+      </DataValues>
+    </DataFrame>
+  </AnalysisData>
+</ReferenceData>
index f245bd98eb22a61471561e856ad725681f339aeb..88fdb356697c279bde518228c97c223a7fa32c33 100644 (file)
@@ -8,15 +8,12 @@
         <Int Name="Count">3</Int>
         <DataValue>
           <Real Name="Value">0.000000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
         <DataValue>
           <Real Name="Value">1.000000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
         <DataValue>
           <Real Name="Value">2.000000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
       </DataValues>
       <DataValues>
         <Int Name="LastColumn">1</Int>
         <DataValue>
           <Real Name="Value">1.000000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
         <DataValue>
           <Real Name="Value">0.000000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
       </DataValues>
       <DataValues>
@@ -38,7 +33,6 @@
         <Int Name="LastColumn">0</Int>
         <DataValue>
           <Real Name="Value">2.000000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
       </DataValues>
     </DataFrame>
         <Int Name="LastColumn">1</Int>
         <DataValue>
           <Real Name="Value">1.000000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
         <DataValue>
           <Real Name="Value">1.000000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
       </DataValues>
       <DataValues>
@@ -63,7 +55,6 @@
         <Int Name="LastColumn">0</Int>
         <DataValue>
           <Real Name="Value">2.000000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
       </DataValues>
     </DataFrame>
         <Int Name="Count">3</Int>
         <DataValue>
           <Real Name="Value">2.000000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
         <DataValue>
           <Real Name="Value">0.000000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
         <DataValue>
           <Real Name="Value">0.000000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
       </DataValues>
     </DataFrame>
     <DataFrame Name="Frame0">
       <Real Name="X">0.000000</Real>
       <DataValues>
-        <Int Name="Count">2</Int>
+        <Int Name="Count">1</Int>
         <DataValue>
           <Real Name="Value">1.333333</Real>
-        </DataValue>
-        <DataValue>
-          <Real Name="Value">0.816497</Real>
+          <Real Name="Error">0.816497</Real>
         </DataValue>
       </DataValues>
     </DataFrame>
     <DataFrame Name="Frame1">
       <Real Name="X">1.000000</Real>
       <DataValues>
-        <Int Name="Count">2</Int>
+        <Int Name="Count">1</Int>
         <DataValue>
           <Real Name="Value">0.500000</Real>
-        </DataValue>
-        <DataValue>
-          <Real Name="Value">0.577350</Real>
+          <Real Name="Error">0.577350</Real>
         </DataValue>
       </DataValues>
     </DataFrame>
     <DataFrame Name="Frame2">
       <Real Name="X">2.000000</Real>
       <DataValues>
-        <Int Name="Count">2</Int>
+        <Int Name="Count">1</Int>
         <DataValue>
           <Real Name="Value">1.000000</Real>
-        </DataValue>
-        <DataValue>
-          <Real Name="Value">1.414214</Real>
+          <Real Name="Error">1.414214</Real>
         </DataValue>
       </DataValues>
     </DataFrame>
index 0847792a44ffb751dbbbd908c9d30c3b54fca7be..adb6dff3d8b6aca99bf3e679b83cdd6cf57cca72 100644 (file)
@@ -8,44 +8,36 @@
         <Int Name="Count">2</Int>
         <DataValue>
           <Real Name="Value">0.700000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
         <DataValue>
           <Real Name="Value">0.500000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
       </DataValues>
       <DataValues>
         <Int Name="Count">2</Int>
         <DataValue>
           <Real Name="Value">1.100000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
         <DataValue>
           <Real Name="Value">1.000000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
       </DataValues>
       <DataValues>
         <Int Name="Count">2</Int>
         <DataValue>
           <Real Name="Value">2.300000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
         <DataValue>
           <Real Name="Value">1.000000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
       </DataValues>
       <DataValues>
         <Int Name="Count">2</Int>
         <DataValue>
           <Real Name="Value">2.900000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
         <DataValue>
           <Real Name="Value">2.000000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
       </DataValues>
     </DataFrame>
         <Int Name="Count">2</Int>
         <DataValue>
           <Real Name="Value">1.300000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
         <DataValue>
           <Real Name="Value">1.000000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
       </DataValues>
       <DataValues>
         <Int Name="Count">2</Int>
         <DataValue>
           <Real Name="Value">2.200000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
         <DataValue>
           <Real Name="Value">3.000000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
       </DataValues>
     </DataFrame>
         <Int Name="Count">2</Int>
         <DataValue>
           <Real Name="Value">3.300000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
         <DataValue>
           <Real Name="Value">0.500000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
       </DataValues>
       <DataValues>
         <Int Name="Count">2</Int>
         <DataValue>
           <Real Name="Value">1.200000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
         <DataValue>
           <Real Name="Value">2.000000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
       </DataValues>
       <DataValues>
         <Int Name="Count">2</Int>
         <DataValue>
           <Real Name="Value">1.300000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
         <DataValue>
           <Real Name="Value">1.000000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
       </DataValues>
     </DataFrame>
     <DataFrame Name="Frame0">
       <Real Name="X">1.250000</Real>
       <DataValues>
-        <Int Name="Count">3</Int>
+        <Int Name="Count">1</Int>
         <DataValue>
           <Real Name="Value">1.250000</Real>
-        </DataValue>
-        <DataValue>
-          <Real Name="Value">0.500000</Real>
-        </DataValue>
-        <DataValue>
-          <Real Name="Value">4.000000</Real>
+          <Real Name="Error">0.500000</Real>
         </DataValue>
       </DataValues>
     </DataFrame>
     <DataFrame Name="Frame1">
       <Real Name="X">1.750000</Real>
       <DataValues>
-        <Int Name="Count">3</Int>
-        <DataValue>
-          <Real Name="Value">0.000000</Real>
-        </DataValue>
-        <DataValue>
-          <Real Name="Value">0.000000</Real>
-        </DataValue>
+        <Int Name="Count">1</Int>
         <DataValue>
           <Real Name="Value">0.000000</Real>
+          <Real Name="Error">0.000000</Real>
         </DataValue>
       </DataValues>
     </DataFrame>
     <DataFrame Name="Frame2">
       <Real Name="X">2.250000</Real>
       <DataValues>
-        <Int Name="Count">3</Int>
-        <DataValue>
-          <Real Name="Value">2.000000</Real>
-        </DataValue>
-        <DataValue>
-          <Real Name="Value">1.414214</Real>
-        </DataValue>
+        <Int Name="Count">1</Int>
         <DataValue>
           <Real Name="Value">2.000000</Real>
+          <Real Name="Error">1.414214</Real>
         </DataValue>
       </DataValues>
     </DataFrame>
     <DataFrame Name="Frame3">
       <Real Name="X">2.750000</Real>
       <DataValues>
-        <Int Name="Count">3</Int>
+        <Int Name="Count">1</Int>
         <DataValue>
           <Real Name="Value">2.000000</Real>
-        </DataValue>
-        <DataValue>
-          <Real Name="Value">0.000000</Real>
-        </DataValue>
-        <DataValue>
-          <Real Name="Value">1.000000</Real>
+          <Real Name="Error">0.000000</Real>
         </DataValue>
       </DataValues>
     </DataFrame>
index dd97dc7bcb23c411e5dcd8f40fcfe4e002db8f37..6a9eede4243ed59e966843d8eeb626e532412688 100644 (file)
@@ -8,44 +8,36 @@
         <Int Name="Count">2</Int>
         <DataValue>
           <Real Name="Value">0.700000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
         <DataValue>
           <Real Name="Value">0.500000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
       </DataValues>
       <DataValues>
         <Int Name="Count">2</Int>
         <DataValue>
           <Real Name="Value">1.100000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
         <DataValue>
           <Real Name="Value">1.000000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
       </DataValues>
       <DataValues>
         <Int Name="Count">2</Int>
         <DataValue>
           <Real Name="Value">2.300000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
         <DataValue>
           <Real Name="Value">1.000000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
       </DataValues>
       <DataValues>
         <Int Name="Count">2</Int>
         <DataValue>
           <Real Name="Value">2.900000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
         <DataValue>
           <Real Name="Value">2.000000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
       </DataValues>
     </DataFrame>
         <Int Name="Count">2</Int>
         <DataValue>
           <Real Name="Value">1.300000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
         <DataValue>
           <Real Name="Value">1.000000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
       </DataValues>
       <DataValues>
         <Int Name="Count">2</Int>
         <DataValue>
           <Real Name="Value">2.200000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
         <DataValue>
           <Real Name="Value">3.000000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
       </DataValues>
     </DataFrame>
         <Int Name="Count">2</Int>
         <DataValue>
           <Real Name="Value">3.300000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
         <DataValue>
           <Real Name="Value">0.500000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
       </DataValues>
       <DataValues>
         <Int Name="Count">2</Int>
         <DataValue>
           <Real Name="Value">1.200000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
         <DataValue>
           <Real Name="Value">2.000000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
       </DataValues>
       <DataValues>
         <Int Name="Count">2</Int>
         <DataValue>
           <Real Name="Value">1.300000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
         <DataValue>
           <Real Name="Value">1.000000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
       </DataValues>
     </DataFrame>
     <DataFrame Name="Frame0">
       <Real Name="X">1.250000</Real>
       <DataValues>
-        <Int Name="Count">3</Int>
+        <Int Name="Count">1</Int>
         <DataValue>
           <Real Name="Value">1.100000</Real>
-        </DataValue>
-        <DataValue>
-          <Real Name="Value">0.547723</Real>
-        </DataValue>
-        <DataValue>
-          <Real Name="Value">5.000000</Real>
+          <Real Name="Error">0.547723</Real>
         </DataValue>
       </DataValues>
     </DataFrame>
     <DataFrame Name="Frame1">
       <Real Name="X">1.750000</Real>
       <DataValues>
-        <Int Name="Count">3</Int>
-        <DataValue>
-          <Real Name="Value">0.000000</Real>
-        </DataValue>
-        <DataValue>
-          <Real Name="Value">0.000000</Real>
-        </DataValue>
+        <Int Name="Count">1</Int>
         <DataValue>
           <Real Name="Value">0.000000</Real>
+          <Real Name="Error">0.000000</Real>
         </DataValue>
       </DataValues>
     </DataFrame>
     <DataFrame Name="Frame2">
       <Real Name="X">2.250000</Real>
       <DataValues>
-        <Int Name="Count">3</Int>
-        <DataValue>
-          <Real Name="Value">2.000000</Real>
-        </DataValue>
-        <DataValue>
-          <Real Name="Value">1.414214</Real>
-        </DataValue>
+        <Int Name="Count">1</Int>
         <DataValue>
           <Real Name="Value">2.000000</Real>
+          <Real Name="Error">1.414214</Real>
         </DataValue>
       </DataValues>
     </DataFrame>
     <DataFrame Name="Frame3">
       <Real Name="X">2.750000</Real>
       <DataValues>
-        <Int Name="Count">3</Int>
+        <Int Name="Count">1</Int>
         <DataValue>
           <Real Name="Value">1.250000</Real>
-        </DataValue>
-        <DataValue>
-          <Real Name="Value">1.060660</Real>
-        </DataValue>
-        <DataValue>
-          <Real Name="Value">2.000000</Real>
+          <Real Name="Error">1.060660</Real>
         </DataValue>
       </DataValues>
     </DataFrame>
diff --git a/src/gromacs/analysisdata/tests/refdata/BinAverageModuleTest_HandlesMultipleDataSets.xml b/src/gromacs/analysisdata/tests/refdata/BinAverageModuleTest_HandlesMultipleDataSets.xml
new file mode 100644 (file)
index 0000000..3171fea
--- /dev/null
@@ -0,0 +1,163 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <AnalysisData Name="InputData">
+    <DataFrame Name="Frame0">
+      <Real Name="X">1.000000</Real>
+      <DataValues>
+        <Int Name="Count">2</Int>
+        <Int Name="DataSet">0</Int>
+        <DataValue>
+          <Real Name="Value">0.700000</Real>
+        </DataValue>
+        <DataValue>
+          <Real Name="Value">0.500000</Real>
+        </DataValue>
+      </DataValues>
+      <DataValues>
+        <Int Name="Count">2</Int>
+        <Int Name="DataSet">0</Int>
+        <DataValue>
+          <Real Name="Value">1.100000</Real>
+        </DataValue>
+        <DataValue>
+          <Real Name="Value">1.000000</Real>
+        </DataValue>
+      </DataValues>
+      <DataValues>
+        <Int Name="Count">2</Int>
+        <Int Name="DataSet">1</Int>
+        <DataValue>
+          <Real Name="Value">2.300000</Real>
+        </DataValue>
+        <DataValue>
+          <Real Name="Value">1.000000</Real>
+        </DataValue>
+      </DataValues>
+      <DataValues>
+        <Int Name="Count">2</Int>
+        <Int Name="DataSet">1</Int>
+        <DataValue>
+          <Real Name="Value">2.900000</Real>
+        </DataValue>
+        <DataValue>
+          <Real Name="Value">2.000000</Real>
+        </DataValue>
+      </DataValues>
+    </DataFrame>
+    <DataFrame Name="Frame1">
+      <Real Name="X">2.000000</Real>
+      <DataValues>
+        <Int Name="Count">2</Int>
+        <Int Name="DataSet">0</Int>
+        <DataValue>
+          <Real Name="Value">1.300000</Real>
+        </DataValue>
+        <DataValue>
+          <Real Name="Value">1.000000</Real>
+        </DataValue>
+      </DataValues>
+      <DataValues>
+        <Int Name="Count">2</Int>
+        <Int Name="DataSet">1</Int>
+        <DataValue>
+          <Real Name="Value">2.200000</Real>
+        </DataValue>
+        <DataValue>
+          <Real Name="Value">3.000000</Real>
+        </DataValue>
+      </DataValues>
+    </DataFrame>
+    <DataFrame Name="Frame2">
+      <Real Name="X">3.000000</Real>
+      <DataValues>
+        <Int Name="Count">2</Int>
+        <Int Name="DataSet">0</Int>
+        <DataValue>
+          <Real Name="Value">3.300000</Real>
+        </DataValue>
+        <DataValue>
+          <Real Name="Value">0.500000</Real>
+        </DataValue>
+      </DataValues>
+      <DataValues>
+        <Int Name="Count">2</Int>
+        <Int Name="DataSet">0</Int>
+        <DataValue>
+          <Real Name="Value">1.200000</Real>
+        </DataValue>
+        <DataValue>
+          <Real Name="Value">2.000000</Real>
+        </DataValue>
+      </DataValues>
+      <DataValues>
+        <Int Name="Count">2</Int>
+        <Int Name="DataSet">1</Int>
+        <DataValue>
+          <Real Name="Value">1.300000</Real>
+        </DataValue>
+        <DataValue>
+          <Real Name="Value">1.000000</Real>
+        </DataValue>
+      </DataValues>
+    </DataFrame>
+  </AnalysisData>
+  <AnalysisData Name="HistogramAverage">
+    <DataFrame Name="Frame0">
+      <Real Name="X">1.250000</Real>
+      <DataValues>
+        <Int Name="Count">2</Int>
+        <DataValue>
+          <Real Name="Value">1.333333</Real>
+          <Real Name="Error">0.577350</Real>
+        </DataValue>
+        <DataValue>
+          <Real Name="Value">1.000000</Real>
+          <Real Name="Error">0.000000</Real>
+        </DataValue>
+      </DataValues>
+    </DataFrame>
+    <DataFrame Name="Frame1">
+      <Real Name="X">1.750000</Real>
+      <DataValues>
+        <Int Name="Count">2</Int>
+        <DataValue>
+          <Real Name="Value">0.000000</Real>
+          <Real Name="Error">0.000000</Real>
+        </DataValue>
+        <DataValue>
+          <Real Name="Value">0.000000</Real>
+          <Real Name="Error">0.000000</Real>
+        </DataValue>
+      </DataValues>
+    </DataFrame>
+    <DataFrame Name="Frame2">
+      <Real Name="X">2.250000</Real>
+      <DataValues>
+        <Int Name="Count">2</Int>
+        <DataValue>
+          <Real Name="Value">0.000000</Real>
+          <Real Name="Error">0.000000</Real>
+        </DataValue>
+        <DataValue>
+          <Real Name="Value">2.000000</Real>
+          <Real Name="Error">1.414214</Real>
+        </DataValue>
+      </DataValues>
+    </DataFrame>
+    <DataFrame Name="Frame3">
+      <Real Name="X">2.750000</Real>
+      <DataValues>
+        <Int Name="Count">2</Int>
+        <DataValue>
+          <Real Name="Value">0.000000</Real>
+          <Real Name="Error">0.000000</Real>
+        </DataValue>
+        <DataValue>
+          <Real Name="Value">2.000000</Real>
+          <Real Name="Error">0.000000</Real>
+        </DataValue>
+      </DataValues>
+    </DataFrame>
+  </AnalysisData>
+</ReferenceData>
index dea4a9f8e591371d3d82c2fc4ea5e0f80a8004cd..6ce464f4b1ac343c4c0a21a1b0a12fd4b9d6d1c0 100644 (file)
@@ -8,15 +8,12 @@
         <Int Name="Count">3</Int>
         <DataValue>
           <Real Name="Value">0.000000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
         <DataValue>
           <Real Name="Value">1.000000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
         <DataValue>
           <Real Name="Value">2.000000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
       </DataValues>
     </DataFrame>
         <Int Name="Count">3</Int>
         <DataValue>
           <Real Name="Value">1.000000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
         <DataValue>
           <Real Name="Value">1.000000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
         <DataValue>
           <Real Name="Value">1.000000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
       </DataValues>
     </DataFrame>
         <Int Name="Count">3</Int>
         <DataValue>
           <Real Name="Value">2.000000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
         <DataValue>
           <Real Name="Value">0.000000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
         <DataValue>
           <Real Name="Value">0.000000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
       </DataValues>
     </DataFrame>
diff --git a/src/gromacs/analysisdata/tests/refdata/FrameAverageModuleTest_HandlesMultipleDataSets.xml b/src/gromacs/analysisdata/tests/refdata/FrameAverageModuleTest_HandlesMultipleDataSets.xml
new file mode 100644 (file)
index 0000000..63865e9
--- /dev/null
@@ -0,0 +1,151 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <AnalysisData Name="InputData">
+    <DataFrame Name="Frame0">
+      <Real Name="X">1.000000</Real>
+      <DataValues>
+        <Int Name="Count">3</Int>
+        <Int Name="DataSet">0</Int>
+        <DataValue>
+          <Real Name="Value">0.000000</Real>
+        </DataValue>
+        <DataValue>
+          <Real Name="Value">1.000000</Real>
+        </DataValue>
+        <DataValue>
+          <Real Name="Value">2.000000</Real>
+        </DataValue>
+      </DataValues>
+      <DataValues>
+        <Int Name="Count">2</Int>
+        <Int Name="DataSet">0</Int>
+        <Int Name="FirstColumn">0</Int>
+        <Int Name="LastColumn">1</Int>
+        <DataValue>
+          <Real Name="Value">1.000000</Real>
+        </DataValue>
+        <DataValue>
+          <Real Name="Value">0.000000</Real>
+        </DataValue>
+      </DataValues>
+      <DataValues>
+        <Int Name="Count">2</Int>
+        <Int Name="DataSet">1</Int>
+        <DataValue>
+          <Real Name="Value">2.000000</Real>
+        </DataValue>
+        <DataValue>
+          <Real Name="Value">1.000000</Real>
+        </DataValue>
+      </DataValues>
+      <DataValues>
+        <Int Name="Count">1</Int>
+        <Int Name="DataSet">1</Int>
+        <Int Name="FirstColumn">1</Int>
+        <Int Name="LastColumn">1</Int>
+        <DataValue>
+          <Real Name="Value">2.000000</Real>
+        </DataValue>
+      </DataValues>
+    </DataFrame>
+    <DataFrame Name="Frame1">
+      <Real Name="X">2.000000</Real>
+      <DataValues>
+        <Int Name="Count">2</Int>
+        <Int Name="DataSet">0</Int>
+        <Int Name="FirstColumn">0</Int>
+        <Int Name="LastColumn">1</Int>
+        <DataValue>
+          <Real Name="Value">1.000000</Real>
+        </DataValue>
+        <DataValue>
+          <Real Name="Value">1.000000</Real>
+        </DataValue>
+      </DataValues>
+      <DataValues>
+        <Int Name="Count">1</Int>
+        <Int Name="DataSet">0</Int>
+        <Int Name="FirstColumn">2</Int>
+        <Int Name="LastColumn">2</Int>
+        <DataValue>
+          <Real Name="Value">2.000000</Real>
+        </DataValue>
+      </DataValues>
+      <DataValues>
+        <Int Name="Count">2</Int>
+        <Int Name="DataSet">1</Int>
+        <DataValue>
+          <Real Name="Value">1.000000</Real>
+        </DataValue>
+        <DataValue>
+          <Real Name="Value">0.000000</Real>
+        </DataValue>
+      </DataValues>
+    </DataFrame>
+    <DataFrame Name="Frame2">
+      <Real Name="X">3.000000</Real>
+      <DataValues>
+        <Int Name="Count">3</Int>
+        <Int Name="DataSet">0</Int>
+        <DataValue>
+          <Real Name="Value">2.000000</Real>
+        </DataValue>
+        <DataValue>
+          <Real Name="Value">0.000000</Real>
+        </DataValue>
+        <DataValue>
+          <Real Name="Value">0.000000</Real>
+        </DataValue>
+      </DataValues>
+      <DataValues>
+        <Int Name="Count">2</Int>
+        <Int Name="DataSet">1</Int>
+        <DataValue>
+          <Real Name="Value">0.000000</Real>
+        </DataValue>
+        <DataValue>
+          <Real Name="Value">2.000000</Real>
+        </DataValue>
+      </DataValues>
+    </DataFrame>
+  </AnalysisData>
+  <AnalysisData Name="FrameAverage">
+    <DataFrame Name="Frame0">
+      <Real Name="X">1.000000</Real>
+      <DataValues>
+        <Int Name="Count">2</Int>
+        <DataValue>
+          <Real Name="Value">0.800000</Real>
+        </DataValue>
+        <DataValue>
+          <Real Name="Value">1.666667</Real>
+        </DataValue>
+      </DataValues>
+    </DataFrame>
+    <DataFrame Name="Frame1">
+      <Real Name="X">2.000000</Real>
+      <DataValues>
+        <Int Name="Count">2</Int>
+        <DataValue>
+          <Real Name="Value">1.333333</Real>
+        </DataValue>
+        <DataValue>
+          <Real Name="Value">0.500000</Real>
+        </DataValue>
+      </DataValues>
+    </DataFrame>
+    <DataFrame Name="Frame2">
+      <Real Name="X">3.000000</Real>
+      <DataValues>
+        <Int Name="Count">2</Int>
+        <DataValue>
+          <Real Name="Value">0.666667</Real>
+        </DataValue>
+        <DataValue>
+          <Real Name="Value">1.000000</Real>
+        </DataValue>
+      </DataValues>
+    </DataFrame>
+  </AnalysisData>
+</ReferenceData>
diff --git a/src/gromacs/analysisdata/tests/refdata/LifetimeModuleTest_BasicTest.xml b/src/gromacs/analysisdata/tests/refdata/LifetimeModuleTest_BasicTest.xml
new file mode 100644 (file)
index 0000000..8196671
--- /dev/null
@@ -0,0 +1,80 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <AnalysisData Name="InputData">
+    <DataFrame Name="Frame0">
+      <Real Name="X">1.000000</Real>
+      <DataValues>
+        <Int Name="Count">3</Int>
+        <DataValue>
+          <Real Name="Value">1.000000</Real>
+        </DataValue>
+        <DataValue>
+          <Real Name="Value">1.000000</Real>
+        </DataValue>
+        <DataValue>
+          <Real Name="Value">1.000000</Real>
+        </DataValue>
+      </DataValues>
+    </DataFrame>
+    <DataFrame Name="Frame1">
+      <Real Name="X">2.000000</Real>
+      <DataValues>
+        <Int Name="Count">3</Int>
+        <DataValue>
+          <Real Name="Value">1.000000</Real>
+        </DataValue>
+        <DataValue>
+          <Real Name="Value">0.000000</Real>
+        </DataValue>
+        <DataValue>
+          <Real Name="Value">1.000000</Real>
+        </DataValue>
+      </DataValues>
+    </DataFrame>
+    <DataFrame Name="Frame2">
+      <Real Name="X">3.000000</Real>
+      <DataValues>
+        <Int Name="Count">3</Int>
+        <DataValue>
+          <Real Name="Value">0.000000</Real>
+        </DataValue>
+        <DataValue>
+          <Real Name="Value">1.000000</Real>
+        </DataValue>
+        <DataValue>
+          <Real Name="Value">1.000000</Real>
+        </DataValue>
+      </DataValues>
+    </DataFrame>
+  </AnalysisData>
+  <AnalysisData Name="Lifetime">
+    <DataFrame Name="Frame0">
+      <Real Name="X">0.000000</Real>
+      <DataValues>
+        <Int Name="Count">1</Int>
+        <DataValue>
+          <Real Name="Value">0.666667</Real>
+        </DataValue>
+      </DataValues>
+    </DataFrame>
+    <DataFrame Name="Frame1">
+      <Real Name="X">1.000000</Real>
+      <DataValues>
+        <Int Name="Count">1</Int>
+        <DataValue>
+          <Real Name="Value">0.500000</Real>
+        </DataValue>
+      </DataValues>
+    </DataFrame>
+    <DataFrame Name="Frame2">
+      <Real Name="X">2.000000</Real>
+      <DataValues>
+        <Int Name="Count">1</Int>
+        <DataValue>
+          <Real Name="Value">1.000000</Real>
+        </DataValue>
+      </DataValues>
+    </DataFrame>
+  </AnalysisData>
+</ReferenceData>
diff --git a/src/gromacs/analysisdata/tests/refdata/LifetimeModuleTest_CumulativeTest.xml b/src/gromacs/analysisdata/tests/refdata/LifetimeModuleTest_CumulativeTest.xml
new file mode 100644 (file)
index 0000000..bda456c
--- /dev/null
@@ -0,0 +1,80 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <AnalysisData Name="InputData">
+    <DataFrame Name="Frame0">
+      <Real Name="X">1.000000</Real>
+      <DataValues>
+        <Int Name="Count">3</Int>
+        <DataValue>
+          <Real Name="Value">1.000000</Real>
+        </DataValue>
+        <DataValue>
+          <Real Name="Value">1.000000</Real>
+        </DataValue>
+        <DataValue>
+          <Real Name="Value">1.000000</Real>
+        </DataValue>
+      </DataValues>
+    </DataFrame>
+    <DataFrame Name="Frame1">
+      <Real Name="X">2.000000</Real>
+      <DataValues>
+        <Int Name="Count">3</Int>
+        <DataValue>
+          <Real Name="Value">1.000000</Real>
+        </DataValue>
+        <DataValue>
+          <Real Name="Value">0.000000</Real>
+        </DataValue>
+        <DataValue>
+          <Real Name="Value">1.000000</Real>
+        </DataValue>
+      </DataValues>
+    </DataFrame>
+    <DataFrame Name="Frame2">
+      <Real Name="X">3.000000</Real>
+      <DataValues>
+        <Int Name="Count">3</Int>
+        <DataValue>
+          <Real Name="Value">0.000000</Real>
+        </DataValue>
+        <DataValue>
+          <Real Name="Value">1.000000</Real>
+        </DataValue>
+        <DataValue>
+          <Real Name="Value">1.000000</Real>
+        </DataValue>
+      </DataValues>
+    </DataFrame>
+  </AnalysisData>
+  <AnalysisData Name="Lifetime">
+    <DataFrame Name="Frame0">
+      <Real Name="X">0.000000</Real>
+      <DataValues>
+        <Int Name="Count">1</Int>
+        <DataValue>
+          <Real Name="Value">2.333333</Real>
+        </DataValue>
+      </DataValues>
+    </DataFrame>
+    <DataFrame Name="Frame1">
+      <Real Name="X">1.000000</Real>
+      <DataValues>
+        <Int Name="Count">1</Int>
+        <DataValue>
+          <Real Name="Value">1.500000</Real>
+        </DataValue>
+      </DataValues>
+    </DataFrame>
+    <DataFrame Name="Frame2">
+      <Real Name="X">2.000000</Real>
+      <DataValues>
+        <Int Name="Count">1</Int>
+        <DataValue>
+          <Real Name="Value">1.000000</Real>
+        </DataValue>
+      </DataValues>
+    </DataFrame>
+  </AnalysisData>
+</ReferenceData>
diff --git a/src/gromacs/analysisdata/tests/refdata/LifetimeModuleTest_HandlesMultipleDataSets.xml b/src/gromacs/analysisdata/tests/refdata/LifetimeModuleTest_HandlesMultipleDataSets.xml
new file mode 100644 (file)
index 0000000..913f42c
--- /dev/null
@@ -0,0 +1,113 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <AnalysisData Name="InputData">
+    <DataFrame Name="Frame0">
+      <Real Name="X">1.000000</Real>
+      <DataValues>
+        <Int Name="Count">2</Int>
+        <Int Name="DataSet">0</Int>
+        <DataValue>
+          <Real Name="Value">1.000000</Real>
+        </DataValue>
+        <DataValue>
+          <Real Name="Value">1.000000</Real>
+        </DataValue>
+      </DataValues>
+      <DataValues>
+        <Int Name="Count">2</Int>
+        <Int Name="DataSet">1</Int>
+        <DataValue>
+          <Real Name="Value">0.000000</Real>
+        </DataValue>
+        <DataValue>
+          <Real Name="Value">0.000000</Real>
+        </DataValue>
+      </DataValues>
+    </DataFrame>
+    <DataFrame Name="Frame1">
+      <Real Name="X">2.000000</Real>
+      <DataValues>
+        <Int Name="Count">2</Int>
+        <Int Name="DataSet">0</Int>
+        <DataValue>
+          <Real Name="Value">1.000000</Real>
+        </DataValue>
+        <DataValue>
+          <Real Name="Value">0.000000</Real>
+        </DataValue>
+      </DataValues>
+      <DataValues>
+        <Int Name="Count">2</Int>
+        <Int Name="DataSet">1</Int>
+        <DataValue>
+          <Real Name="Value">1.000000</Real>
+        </DataValue>
+        <DataValue>
+          <Real Name="Value">0.000000</Real>
+        </DataValue>
+      </DataValues>
+    </DataFrame>
+    <DataFrame Name="Frame2">
+      <Real Name="X">3.000000</Real>
+      <DataValues>
+        <Int Name="Count">2</Int>
+        <Int Name="DataSet">0</Int>
+        <DataValue>
+          <Real Name="Value">1.000000</Real>
+        </DataValue>
+        <DataValue>
+          <Real Name="Value">0.000000</Real>
+        </DataValue>
+      </DataValues>
+      <DataValues>
+        <Int Name="Count">2</Int>
+        <Int Name="DataSet">1</Int>
+        <DataValue>
+          <Real Name="Value">1.000000</Real>
+        </DataValue>
+        <DataValue>
+          <Real Name="Value">1.000000</Real>
+        </DataValue>
+      </DataValues>
+    </DataFrame>
+  </AnalysisData>
+  <AnalysisData Name="Lifetime">
+    <DataFrame Name="Frame0">
+      <Real Name="X">0.000000</Real>
+      <DataValues>
+        <Int Name="Count">2</Int>
+        <DataValue>
+          <Real Name="Value">0.333333</Real>
+        </DataValue>
+        <DataValue>
+          <Real Name="Value">0.333333</Real>
+        </DataValue>
+      </DataValues>
+    </DataFrame>
+    <DataFrame Name="Frame1">
+      <Real Name="X">1.000000</Real>
+      <DataValues>
+        <Int Name="Count">2</Int>
+        <DataValue>
+          <Real Name="Value">0.000000</Real>
+        </DataValue>
+        <DataValue>
+          <Real Name="Value">0.500000</Real>
+        </DataValue>
+      </DataValues>
+    </DataFrame>
+    <DataFrame Name="Frame2">
+      <Real Name="X">2.000000</Real>
+      <DataValues>
+        <Int Name="Count">2</Int>
+        <DataValue>
+          <Real Name="Value">1.000000</Real>
+        </DataValue>
+        <DataValue>
+          <Real Name="Value">0.000000</Real>
+        </DataValue>
+      </DataValues>
+    </DataFrame>
+  </AnalysisData>
+</ReferenceData>
index 15c02759741d105aff654d5e842e871c62e07664..c4bcf44b66d2c08e52ccd3e9e773bcb8a276c93c 100644 (file)
@@ -8,28 +8,24 @@
         <Int Name="Count">1</Int>
         <DataValue>
           <Real Name="Value">0.700000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
       </DataValues>
       <DataValues>
         <Int Name="Count">1</Int>
         <DataValue>
           <Real Name="Value">1.100000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
       </DataValues>
       <DataValues>
         <Int Name="Count">1</Int>
         <DataValue>
           <Real Name="Value">2.300000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
       </DataValues>
       <DataValues>
         <Int Name="Count">1</Int>
         <DataValue>
           <Real Name="Value">2.900000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
       </DataValues>
     </DataFrame>
         <Int Name="Count">1</Int>
         <DataValue>
           <Real Name="Value">1.300000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
       </DataValues>
       <DataValues>
         <Int Name="Count">1</Int>
         <DataValue>
           <Real Name="Value">2.200000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
       </DataValues>
     </DataFrame>
         <Int Name="Count">1</Int>
         <DataValue>
           <Real Name="Value">3.300000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
       </DataValues>
       <DataValues>
         <Int Name="Count">1</Int>
         <DataValue>
           <Real Name="Value">1.200000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
       </DataValues>
       <DataValues>
         <Int Name="Count">1</Int>
         <DataValue>
           <Real Name="Value">1.300000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
       </DataValues>
     </DataFrame>
     <DataFrame Name="Frame0">
       <Real Name="X">1.250000</Real>
       <DataValues>
-        <Int Name="Count">2</Int>
+        <Int Name="Count">1</Int>
         <DataValue>
           <Real Name="Value">1.333333</Real>
-        </DataValue>
-        <DataValue>
-          <Real Name="Value">0.577350</Real>
+          <Real Name="Error">0.577350</Real>
         </DataValue>
       </DataValues>
     </DataFrame>
     <DataFrame Name="Frame1">
       <Real Name="X">1.750000</Real>
       <DataValues>
-        <Int Name="Count">2</Int>
-        <DataValue>
-          <Real Name="Value">0.000000</Real>
-        </DataValue>
+        <Int Name="Count">1</Int>
         <DataValue>
           <Real Name="Value">0.000000</Real>
+          <Real Name="Error">0.000000</Real>
         </DataValue>
       </DataValues>
     </DataFrame>
     <DataFrame Name="Frame2">
       <Real Name="X">2.250000</Real>
       <DataValues>
-        <Int Name="Count">2</Int>
+        <Int Name="Count">1</Int>
         <DataValue>
           <Real Name="Value">0.666667</Real>
-        </DataValue>
-        <DataValue>
-          <Real Name="Value">0.577350</Real>
+          <Real Name="Error">0.577350</Real>
         </DataValue>
       </DataValues>
     </DataFrame>
     <DataFrame Name="Frame3">
       <Real Name="X">2.750000</Real>
       <DataValues>
-        <Int Name="Count">2</Int>
+        <Int Name="Count">1</Int>
         <DataValue>
           <Real Name="Value">0.333333</Real>
-        </DataValue>
-        <DataValue>
-          <Real Name="Value">0.577350</Real>
+          <Real Name="Error">0.577350</Real>
         </DataValue>
       </DataValues>
     </DataFrame>
index 5c8f6038167e5fdeda76c993a0c644541be1ee75..226eadba194512a29e31f5f72fbb5004097f984e 100644 (file)
@@ -8,28 +8,24 @@
         <Int Name="Count">1</Int>
         <DataValue>
           <Real Name="Value">0.700000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
       </DataValues>
       <DataValues>
         <Int Name="Count">1</Int>
         <DataValue>
           <Real Name="Value">1.100000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
       </DataValues>
       <DataValues>
         <Int Name="Count">1</Int>
         <DataValue>
           <Real Name="Value">2.300000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
       </DataValues>
       <DataValues>
         <Int Name="Count">1</Int>
         <DataValue>
           <Real Name="Value">2.900000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
       </DataValues>
     </DataFrame>
         <Int Name="Count">1</Int>
         <DataValue>
           <Real Name="Value">1.300000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
       </DataValues>
       <DataValues>
         <Int Name="Count">1</Int>
         <DataValue>
           <Real Name="Value">2.200000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
       </DataValues>
     </DataFrame>
         <Int Name="Count">1</Int>
         <DataValue>
           <Real Name="Value">3.300000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
       </DataValues>
       <DataValues>
         <Int Name="Count">1</Int>
         <DataValue>
           <Real Name="Value">1.200000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
       </DataValues>
       <DataValues>
         <Int Name="Count">1</Int>
         <DataValue>
           <Real Name="Value">1.300000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
       </DataValues>
     </DataFrame>
     <DataFrame Name="Frame0">
       <Real Name="X">1.250000</Real>
       <DataValues>
-        <Int Name="Count">2</Int>
+        <Int Name="Count">1</Int>
         <DataValue>
           <Real Name="Value">1.666667</Real>
-        </DataValue>
-        <DataValue>
-          <Real Name="Value">0.577350</Real>
+          <Real Name="Error">0.577350</Real>
         </DataValue>
       </DataValues>
     </DataFrame>
     <DataFrame Name="Frame1">
       <Real Name="X">1.750000</Real>
       <DataValues>
-        <Int Name="Count">2</Int>
-        <DataValue>
-          <Real Name="Value">0.000000</Real>
-        </DataValue>
+        <Int Name="Count">1</Int>
         <DataValue>
           <Real Name="Value">0.000000</Real>
+          <Real Name="Error">0.000000</Real>
         </DataValue>
       </DataValues>
     </DataFrame>
     <DataFrame Name="Frame2">
       <Real Name="X">2.250000</Real>
       <DataValues>
-        <Int Name="Count">2</Int>
+        <Int Name="Count">1</Int>
         <DataValue>
           <Real Name="Value">0.666667</Real>
-        </DataValue>
-        <DataValue>
-          <Real Name="Value">0.577350</Real>
+          <Real Name="Error">0.577350</Real>
         </DataValue>
       </DataValues>
     </DataFrame>
     <DataFrame Name="Frame3">
       <Real Name="X">2.750000</Real>
       <DataValues>
-        <Int Name="Count">2</Int>
+        <Int Name="Count">1</Int>
         <DataValue>
           <Real Name="Value">0.666667</Real>
-        </DataValue>
-        <DataValue>
-          <Real Name="Value">0.577350</Real>
+          <Real Name="Error">0.577350</Real>
         </DataValue>
       </DataValues>
     </DataFrame>
index 95af2f52ebc0a3f18e9611fc1cfa03f3b8a6415e..ee7d8f389c73636984a70acb73f6cbcd41a8b9ec 100644 (file)
@@ -8,44 +8,36 @@
         <Int Name="Count">2</Int>
         <DataValue>
           <Real Name="Value">0.700000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
         <DataValue>
           <Real Name="Value">0.500000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
       </DataValues>
       <DataValues>
         <Int Name="Count">2</Int>
         <DataValue>
           <Real Name="Value">1.100000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
         <DataValue>
           <Real Name="Value">1.000000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
       </DataValues>
       <DataValues>
         <Int Name="Count">2</Int>
         <DataValue>
           <Real Name="Value">2.300000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
         <DataValue>
           <Real Name="Value">1.000000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
       </DataValues>
       <DataValues>
         <Int Name="Count">2</Int>
         <DataValue>
           <Real Name="Value">2.900000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
         <DataValue>
           <Real Name="Value">2.000000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
       </DataValues>
     </DataFrame>
         <Int Name="Count">2</Int>
         <DataValue>
           <Real Name="Value">1.300000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
         <DataValue>
           <Real Name="Value">1.000000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
       </DataValues>
       <DataValues>
         <Int Name="Count">2</Int>
         <DataValue>
           <Real Name="Value">2.200000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
         <DataValue>
           <Real Name="Value">3.000000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
       </DataValues>
     </DataFrame>
         <Int Name="Count">2</Int>
         <DataValue>
           <Real Name="Value">3.300000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
         <DataValue>
           <Real Name="Value">0.500000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
       </DataValues>
       <DataValues>
         <Int Name="Count">2</Int>
         <DataValue>
           <Real Name="Value">1.200000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
         <DataValue>
           <Real Name="Value">2.000000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
       </DataValues>
       <DataValues>
         <Int Name="Count">2</Int>
         <DataValue>
           <Real Name="Value">1.300000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
         <DataValue>
           <Real Name="Value">1.000000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
       </DataValues>
     </DataFrame>
     <DataFrame Name="Frame0">
       <Real Name="X">1.250000</Real>
       <DataValues>
-        <Int Name="Count">2</Int>
+        <Int Name="Count">1</Int>
         <DataValue>
           <Real Name="Value">1.666667</Real>
-        </DataValue>
-        <DataValue>
-          <Real Name="Value">1.154701</Real>
+          <Real Name="Error">1.154701</Real>
         </DataValue>
       </DataValues>
     </DataFrame>
     <DataFrame Name="Frame1">
       <Real Name="X">1.750000</Real>
       <DataValues>
-        <Int Name="Count">2</Int>
-        <DataValue>
-          <Real Name="Value">0.000000</Real>
-        </DataValue>
+        <Int Name="Count">1</Int>
         <DataValue>
           <Real Name="Value">0.000000</Real>
+          <Real Name="Error">0.000000</Real>
         </DataValue>
       </DataValues>
     </DataFrame>
     <DataFrame Name="Frame2">
       <Real Name="X">2.250000</Real>
       <DataValues>
-        <Int Name="Count">2</Int>
+        <Int Name="Count">1</Int>
         <DataValue>
           <Real Name="Value">1.333333</Real>
-        </DataValue>
-        <DataValue>
-          <Real Name="Value">1.527525</Real>
+          <Real Name="Error">1.527525</Real>
         </DataValue>
       </DataValues>
     </DataFrame>
     <DataFrame Name="Frame3">
       <Real Name="X">2.750000</Real>
       <DataValues>
-        <Int Name="Count">2</Int>
+        <Int Name="Count">1</Int>
         <DataValue>
           <Real Name="Value">0.666667</Real>
-        </DataValue>
-        <DataValue>
-          <Real Name="Value">1.154701</Real>
+          <Real Name="Error">1.154701</Real>
         </DataValue>
       </DataValues>
     </DataFrame>
index 48d48130c915292683a901d24975700833e599ba..667e24c83feb362299f7a0d43bd4dcc6aef2d069 100644 (file)
@@ -8,44 +8,36 @@
         <Int Name="Count">2</Int>
         <DataValue>
           <Real Name="Value">0.700000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
         <DataValue>
           <Real Name="Value">0.500000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
       </DataValues>
       <DataValues>
         <Int Name="Count">2</Int>
         <DataValue>
           <Real Name="Value">1.100000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
         <DataValue>
           <Real Name="Value">1.000000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
       </DataValues>
       <DataValues>
         <Int Name="Count">2</Int>
         <DataValue>
           <Real Name="Value">2.300000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
         <DataValue>
           <Real Name="Value">1.000000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
       </DataValues>
       <DataValues>
         <Int Name="Count">2</Int>
         <DataValue>
           <Real Name="Value">2.900000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
         <DataValue>
           <Real Name="Value">2.000000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
       </DataValues>
     </DataFrame>
         <Int Name="Count">2</Int>
         <DataValue>
           <Real Name="Value">1.300000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
         <DataValue>
           <Real Name="Value">1.000000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
       </DataValues>
       <DataValues>
         <Int Name="Count">2</Int>
         <DataValue>
           <Real Name="Value">2.200000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
         <DataValue>
           <Real Name="Value">3.000000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
       </DataValues>
     </DataFrame>
         <Int Name="Count">2</Int>
         <DataValue>
           <Real Name="Value">3.300000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
         <DataValue>
           <Real Name="Value">0.500000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
       </DataValues>
       <DataValues>
         <Int Name="Count">2</Int>
         <DataValue>
           <Real Name="Value">1.200000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
         <DataValue>
           <Real Name="Value">2.000000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
       </DataValues>
       <DataValues>
         <Int Name="Count">2</Int>
         <DataValue>
           <Real Name="Value">1.300000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
         <DataValue>
           <Real Name="Value">1.000000</Real>
-          <Real Name="Error">0.000000</Real>
         </DataValue>
       </DataValues>
     </DataFrame>
     <DataFrame Name="Frame0">
       <Real Name="X">1.250000</Real>
       <DataValues>
-        <Int Name="Count">2</Int>
+        <Int Name="Count">1</Int>
         <DataValue>
           <Real Name="Value">1.833333</Real>
-        </DataValue>
-        <DataValue>
-          <Real Name="Value">1.040833</Real>
+          <Real Name="Error">1.040833</Real>
         </DataValue>
       </DataValues>
     </DataFrame>
     <DataFrame Name="Frame1">
       <Real Name="X">1.750000</Real>
       <DataValues>
-        <Int Name="Count">2</Int>
-        <DataValue>
-          <Real Name="Value">0.000000</Real>
-        </DataValue>
+        <Int Name="Count">1</Int>
         <DataValue>
           <Real Name="Value">0.000000</Real>
+          <Real Name="Error">0.000000</Real>
         </DataValue>
       </DataValues>
     </DataFrame>
     <DataFrame Name="Frame2">
       <Real Name="X">2.250000</Real>
       <DataValues>
-        <Int Name="Count">2</Int>
+        <Int Name="Count">1</Int>
         <DataValue>
           <Real Name="Value">1.333333</Real>
-        </DataValue>
-        <DataValue>
-          <Real Name="Value">1.527525</Real>
+          <Real Name="Error">1.527525</Real>
         </DataValue>
       </DataValues>
     </DataFrame>
     <DataFrame Name="Frame3">
       <Real Name="X">2.750000</Real>
       <DataValues>
-        <Int Name="Count">2</Int>
+        <Int Name="Count">1</Int>
         <DataValue>
           <Real Name="Value">0.833333</Real>
-        </DataValue>
-        <DataValue>
-          <Real Name="Value">1.040833</Real>
+          <Real Name="Error">1.040833</Real>
         </DataValue>
       </DataValues>
     </DataFrame>
diff --git a/src/gromacs/analysisdata/tests/refdata/WeightedHistogramModuleTest_HandlesMultipleDataSets.xml b/src/gromacs/analysisdata/tests/refdata/WeightedHistogramModuleTest_HandlesMultipleDataSets.xml
new file mode 100644 (file)
index 0000000..4c02d37
--- /dev/null
@@ -0,0 +1,270 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <AnalysisData Name="InputData">
+    <DataFrame Name="Frame0">
+      <Real Name="X">1.000000</Real>
+      <DataValues>
+        <Int Name="Count">2</Int>
+        <Int Name="DataSet">0</Int>
+        <DataValue>
+          <Real Name="Value">0.700000</Real>
+        </DataValue>
+        <DataValue>
+          <Real Name="Value">0.500000</Real>
+        </DataValue>
+      </DataValues>
+      <DataValues>
+        <Int Name="Count">2</Int>
+        <Int Name="DataSet">0</Int>
+        <DataValue>
+          <Real Name="Value">1.100000</Real>
+        </DataValue>
+        <DataValue>
+          <Real Name="Value">1.000000</Real>
+        </DataValue>
+      </DataValues>
+      <DataValues>
+        <Int Name="Count">2</Int>
+        <Int Name="DataSet">1</Int>
+        <DataValue>
+          <Real Name="Value">2.300000</Real>
+        </DataValue>
+        <DataValue>
+          <Real Name="Value">1.000000</Real>
+        </DataValue>
+      </DataValues>
+      <DataValues>
+        <Int Name="Count">2</Int>
+        <Int Name="DataSet">1</Int>
+        <DataValue>
+          <Real Name="Value">2.900000</Real>
+        </DataValue>
+        <DataValue>
+          <Real Name="Value">2.000000</Real>
+        </DataValue>
+      </DataValues>
+    </DataFrame>
+    <DataFrame Name="Frame1">
+      <Real Name="X">2.000000</Real>
+      <DataValues>
+        <Int Name="Count">2</Int>
+        <Int Name="DataSet">0</Int>
+        <DataValue>
+          <Real Name="Value">1.300000</Real>
+        </DataValue>
+        <DataValue>
+          <Real Name="Value">1.000000</Real>
+        </DataValue>
+      </DataValues>
+      <DataValues>
+        <Int Name="Count">2</Int>
+        <Int Name="DataSet">1</Int>
+        <DataValue>
+          <Real Name="Value">2.200000</Real>
+        </DataValue>
+        <DataValue>
+          <Real Name="Value">3.000000</Real>
+        </DataValue>
+      </DataValues>
+    </DataFrame>
+    <DataFrame Name="Frame2">
+      <Real Name="X">3.000000</Real>
+      <DataValues>
+        <Int Name="Count">2</Int>
+        <Int Name="DataSet">0</Int>
+        <DataValue>
+          <Real Name="Value">3.300000</Real>
+        </DataValue>
+        <DataValue>
+          <Real Name="Value">0.500000</Real>
+        </DataValue>
+      </DataValues>
+      <DataValues>
+        <Int Name="Count">2</Int>
+        <Int Name="DataSet">0</Int>
+        <DataValue>
+          <Real Name="Value">1.200000</Real>
+        </DataValue>
+        <DataValue>
+          <Real Name="Value">2.000000</Real>
+        </DataValue>
+      </DataValues>
+      <DataValues>
+        <Int Name="Count">2</Int>
+        <Int Name="DataSet">1</Int>
+        <DataValue>
+          <Real Name="Value">1.300000</Real>
+        </DataValue>
+        <DataValue>
+          <Real Name="Value">1.000000</Real>
+        </DataValue>
+      </DataValues>
+    </DataFrame>
+  </AnalysisData>
+  <AnalysisData Name="Histogram">
+    <DataFrame Name="Frame0">
+      <Real Name="X">1.000000</Real>
+      <DataValues>
+        <Int Name="Count">4</Int>
+        <Int Name="DataSet">0</Int>
+        <DataValue>
+          <Real Name="Value">1.000000</Real>
+        </DataValue>
+        <DataValue>
+          <Real Name="Value">0.000000</Real>
+        </DataValue>
+        <DataValue>
+          <Real Name="Value">0.000000</Real>
+        </DataValue>
+        <DataValue>
+          <Real Name="Value">0.000000</Real>
+        </DataValue>
+      </DataValues>
+      <DataValues>
+        <Int Name="Count">4</Int>
+        <Int Name="DataSet">1</Int>
+        <DataValue>
+          <Real Name="Value">0.000000</Real>
+        </DataValue>
+        <DataValue>
+          <Real Name="Value">0.000000</Real>
+        </DataValue>
+        <DataValue>
+          <Real Name="Value">1.000000</Real>
+        </DataValue>
+        <DataValue>
+          <Real Name="Value">2.000000</Real>
+        </DataValue>
+      </DataValues>
+    </DataFrame>
+    <DataFrame Name="Frame1">
+      <Real Name="X">2.000000</Real>
+      <DataValues>
+        <Int Name="Count">4</Int>
+        <Int Name="DataSet">0</Int>
+        <DataValue>
+          <Real Name="Value">1.000000</Real>
+        </DataValue>
+        <DataValue>
+          <Real Name="Value">0.000000</Real>
+        </DataValue>
+        <DataValue>
+          <Real Name="Value">0.000000</Real>
+        </DataValue>
+        <DataValue>
+          <Real Name="Value">0.000000</Real>
+        </DataValue>
+      </DataValues>
+      <DataValues>
+        <Int Name="Count">4</Int>
+        <Int Name="DataSet">1</Int>
+        <DataValue>
+          <Real Name="Value">0.000000</Real>
+        </DataValue>
+        <DataValue>
+          <Real Name="Value">0.000000</Real>
+        </DataValue>
+        <DataValue>
+          <Real Name="Value">3.000000</Real>
+        </DataValue>
+        <DataValue>
+          <Real Name="Value">0.000000</Real>
+        </DataValue>
+      </DataValues>
+    </DataFrame>
+    <DataFrame Name="Frame2">
+      <Real Name="X">3.000000</Real>
+      <DataValues>
+        <Int Name="Count">4</Int>
+        <Int Name="DataSet">0</Int>
+        <DataValue>
+          <Real Name="Value">2.000000</Real>
+        </DataValue>
+        <DataValue>
+          <Real Name="Value">0.000000</Real>
+        </DataValue>
+        <DataValue>
+          <Real Name="Value">0.000000</Real>
+        </DataValue>
+        <DataValue>
+          <Real Name="Value">0.000000</Real>
+        </DataValue>
+      </DataValues>
+      <DataValues>
+        <Int Name="Count">4</Int>
+        <Int Name="DataSet">1</Int>
+        <DataValue>
+          <Real Name="Value">1.000000</Real>
+        </DataValue>
+        <DataValue>
+          <Real Name="Value">0.000000</Real>
+        </DataValue>
+        <DataValue>
+          <Real Name="Value">0.000000</Real>
+        </DataValue>
+        <DataValue>
+          <Real Name="Value">0.000000</Real>
+        </DataValue>
+      </DataValues>
+    </DataFrame>
+  </AnalysisData>
+  <AnalysisData Name="HistogramAverage">
+    <DataFrame Name="Frame0">
+      <Real Name="X">1.250000</Real>
+      <DataValues>
+        <Int Name="Count">2</Int>
+        <DataValue>
+          <Real Name="Value">1.333333</Real>
+          <Real Name="Error">0.577350</Real>
+        </DataValue>
+        <DataValue>
+          <Real Name="Value">0.333333</Real>
+          <Real Name="Error">0.577350</Real>
+        </DataValue>
+      </DataValues>
+    </DataFrame>
+    <DataFrame Name="Frame1">
+      <Real Name="X">1.750000</Real>
+      <DataValues>
+        <Int Name="Count">2</Int>
+        <DataValue>
+          <Real Name="Value">0.000000</Real>
+          <Real Name="Error">0.000000</Real>
+        </DataValue>
+        <DataValue>
+          <Real Name="Value">0.000000</Real>
+          <Real Name="Error">0.000000</Real>
+        </DataValue>
+      </DataValues>
+    </DataFrame>
+    <DataFrame Name="Frame2">
+      <Real Name="X">2.250000</Real>
+      <DataValues>
+        <Int Name="Count">2</Int>
+        <DataValue>
+          <Real Name="Value">0.000000</Real>
+          <Real Name="Error">0.000000</Real>
+        </DataValue>
+        <DataValue>
+          <Real Name="Value">1.333333</Real>
+          <Real Name="Error">1.527525</Real>
+        </DataValue>
+      </DataValues>
+    </DataFrame>
+    <DataFrame Name="Frame3">
+      <Real Name="X">2.750000</Real>
+      <DataValues>
+        <Int Name="Count">2</Int>
+        <DataValue>
+          <Real Name="Value">0.000000</Real>
+          <Real Name="Error">0.000000</Real>
+        </DataValue>
+        <DataValue>
+          <Real Name="Value">0.666667</Real>
+          <Real Name="Error">1.154701</Real>
+        </DataValue>
+      </DataValues>
+    </DataFrame>
+  </AnalysisData>
+</ReferenceData>
index abad36c26ad0cb0afb66fb9e89ea03b97c6a1cc7..9223385238c2e5c31edd3d1071226396511a3791 100644 (file)
@@ -13,12 +13,17 @@ and use the copy_xsl.sh script to copy it to relevant locations.
 <xsl:import href="common-referencedata.xsl"/>
 
 <xsl:template match="AnalysisData">
+    <xsl:variable name="has-datasetspec"
+                  select="DataFrame/DataValues/Int[@Name='DataSet']"/>
     <xsl:variable name="has-columnspec"
                   select="DataFrame/DataValues/Int[@Name='FirstColumn']"/>
     <table border="1">
         <tr>
             <th>Frame</th>
             <th>X</th>
+            <xsl:if test="$has-datasetspec">
+                <th>Set</th>
+            </xsl:if>
             <xsl:if test="$has-columnspec">
                 <th>Columns</th>
             </xsl:if>
@@ -28,6 +33,9 @@ and use the copy_xsl.sh script to copy it to relevant locations.
         <tr>
             <td><xsl:value-of select="../@Name"/></td>
             <td><xsl:value-of select="../Real[@Name='X']"/></td>
+            <xsl:if test="$has-datasetspec">
+                <td><xsl:value-of select="Int[@Name='DataSet']"/></td>
+            </xsl:if>
             <xsl:if test="$has-columnspec">
                 <td>
                     <xsl:choose>
@@ -46,8 +54,19 @@ and use the copy_xsl.sh script to copy it to relevant locations.
     </table>
 </xsl:template>
 
+<xsl:template match="DataValue[Bool[@Name='Present']='false']">
+    (
+    <xsl:value-of select="Real[@Name='Value']"/>
+    <xsl:if test="Real[@Name='Error']">
+        &#177; <xsl:value-of select="Real[@Name='Error']"/>
+    </xsl:if>
+    )
+</xsl:template>
 <xsl:template match="DataValue">
     <xsl:value-of select="Real[@Name='Value']"/>
+    <xsl:if test="Real[@Name='Error']">
+        &#177; <xsl:value-of select="Real[@Name='Error']"/>
+    </xsl:if>
 </xsl:template>
 
 </xsl:stylesheet>
index be6dcc239845d5dd16a187252a941b8b89c44cd8..68e16ef9960c5ce5675724bf7835248dd4fdccc0 100644 (file)
@@ -48,6 +48,7 @@
 #include <utility>
 
 #include "gromacs/legacyheaders/copyrite.h"
+#include "gromacs/legacyheaders/network.h"
 
 #include "gromacs/commandline/cmdlinemodule.h"
 #include "gromacs/commandline/cmdlineparser.h"
@@ -60,6 +61,7 @@
 #include "gromacs/utility/exceptions.h"
 #include "gromacs/utility/file.h"
 #include "gromacs/utility/gmxassert.h"
+#include "gromacs/utility/init.h"
 #include "gromacs/utility/programinfo.h"
 #include "gromacs/utility/stringutil.h"
 
@@ -311,6 +313,78 @@ void CommandLineHelpModule::writeHelp(const HelpWriterContext &context) const
     // TODO: More information.
 }
 
+namespace
+{
+
+/********************************************************************
+ * CMainCommandLineModule
+ */
+
+/*! \internal \brief
+ * Implements a CommandLineModuleInterface, given a function with C/C++ main()
+ * signature.
+ *
+ * \ingroup module_commandline
+ */
+class CMainCommandLineModule : public CommandLineModuleInterface
+{
+    public:
+        //! \copydoc gmx::CommandLineModuleManager::CMainFunction
+        typedef CommandLineModuleManager::CMainFunction CMainFunction;
+
+        /*! \brief
+         * Creates a wrapper module for the given main function.
+         *
+         * \param[in] name             Name for the module.
+         * \param[in] shortDescription One-line description for the module.
+         * \param[in] mainFunction     Main function to wrap.
+         *
+         * Does not throw.  This is essential for correct implementation of
+         * CommandLineModuleManager::runAsMainCMain().
+         */
+        CMainCommandLineModule(const char *name, const char *shortDescription,
+                               CMainFunction mainFunction)
+            : name_(name), shortDescription_(shortDescription),
+              mainFunction_(mainFunction)
+        {
+        }
+
+        virtual const char *name() const
+        {
+            return name_;
+        }
+        virtual const char *shortDescription() const
+        {
+            return shortDescription_;
+        }
+
+        virtual int run(int argc, char *argv[])
+        {
+            return mainFunction_(argc, argv);
+        }
+        virtual void writeHelp(const HelpWriterContext &context) const
+        {
+            if (context.outputFormat() != eHelpOutputFormat_Console)
+            {
+                GMX_THROW(NotImplementedError(
+                                  "Command-line help is not implemented for this output format"));
+            }
+            char *argv[2];
+            // TODO: The constness should not be cast away.
+            argv[0] = const_cast<char *>(name_);
+            argv[1] = const_cast<char *>("-h");
+            mainFunction_(2, argv);
+        }
+
+    private:
+        const char             *name_;
+        const char             *shortDescription_;
+        CMainFunction           mainFunction_;
+
+};
+
+}   // namespace
+
 /********************************************************************
  * CommandLineModuleManager::Impl
  */
@@ -409,6 +483,7 @@ CommandLineModuleManager::Impl::Impl(ProgramInfo *programInfo)
     : programInfo_(*programInfo), helpModule_(NULL), singleModule_(NULL),
       bQuiet_(false), bStdOutInfo_(false)
 {
+    binaryInfoSettings_.copyright(true);
 }
 
 CommandLineModuleMap::const_iterator
@@ -437,70 +512,98 @@ CommandLineModuleManager::Impl::findModuleFromBinaryName(
 CommandLineModuleInterface *
 CommandLineModuleManager::Impl::processCommonOptions(int *argc, char ***argv)
 {
-    if (singleModule_ != NULL)
+    // Check if we are directly invoking a certain module.
+    CommandLineModuleInterface *module = singleModule_;
+    if (module == NULL)
     {
-        // TODO: Process common options also in this case.
-        return singleModule_;
+        // Also check for invokation through named symlinks.
+        CommandLineModuleMap::const_iterator moduleIter
+            = findModuleFromBinaryName(programInfo_);
+        if (moduleIter != modules_.end())
+        {
+            module = moduleIter->second.get();
+        }
     }
-    // Check if the module is called through a symlink.
-    CommandLineModuleMap::const_iterator module
-        = findModuleFromBinaryName(programInfo_);
-    if (module != modules_.end())
+
+    bool bHelp      = false;
+    bool bVersion   = false;
+    bool bCopyright = true;
+    // TODO: Print the common options into the help.
+    // TODO: It would be nice to propagate at least the -quiet option to
+    // the modules so that they can also be quiet in response to this.
+    // TODO: Consider handling -h and related options here instead of in the
+    // modules (also -hidden needs to be transfered here to make that work).
+    // That would mean that with -h, all module-specific options would get
+    // ignored.  This means that the help output would not depend on the
+    // command line, but would always show the default values (making it
+    // possible to simplify it further), but also that mdrun -h could not be
+    // used for option validation in g_tune_pme.
+    Options options(NULL, NULL);
+    if (module == NULL)
     {
-        // TODO: Process common options also in this case.
-        return module->second.get();
+        options.addOption(BooleanOption("h").store(&bHelp));
     }
-    // If not, process options to the wrapper binary.
-    // TODO: This should be done by CommandLineParser
-    // (together with the above TODO).
-    int moduleArgOffset = 1;
-    while (moduleArgOffset < *argc && (*argv)[moduleArgOffset][0] == '-')
+    options.addOption(BooleanOption("quiet").store(&bQuiet_));
+    options.addOption(BooleanOption("version").store(&bVersion));
+    options.addOption(BooleanOption("copyright").store(&bCopyright));
+
+    if (module == NULL)
     {
-        ++moduleArgOffset;
+        // If not in single-module mode, process options to the wrapper binary.
+        // TODO: Ideally, this could be done by CommandLineParser.
+        int argcForWrapper = 1;
+        while (argcForWrapper < *argc && (*argv)[argcForWrapper][0] == '-')
+        {
+            ++argcForWrapper;
+        }
+        if (argcForWrapper > 1)
+        {
+            CommandLineParser(&options).parse(&argcForWrapper, *argv);
+        }
+        // If no action requested and there is a module specified, process it.
+        if (argcForWrapper < *argc && !bHelp && !bVersion)
+        {
+            const char *moduleName = (*argv)[argcForWrapper];
+            CommandLineModuleMap::const_iterator moduleIter
+                = findModuleByName(moduleName);
+            if (moduleIter == modules_.end())
+            {
+                std::string message =
+                    formatString("'%s' is not a GROMACS command.", moduleName);
+                GMX_THROW(InvalidInputError(message));
+            }
+            module = moduleIter->second.get();
+            programInfo_.setDisplayName(
+                    programInfo_.realBinaryName() + "-" + moduleIter->first);
+            *argc -= argcForWrapper;
+            *argv += argcForWrapper;
+            // After this point, argc and argv are the same independent of
+            // which path is taken: (*argv)[0] is the module name.
+        }
     }
-    bool bHelp      = false;
-    bool bVersion   = false;
-    bool bCopyright = false;
-    if (moduleArgOffset > 1)
+    else
     {
-        // TODO: Print these options into the help.
-        // TODO: It would be nice to propagate at least the -quiet option to
-        // the modules so that they can also be quiet in response to this.
-        Options options(NULL, NULL);
-        options.addOption(BooleanOption("h").store(&bHelp));
-        options.addOption(BooleanOption("quiet").store(&bQuiet_));
-        options.addOption(BooleanOption("version").store(&bVersion));
-        options.addOption(BooleanOption("copyright").store(&bCopyright));
-        CommandLineParser(&options).parse(&moduleArgOffset, *argv);
-        options.finish();
-        binaryInfoSettings_.extendedInfo(bVersion);
-        binaryInfoSettings_.copyright(bCopyright);
+        // In single-module mode, recognize the common options also after the
+        // module name.
+        CommandLineParser(&options).skipUnknown(true).parse(argc, *argv);
     }
-    if (bVersion || bCopyright)
+    options.finish();
+    binaryInfoSettings_.extendedInfo(bVersion);
+    binaryInfoSettings_.copyright(bCopyright);
+    if (bVersion)
     {
         bQuiet_      = false;
         bStdOutInfo_ = true;
         return NULL;
     }
-    // If no module or help requested, show the help.
-    if (moduleArgOffset == *argc || bHelp)
+    // If no module specified and no other action, show the help.
+    // Also explicitly specifying -h for the wrapper binary goes here.
+    if (module == NULL)
     {
         *argc = 1;
         return helpModule_;
     }
-    // Find the module to run and arguments to it.
-    const char *moduleName = (*argv)[moduleArgOffset];
-    module = findModuleByName(moduleName);
-    if (module == modules_.end())
-    {
-        std::string message = formatString("'%s' is not a GROMACS command.", moduleName);
-        GMX_THROW(InvalidInputError(message));
-    }
-    programInfo_.setDisplayName(
-            programInfo_.realBinaryName() + "-" + module->first);
-    *argc -= moduleArgOffset;
-    *argv += moduleArgOffset;
-    return module->second.get();
+    return module;
 }
 
 /********************************************************************
@@ -531,6 +634,15 @@ void CommandLineModuleManager::addModule(CommandLineModulePointer module)
     addHelpTopic(move(helpTopic));
 }
 
+void CommandLineModuleManager::addModuleCMain(
+        const char *name, const char *shortDescription,
+        CMainFunction mainFunction)
+{
+    CommandLineModulePointer module(
+            new CMainCommandLineModule(name, shortDescription, mainFunction));
+    addModule(move(module));
+}
+
 void CommandLineModuleManager::addHelpTopic(HelpTopicPointer topic)
 {
     if (impl_->helpModule_ == NULL)
@@ -544,18 +656,24 @@ void CommandLineModuleManager::addHelpTopic(HelpTopicPointer topic)
 int CommandLineModuleManager::run(int argc, char *argv[])
 {
     CommandLineModuleInterface *module;
+    const bool                  bMaster = (!gmx_mpi_initialized() || gmx_node_rank() == 0);
     try
     {
         module = impl_->processCommonOptions(&argc, &argv);
     }
     catch (const std::exception &)
     {
-        if (!impl_->bQuiet_)
+        if (bMaster && !impl_->bQuiet_)
         {
-            printBinaryInformation(stderr, impl_->programInfo_);
+            printBinaryInformation(stderr, impl_->programInfo_,
+                                   impl_->binaryInfoSettings_);
         }
         throw;
     }
+    if (!bMaster)
+    {
+        impl_->bQuiet_ = true;
+    }
     if (!impl_->bQuiet_)
     {
         FILE *out = (impl_->bStdOutInfo_ ? stdout : stderr);
@@ -579,18 +697,28 @@ int CommandLineModuleManager::run(int argc, char *argv[])
 int CommandLineModuleManager::runAsMainSingleModule(
         int argc, char *argv[], CommandLineModuleInterface *module)
 {
-    ProgramInfo &programInfo = ProgramInfo::init(argc, argv);
+    ProgramInfo &programInfo = gmx::init(&argc, &argv);
     try
     {
-       CommandLineModuleManager manager(&programInfo);
-       manager.impl_->singleModule_ = module;
-       return manager.run(argc, argv);
+        CommandLineModuleManager manager(&programInfo);
+        manager.impl_->singleModule_ = module;
+        int rc = manager.run(argc, argv);
+        gmx::finalize();
+        return rc;
     }
     catch (const std::exception &ex)
     {
-       printFatalErrorMessage(stderr, ex);
-       return 1;
+        printFatalErrorMessage(stderr, ex);
+        return processExceptionAtExit(ex);
     }
 }
 
+// static
+int CommandLineModuleManager::runAsMainCMain(
+        int argc, char *argv[], CMainFunction mainFunction)
+{
+    CMainCommandLineModule module(argv[0], NULL, mainFunction);
+    return runAsMainSingleModule(argc, argv, &module);
+}
+
 } // namespace gmx
index 70a35418b4abd090565e1e73ef6ad53bd9b66e71..c6dcbdcfe9f8b777097ffec6e224aeb7d54fc132 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2012, by the GROMACS development team, led by
+ * Copyright (c) 2012,2013, 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.
@@ -64,18 +64,19 @@ typedef gmx_unique_ptr<CommandLineModuleInterface>::type
  * \code
    int main(int argc, char *argv[])
    {
-       const gmx::ProgramInfo &programInfo =
-           gmx::ProgramInfo::init("gmx", argc, argv);
+       gmx::ProgramInfo &programInfo = gmx::init("gmx", &argc, &argv);
        try
        {
-           gmx::CommandLineModuleManager manager(programInfo);
+           gmx::CommandLineModuleManager manager(&programInfo);
            // <register all necessary modules>
-           return manager.run(argc, argv);
+           int rc = manager.run(argc, argv);
+           gmx::finalize();
+           return rc;
        }
        catch (const std::exception &ex)
        {
            gmx::printFatalErrorMessage(stderr, ex);
-           return 1;
+           return gmx::processExceptionAtExit(ex);
        }
    }
  * \endcode
@@ -86,6 +87,9 @@ typedef gmx_unique_ptr<CommandLineModuleInterface>::type
 class CommandLineModuleManager
 {
     public:
+        //! Function pointer type for a C main function.
+        typedef int (*CMainFunction)(int argc, char *argv[]);
+
         /*! \brief
          * Implements a main() method that runs a single module.
          *
@@ -118,6 +122,37 @@ class CommandLineModuleManager
          */
         static int runAsMainSingleModule(int argc, char *argv[],
                                          CommandLineModuleInterface *module);
+        /*! \brief
+         * Implements a main() method that runs a given function.
+         *
+         * \param argc         \c argc passed to main().
+         * \param argv         \c argv passed to main().
+         * \param mainFunction The main()-like method to wrap.
+         *
+         * This method creates a dummy command-line module that does its
+         * processing by calling \p mainFunction; see addModuleCMain() for
+         * details.  It then runs this module with runAsMainSingleModule().
+         * This allows the resulting executable to handle common options and do
+         * other common actions (e.g., startup headers) without duplicate code
+         * in the main methods.
+         *
+         * Usage:
+         * \code
+           int my_main(int argc, char *argv[])
+           {
+               // <...>
+           }
+
+           int main(int argc, char *argv[])
+           {
+               return gmx::CommandLineModuleManager::runAsMainCMain(argc, argv, &my_main);
+           }
+         * \endcode
+         *
+         * Does not throw.  All exceptions are caught and handled internally.
+         */
+        static int runAsMainCMain(int argc, char *argv[],
+                                  CMainFunction mainFunction);
 
         /*! \brief
          * Initializes a command-line module manager.
@@ -160,6 +195,25 @@ class CommandLineModuleManager
          * \see registerModule()
          */
         void addModule(CommandLineModulePointer module);
+        /*! \brief
+         * Adds a module that runs a given main()-like function.
+         *
+         * \param[in] name             Name for the module.
+         * \param[in] shortDescription One-line description for the module.
+         * \param[in] mainFunction     Main function to wrap.
+         * \throws    std::bad_alloc if out of memory.
+         *
+         * There is normally no need to call this method outside the Gromacs
+         * library.  User code usually wants to use runAsMainCMain().
+         *
+         * \p name and \p shortDescription should be string constants, or the
+         * caller should otherwise ensure that they stay in scope for the
+         * duration the CommandLineModuleManager object exists.
+         * \p mainFunction should call parse_common_args() to process its
+         * command-line arguments.
+         */
+        void addModuleCMain(const char *name, const char *shortDescription,
+                            CMainFunction mainFunction);
         /*! \brief
          * Registers a module of a certain type to this manager.
          *
index 992b07088775f71de3dbb2dd8390330d1e6a438a..bdd44ed1a8141ee107ac9eed7099ec0f4f3e3bfa 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2010,2011,2012, by the GROMACS development team, led by
+ * Copyright (c) 2010,2011,2012,2013, 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.
  */
 #include "cmdlineparser.h"
 
-#include <cctype>
+#include <cstdlib>
 
 #include <string>
 #include <vector>
 
 #include "gromacs/options/optionsassigner.h"
+#include "gromacs/utility/common.h"
 #include "gromacs/utility/exceptions.h"
 
 namespace gmx
@@ -67,17 +68,52 @@ class CommandLineParser::Impl
         //! Sets the options object to parse to.
         explicit Impl(Options *options);
 
+        /*! \brief
+         * Determines whether a cmdline parameter starts an option and the name
+         * of that option.
+         *
+         * \param[in] arg  Individual argument from \c argv.
+         * \returns The beginning of the option name in \p arg, or NULL if
+         *     \p arg does not look like an option.
+         */
+        const char *toOptionName(const char *arg) const;
+
         //! Helper object for assigning the options.
         OptionsAssigner         assigner_;
+        //! Whether to allow and skip unknown options.
+        bool                    bSkipUnknown_;
 };
 
 CommandLineParser::Impl::Impl(Options *options)
-    : assigner_(options)
+    : assigner_(options), bSkipUnknown_(false)
 {
     assigner_.setAcceptBooleanNoPrefix(true);
     assigner_.setNoStrictSectioning(true);
 }
 
+const char *CommandLineParser::Impl::toOptionName(const char *arg) const
+{
+    // Lone '-' or '--' is not an option.
+    if (arg[0] != '-' || arg[1] == '\0' || (arg[1] == '-' && arg[2] == '\0'))
+    {
+        return NULL;
+    }
+    // Something starting with '--' is always an option.
+    if (arg[1] == '-')
+    {
+        return arg + 2;
+    }
+    // Don't return numbers as option names.
+    char *endptr;
+    // We are only interested in endptr, not in the actual value.
+    GMX_IGNORE_RETURN_VALUE(std::strtod(arg, &endptr));
+    if (*endptr == '\0')
+    {
+        return NULL;
+    }
+    return arg + 1;
+}
+
 /********************************************************************
  * CommandLineParser
  */
@@ -91,31 +127,27 @@ CommandLineParser::~CommandLineParser()
 {
 }
 
-void CommandLineParser::parse(int *argc, char *argv[])
+CommandLineParser &CommandLineParser::skipUnknown(bool bEnabled)
 {
-    std::vector<std::string> commandLine;
-    for (int i = 0; i < *argc; ++i)
-    {
-        commandLine.push_back(argv[i]);
-    }
-    parse(&commandLine);
+    impl_->bSkipUnknown_ = bEnabled;
+    return *this;
 }
 
-void CommandLineParser::parse(std::vector<std::string> *commandLine)
+void CommandLineParser::parse(int *argc, char *argv[])
 {
     ExceptionInitializer errors("Invalid command-line options");
     std::string          currentContext;
-    // Start in the discard phase to skip options that can't be understood.
-    bool                 bDiscard = true;
+    bool                 bInOption = false;
 
     impl_->assigner_.start();
-    std::vector<std::string>::const_iterator arg;
-    for (arg = commandLine->begin() + 1; arg != commandLine->end(); ++arg)
+    int newi = 1;
+    for (int i = 1; i != *argc; ++i)
     {
-        // Lone '-' and numbers are passed as values.
-        if ((*arg)[0] == '-' && std::isalpha((*arg)[1]))
+        const char *const arg        = argv[i];
+        const char *const optionName = impl_->toOptionName(arg);
+        if (optionName != NULL)
         {
-            if (!bDiscard)
+            if (bInOption)
             {
                 try
                 {
@@ -126,28 +158,40 @@ void CommandLineParser::parse(std::vector<std::string> *commandLine)
                     ex.prependContext(currentContext);
                     errors.addCurrentExceptionAsNested();
                 }
-                currentContext.clear();
             }
-            currentContext = "In command-line option " + *arg;
-            bDiscard       = false;
+            currentContext = "In command-line option " + std::string(arg);
             try
             {
-                const char *name = arg->c_str() + 1;
-                impl_->assigner_.startOption(name);
+                bInOption = impl_->assigner_.tryStartOption(optionName);
+                if (!bInOption)
+                {
+                    currentContext.clear();
+                    if (!impl_->bSkipUnknown_)
+                    {
+                        std::string message =
+                            "Unknown command-line option " + std::string(arg);
+                        GMX_THROW(InvalidInputError(message));
+                    }
+                }
             }
             catch (UserInputError &ex)
             {
-                bDiscard = true;
+                // If tryStartOption() throws, make sure that the rest gets
+                // ignored.
+                // TODO: Consider whether we should remove the option from the
+                // command line nonetheless, as it is recognized, but just
+                // invalid.
+                bInOption = false;
                 ex.prependContext(currentContext);
                 errors.addCurrentExceptionAsNested();
                 currentContext.clear();
             }
         }
-        else if (!bDiscard)
+        else if (bInOption)
         {
             try
             {
-                impl_->assigner_.appendValue(*arg);
+                impl_->assigner_.appendValue(arg);
             }
             catch (UserInputError &ex)
             {
@@ -155,8 +199,20 @@ void CommandLineParser::parse(std::vector<std::string> *commandLine)
                 errors.addCurrentExceptionAsNested();
             }
         }
+        // Remove recognized options if applicable.
+        if (!bInOption && impl_->bSkipUnknown_)
+        {
+            argv[newi] = argv[i];
+            ++newi;
+        }
+    }
+    // Update the argc count if argv was modified.
+    if (impl_->bSkipUnknown_)
+    {
+        *argc = newi;
     }
-    if (!bDiscard)
+    // Finish the last option.
+    if (bInOption)
     {
         try
         {
index ac7f795a01e82c1cf3294730cc3454e93b147c80..b71f126daf25168baa2526ffcf80faf9669ce811 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2010,2011,2012, by the GROMACS development team, led by
+ * Copyright (c) 2010,2011,2012,2013, 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.
@@ -81,39 +81,37 @@ class CommandLineParser
         ~CommandLineParser();
 
         /*! \brief
-         * Parses the command line.
+         * Makes the parser skip unknown options and keep them in \c argv.
          *
-         * \throws  std::bad_alloc if out of memory.
-         * \throws  InvalidInputError if any errors were detected in the input.
+         * \param[in] bEnabled  Whether to skip and keep unknown options.
+         * \returns   *this
          *
-         * All command-line arguments are parsed, and an aggregate exception
-         * with all the detected errors is thrown in the end.
+         * Setting this option to true has dual effect: unknown options are
+         * silently skipped, and all recognized options are removed from
+         * \c argc and \c argv in parse().  These effects should be easy to
+         * separate into different flags if there is need for it.
+         *
+         * The default is false: unknown options result in exceptions and
+         * \c argc and \c argv are not modified.
          *
-         * Currently, the input parameters are not modified, but this may
-         * change if/when support for parsing only part of the options is
-         * implemented.
+         * Does not throw.
          */
-        void parse(int *argc, char *argv[]);
+        CommandLineParser &skipUnknown(bool bEnabled);
+
         /*! \brief
-         * Parses the command line from a std::vector.
+         * Parses the command line.
          *
-         * \param[in] commandLine  Array of command-line strings.
          * \throws  std::bad_alloc if out of memory.
          * \throws  InvalidInputError if any errors were detected in the input.
          *
-         * \p commandLine should relate to the standard \c argv array
-         * one-to-one.
-         *
-         * This method is provided for convenience for cases where the command
-         * line needs to be stored before parsing.
-         *
-         * Currently, the input parameters are not modified, but this may
-         * change if/when support for parsing only part of the options is
-         * implemented.
+         * All command-line arguments are parsed, and an aggregate exception
+         * with all the detected errors is thrown in the end.
          *
-         * \see parse(int *, char *[])
+         * If skipUnknown() is false, the input parameters are not modified.
+         * If skipUnknown() is true, recognized options and their values are
+         * removed from the argument list.  \c argv[0] is never modified.
          */
-        void parse(std::vector<std::string> *commandLine);
+        void parse(int *argc, char *argv[]);
 
     private:
         class Impl;
index d443acc2601c47487f0f8d4dd7d351c16c6c90a9..87cf7bd8777ffdb19b77b8a171f23a429013758a 100644 (file)
@@ -68,11 +68,13 @@ class CommandLineParserTest : public ::testing::Test
         bool                    flag_;
         std::vector<int>        ivalues_;
         std::vector<double>     dvalues_;
+        int                     ivalue1p_;
+        int                     ivalue12_;
 };
 
 CommandLineParserTest::CommandLineParserTest()
     : options_(NULL, NULL), parser_(&options_),
-      flag_(false)
+      flag_(false), ivalue1p_(0), ivalue12_(0)
 {
     using gmx::BooleanOption;
     using gmx::IntegerOption;
@@ -80,6 +82,8 @@ CommandLineParserTest::CommandLineParserTest()
     options_.addOption(BooleanOption("flag").store(&flag_));
     options_.addOption(IntegerOption("mvi").storeVector(&ivalues_).multiValue());
     options_.addOption(DoubleOption("mvd").storeVector(&dvalues_).allowMultiple());
+    options_.addOption(IntegerOption("1p").store(&ivalue1p_));
+    options_.addOption(IntegerOption("12").store(&ivalue12_));
 }
 
 TEST_F(CommandLineParserTest, HandlesSingleValues)
@@ -114,4 +118,57 @@ TEST_F(CommandLineParserTest, HandlesNegativeNumbers)
     EXPECT_DOUBLE_EQ(-2.7, dvalues_[0]);
 }
 
+TEST_F(CommandLineParserTest, HandlesDoubleDashOptionPrefix)
+{
+    const char *const cmdline[] = {
+        "test", "--mvi", "1", "-2", "--mvd", "-2.7"
+    };
+    CommandLine       args(CommandLine::create(cmdline));
+    ASSERT_NO_THROW_GMX(parser_.parse(&args.argc(), args.argv()));
+    ASSERT_NO_THROW_GMX(options_.finish());
+
+    ASSERT_EQ(2U, ivalues_.size());
+    EXPECT_EQ(1, ivalues_[0]);
+    EXPECT_EQ(-2, ivalues_[1]);
+    ASSERT_EQ(1U, dvalues_.size());
+    EXPECT_DOUBLE_EQ(-2.7, dvalues_[0]);
+}
+
+TEST_F(CommandLineParserTest, HandlesOptionsStartingWithNumbers)
+{
+    const char *const cmdline[] = {
+        "test", "--12", "1", "-1p", "-12"
+    };
+    CommandLine       args(CommandLine::create(cmdline));
+    ASSERT_NO_THROW_GMX(parser_.parse(&args.argc(), args.argv()));
+    ASSERT_NO_THROW_GMX(options_.finish());
+
+    EXPECT_EQ(1, ivalue12_);
+    EXPECT_EQ(-12, ivalue1p_);
+}
+
+TEST_F(CommandLineParserTest, HandlesSkipUnknown)
+{
+    const char *const cmdline[] = {
+        "test", "-opt1", "-flag", "-opt2", "value", "-mvi", "2", "-mvd", "2.7", "-opt3"
+    };
+    CommandLine       args(CommandLine::create(cmdline));
+    parser_.skipUnknown(true);
+    ASSERT_NO_THROW_GMX(parser_.parse(&args.argc(), args.argv()));
+    ASSERT_NO_THROW_GMX(options_.finish());
+
+    ASSERT_EQ(5, args.argc());
+    EXPECT_STREQ("test", args.arg(0));
+    EXPECT_STREQ("-opt1", args.arg(1));
+    EXPECT_STREQ("-opt2", args.arg(2));
+    EXPECT_STREQ("value", args.arg(3));
+    EXPECT_STREQ("-opt3", args.arg(4));
+
+    EXPECT_TRUE(flag_);
+    ASSERT_EQ(1U, ivalues_.size());
+    EXPECT_EQ(2, ivalues_[0]);
+    ASSERT_EQ(1U, dvalues_.size());
+    EXPECT_DOUBLE_EQ(2.7, dvalues_[0]);
+}
+
 } // namespace
index 5fba0be20760857b83dbdbf4ec8e05691b55e236..788d4e791d2c8b53d4b235c6d33e5a51f4f32f1a 100644 (file)
@@ -39,6 +39,7 @@
 #include "cmat.h"
 #include "smalloc.h"
 #include "macros.h"
+#include "vec.h"
 #include "xvgr.h"
 #include "matio.h"
 #include "futil.h"
@@ -51,11 +52,9 @@ t_mat *init_mat(int n1, gmx_bool b1D)
     m->n1     = n1;
     m->nn     = 0;
     m->b1D    = b1D;
-    m->emat   = 0;
     m->maxrms = 0;
     m->minrms = 1e20;
     m->sumrms = 0;
-    m->nn     = 0;
     m->mat    = mk_matrix(n1, n1, b1D);
 
     snew(m->erow, n1);
@@ -65,6 +64,29 @@ t_mat *init_mat(int n1, gmx_bool b1D)
     return m;
 }
 
+void copy_t_mat(t_mat *dst, t_mat *src)
+{
+    int i, j;
+
+    if (dst->nn != src->nn)
+    {
+        fprintf(stderr, "t_mat structures not identical in size dst %d src %d\n",dst->nn,src->nn);
+        return;
+    }
+    dst->maxrms = src->maxrms;
+    dst->minrms = src->minrms;
+    dst->sumrms = src->sumrms;
+    for(i = 0; (i < src->nn); i++)
+    {
+        for(j = 0; (j < src->nn); j++)
+        {
+            dst->mat[i][j] = src->mat[i][j];
+        }
+        dst->erow[i] = src->erow[i];
+        dst->m_ind[i] = src->m_ind[i];
+    }
+}
+
 void enlarge_mat(t_mat *m, int deltan)
 {
     int i, j;
@@ -122,50 +144,39 @@ void done_mat(t_mat **m)
     *m = NULL;
 }
 
-real row_energy(int nn, int row, real *mat)
-{
-    real re = 0;
-    int  i;
-
-    for (i = 0; (i < nn); i++)
-    {
-        re += abs(i-row)*mat[i];
-    }
-    return re/nn;
-}
-
 real mat_energy(t_mat *m)
 {
-    real re, retot;
-    int  j, jj;
+    int  j;
+    real emat = 0;
 
-    retot = 0;
-    for (j = 0; (j < m->nn); j++)
+    for (j = 0; (j < m->nn-1); j++)
     {
-        jj         = m->m_ind[j];
-        re         = row_energy(m->nn, jj, m->mat[j]);
-        m->erow[j] = re;
-        retot     += re;
+        emat += sqr(m->mat[j][j+1]);
     }
-    m->emat = retot/m->nn;
-    return m->emat;
+    return emat;
 }
 
-void swap_rows(t_mat *m, int isw, int jsw)
+void swap_rows(t_mat *m, int iswap, int jswap)
 {
     real *tmp, ttt;
-    int   i;
+    int   i, itmp;
+
+    /* Swap indices */
+    itmp            = m->m_ind[iswap];
+    m->m_ind[iswap] = m->m_ind[jswap];
+    m->m_ind[jswap] = itmp;
+
+    /* Swap rows (since the matrix is an array of pointers) */
+    tmp           = m->mat[iswap];
+    m->mat[iswap] = m->mat[jswap];
+    m->mat[jswap] = tmp;
 
-    /* Swap rows */
-    tmp         = m->mat[isw];
-    m->mat[isw] = m->mat[jsw];
-    m->mat[jsw] = tmp;
     /* Swap columns */
     for (i = 0; (i < m->nn); i++)
     {
-        ttt            = m->mat[isw][i];
-        m->mat[isw][i] = m->mat[jsw][i];
-        m->mat[jsw][i] = ttt;
+        ttt              = m->mat[i][iswap];
+        m->mat[i][iswap] = m->mat[i][jswap];
+        m->mat[i][jswap] = ttt;
     }
 }
 
index 613f0971dd014436d27247ac995193c8b871ec26..69930a48ec670f527343175350ab7c9bd936984a 100644 (file)
@@ -51,7 +51,7 @@ typedef struct {
     int      n1, nn;
     int     *m_ind;
     gmx_bool b1D;
-    real     emat, minrms, maxrms, sumrms;
+    real     minrms, maxrms, sumrms;
     real    *erow;
     real   **mat;
 } t_mat;
@@ -61,18 +61,18 @@ typedef struct {
 
 extern t_mat *init_mat(int n1, gmx_bool b1D);
 
+extern void copy_t_mat(t_mat *dst, t_mat *src);
+
 extern void enlarge_mat(t_mat *m, int deltan);
 
 extern void reset_index(t_mat *m);
 
-extern void swap_rows(t_mat *m, int isw, int jsw);
+extern void swap_rows(t_mat *m, int iswap, int jswap);
 
 extern void set_mat_entry(t_mat *m, int i, int j, real val);
 
 extern void done_mat(t_mat **m);
 
-extern real row_energy(int n1, int row, real *mat);
-
 extern real mat_energy(t_mat *mat);
 
 extern void swap_mat(t_mat *m);
index d4e4af2bb27828474bdf7867e8840dca438888b9..0a8be51c4ca8b789a1743611b79e49540b8b34bf 100644 (file)
@@ -47,7 +47,7 @@
 #include "vec.h"
 #include "macros.h"
 #include "index.h"
-#include "random.h"
+#include "gmx_random.h"
 #include "pbc.h"
 #include "rmpbc.h"
 #include "xvgr.h"
@@ -149,81 +149,137 @@ void cp_index(int nn, int from[], int to[])
     }
 }
 
-void mc_optimize(FILE *log, t_mat *m, int maxiter, int *seed, real kT)
+void mc_optimize(FILE *log, t_mat *m, real *time,
+                 int maxiter, int nrandom,
+                 int seed, real kT,
+                 const char *conv, output_env_t oenv)
 {
-    real  e[2], ei, ej, efac;
-    int  *low_index;
-    int   cur = 0;
-#define next (1-cur)
-    int   i, isw, jsw, iisw, jjsw, nn;
+    FILE      *fp = NULL;
+    real       ecur, enext, emin, prob, enorm;
+    int        i, j, iswap, jswap, nn, nuphill = 0;
+    gmx_rng_t  rng;
+    t_mat     *minimum;
 
-    fprintf(stderr, "\nDoing Monte Carlo clustering\n");
-    nn = m->nn;
-    snew(low_index, nn);
-    cp_index(nn, m->m_ind, low_index);
-    if (getenv("TESTMC"))
+    if (m->n1 != m->nn)
     {
-        e[cur] = mat_energy(m);
-        pr_energy(log, e[cur]);
-        fprintf(log, "Doing 1000 random swaps\n");
-        for (i = 0; (i < 1000); i++)
+        fprintf(stderr,"Can not do Monte Carlo optimization with a non-square matrix.\n");
+        return;
+    }
+    printf("\nDoing Monte Carlo optimization to find the smoothest trajectory\n");
+    printf("by reordering the frames to minimize the path between the two structures\n");
+    printf("that have the largest pairwise RMSD.\n");
+
+    iswap = jswap = -1;
+    enorm = m->mat[0][0];
+    for(i = 0; (i < m->n1); i++)
+    {
+        for(j = 0; (j < m->nn); j++)
         {
-            do
+            if (m->mat[i][j] > enorm) 
             {
-                isw = nn*rando(seed);
-                jsw = nn*rando(seed);
+                enorm = m->mat[i][j];
+                iswap   = i;
+                jswap   = j;
             }
-            while ((isw == jsw) || (isw >= nn) || (jsw >= nn));
-            iisw          = m->m_ind[isw];
-            jjsw          = m->m_ind[jsw];
-            m->m_ind[isw] = jjsw;
-            m->m_ind[jsw] = iisw;
         }
     }
-    e[cur] = mat_energy(m);
-    pr_energy(log, e[cur]);
+    if ((iswap == -1) || (jswap == -1))
+    {
+        fprintf(stderr, "Matrix contains identical values in all fields\n");
+        return;
+    }
+    swap_rows(m, 0, iswap);
+    swap_rows(m, m->n1-1, jswap);
+    emin = ecur = mat_energy(m);
+    printf("Largest distance %g between %d and %d. Energy: %g.\n",
+           enorm, iswap, jswap, emin);
+
+    rng = gmx_rng_init(seed);
+    nn = m->nn;
+
+    /* Initiate and store global minimum */
+    minimum = init_mat(nn, m->b1D);
+    minimum->nn = nn;
+    copy_t_mat(minimum, m);
+
+    if (NULL != conv)
+    {
+        fp = xvgropen(conv, "Convergence of the MC optimization",
+                      "Energy", "Step", oenv);
+    }
     for (i = 0; (i < maxiter); i++)
     {
+        /* Generate new swapping candidates */
         do
         {
-            isw = nn*rando(seed);
-            jsw = nn*rando(seed);
+            iswap = 1+(nn-2)*gmx_rng_uniform_real(rng);
+            jswap = 1+(nn-2)*gmx_rng_uniform_real(rng);
         }
-        while ((isw == jsw) || (isw >= nn) || (jsw >= nn));
-
-        iisw = m->m_ind[isw];
-        jjsw = m->m_ind[jsw];
-        ei   = row_energy(nn, iisw, m->mat[jsw]);
-        ej   = row_energy(nn, jjsw, m->mat[isw]);
+        while ((iswap == jswap) || (iswap >= nn-1) || (jswap >= nn-1));
 
-        e[next] = e[cur] + (ei+ej-EROW(m, isw)-EROW(m, jsw))/nn;
+        /* Apply swap and compute energy */
+        swap_rows(m, iswap, jswap);
+        enext = mat_energy(m);
 
-        efac = kT ? exp((e[next]-e[cur])/kT) : -1;
-        if ((e[next] > e[cur]) || (efac > rando(seed)))
+        /* Compute probability */
+        prob = 0;
+        if ((enext < ecur) || (i < nrandom))
         {
-
-            if (e[next] > e[cur])
+            prob = 1;
+            if (enext < emin)
             {
-                cp_index(nn, m->m_ind, low_index);
+                /* Store global minimum */
+                copy_t_mat(minimum, m);
+                emin = enext;
             }
-            else
+        }
+        else if (kT > 0)
+        {
+            /* Try Monte Carlo step */
+            prob = exp(-(enext-ecur)/(enorm*kT));
+        }
+
+        if ((prob == 1) || (gmx_rng_uniform_real(rng) < prob))
+        {
+            if (enext > ecur)
             {
-                fprintf(log, "Taking uphill step\n");
+                nuphill++;
             }
 
-            /* Now swapping rows */
-            m->m_ind[isw]  = jjsw;
-            m->m_ind[jsw]  = iisw;
-            EROW(m, isw)   = ei;
-            EROW(m, jsw)   = ej;
-            cur            = next;
-            fprintf(log, "Iter: %d Swapped %4d and %4d (now %g)",
-                    i, isw, jsw, mat_energy(m));
-            pr_energy(log, e[cur]);
+            fprintf(log, "Iter: %d Swapped %4d and %4d (energy: %g prob: %g)\n",
+                    i, iswap, jswap, enext, prob);
+            if (NULL != fp)
+            {
+                fprintf(fp, "%6d  %10g\n", i, enext);
+            }
+            ecur = enext;
         }
+        else
+        {
+            swap_rows(m, jswap, iswap);
+        }
+    }
+    fprintf(log, "%d uphill steps were taken during optimization\n",
+            nuphill);
+
+    /* Now swap the matrix to get it into global minimum mode */
+    copy_t_mat(m, minimum);
+
+    fprintf(log, "Global minimum energy %g\n", mat_energy(minimum));
+    fprintf(log, "Global minimum energy %g\n", mat_energy(m));
+    fprintf(log, "Swapped time and frame indices and RMSD to next neighbor:\n");
+    for(i=0; (i<m->nn); i++)
+    {
+        fprintf(log, "%10g  %5d  %10g\n",
+                time[m->m_ind[i]],
+                m->m_ind[i],
+                (i<m->nn-1) ? m->mat[m->m_ind[i]][m->m_ind[i+1]] : 0);
+    }
+
+    if (NULL != fp)
+    {
+        fclose(fp);
     }
-    /* Now restore the highest energy index */
-    cp_index(nn, low_index, m->m_ind);
 }
 
 static void calc_dist(int nind, rvec x[], real **d)
@@ -1290,7 +1346,16 @@ int gmx_cluster(int argc, char *argv[])
         "of a structure are the M closest structures or all structures within",
         "[TT]cutoff[tt].[PAR]",
 
-        "Monte Carlo: reorder the RMSD matrix using Monte Carlo.[PAR]",
+        "Monte Carlo: reorder the RMSD matrix using Monte Carlo such that",
+        "the order of the frames is using the smallest possible increments.",
+        "With this it is possible to make a smooth animation going from one",
+        "structure to another with the largest possible (e.g.) RMSD between",
+        "them, however the intermediate steps should be as small as possible.",
+        "Applications could be to visualize a potential of mean force",
+        "ensemble of simulations or a pulling simulation. Obviously the user",
+        "has to prepare the trajectory well (e.g. by not superimposing frames).",
+        "The final result can be inspect visually by looking at the matrix",
+        "[TT].xpm[tt] file, which should vary smoothly from bottom to top.[PAR]",
 
         "diagonalization: diagonalize the RMSD matrix.[PAR]",
 
@@ -1344,7 +1409,7 @@ int gmx_cluster(int argc, char *argv[])
     rvec              *xtps, *usextps, *x1, **xx = NULL;
     const char        *fn, *trx_out_fn;
     t_clusters         clust;
-    t_mat             *rms;
+    t_mat             *rms, *orig=NULL;
     real              *eigenvalues;
     t_topology         top;
     int                ePBC;
@@ -1376,7 +1441,7 @@ int gmx_cluster(int argc, char *argv[])
     static int   nlevels  = 40, skip = 1;
     static real  scalemax = -1.0, rmsdcut = 0.1, rmsmin = 0.0;
     gmx_bool     bRMSdist = FALSE, bBinary = FALSE, bAverage = FALSE, bFit = TRUE;
-    static int   niter    = 10000, seed = 1993, write_ncl = 0, write_nst = 1, minstruct = 1;
+    static int   niter    = 10000, nrandom = 0, seed = 1993, write_ncl = 0, write_nst = 1, minstruct = 1;
     static real  kT       = 1e-3;
     static int   M        = 10, P = 3;
     output_env_t oenv;
@@ -1416,9 +1481,11 @@ int gmx_cluster(int argc, char *argv[])
         { "-P",     FALSE, etINT,  {&P},
           "Number of identical nearest neighbors required to form a cluster" },
         { "-seed",  FALSE, etINT,  {&seed},
-          "Random number seed for Monte Carlo clustering algorithm" },
+          "Random number seed for Monte Carlo clustering algorithm: <= 0 means generate" },
         { "-niter", FALSE, etINT,  {&niter},
           "Number of iterations for MC" },
+        { "-nrandom", FALSE, etINT,  {&nrandom},
+          "The first iterations for MC may be done complete random, to shuffle the frames" },
         { "-kT",    FALSE, etREAL, {&kT},
           "Boltzmann weighting factor for Monte Carlo optimization "
           "(zero turns off uphill steps)" },
@@ -1430,10 +1497,12 @@ int gmx_cluster(int argc, char *argv[])
         { efTPS, "-s",     NULL,        ffOPTRD },
         { efNDX, NULL,     NULL,        ffOPTRD },
         { efXPM, "-dm",   "rmsd",       ffOPTRD },
+        { efXPM, "-om",   "rmsd-raw",   ffWRITE },
         { efXPM, "-o",    "rmsd-clust", ffWRITE },
         { efLOG, "-g",    "cluster",    ffWRITE },
         { efXVG, "-dist", "rmsd-dist",  ffOPTWR },
         { efXVG, "-ev",   "rmsd-eig",   ffOPTWR },
+        { efXVG, "-conv", "mc-conv",    ffOPTWR },
         { efXVG, "-sz",   "clust-size", ffOPTWR},
         { efXPM, "-tr",   "clust-trans", ffOPTWR},
         { efXVG, "-ntr",  "clust-trans", ffOPTWR},
@@ -1719,7 +1788,7 @@ int gmx_cluster(int argc, char *argv[])
                 rms->minrms, rms->maxrms);
     ffprintf_g(stderr, log, buf, "Average RMSD is %g\n", 2*rms->sumrms/(nf*(nf-1)));
     ffprintf_d(stderr, log, buf, "Number of structures for matrix %d\n", nf);
-    ffprintf_g(stderr, log, buf, "Energy of the matrix is %g nm\n", mat_energy(rms));
+    ffprintf_g(stderr, log, buf, "Energy of the matrix is %g.\n", mat_energy(rms));
     if (bUseRmsdCut && (rmsdcut < rms->minrms || rmsdcut > rms->maxrms) )
     {
         fprintf(stderr, "WARNING: rmsd cutoff %g is outside range of rmsd values "
@@ -1781,9 +1850,11 @@ int gmx_cluster(int argc, char *argv[])
             ffclose(fp);
             break;
         case m_monte_carlo:
-            mc_optimize(log, rms, niter, &seed, kT);
-            swap_mat(rms);
-            reset_index(rms);
+            orig = init_mat(rms->nn, FALSE);
+            orig->nn = rms->nn;
+            copy_t_mat(orig, rms);
+            mc_optimize(log, rms, time, niter, nrandom, seed, kT, 
+                        opt2fn_null("-conv",NFILE,fnm), oenv);
             break;
         case m_jarvis_patrick:
             jarvis_patrick(rms->nn, rms->mat, M, P, bJP_RMSD ? rmsdcut : -1, &clust);
@@ -1797,7 +1868,7 @@ int gmx_cluster(int argc, char *argv[])
 
     if (method == m_monte_carlo || method == m_diagonalize)
     {
-        fprintf(stderr, "Energy of the matrix after clustering is %g nm\n",
+        fprintf(stderr, "Energy of the matrix after clustering is %g.\n",
                 mat_energy(rms));
     }
 
@@ -1878,7 +1949,18 @@ int gmx_cluster(int argc, char *argv[])
     }
     fprintf(stderr, "\n");
     ffclose(fp);
-
+    if (NULL != orig)
+    {
+        fp = opt2FILE("-om", NFILE, fnm, "w");
+        sprintf(buf, "Time (%s)", output_env_get_time_unit(oenv));
+        sprintf(title, "RMS%sDeviation", bRMSdist ? " Distance " : " ");
+        write_xpm(fp, 0, title, "RMSD (nm)", buf, buf,
+                  nf, nf, time, time, orig->mat, 0.0, orig->maxrms,
+                  rlo_top, rhi_top, &nlevels);
+        ffclose(fp);
+        done_mat(&orig);
+        sfree(orig);
+    }
     /* now show what we've done */
     do_view(oenv, opt2fn("-o", NFILE, fnm), "-nxy");
     do_view(oenv, opt2fn_null("-sz", NFILE, fnm), "-nxy");
@@ -1893,6 +1975,7 @@ int gmx_cluster(int argc, char *argv[])
         do_view(oenv, opt2fn_null("-ntr", NFILE, fnm), "-nxy");
         do_view(oenv, opt2fn_null("-clid", NFILE, fnm), "-nxy");
     }
+    do_view(oenv, opt2fn_null("-conv", NFILE, fnm), NULL);
 
     return 0;
 }
index adec0b6f2067a0f88bf82ce989f4d1121333a1c9..fcb4c580b91a72070940561793709c984997be50 100644 (file)
@@ -723,7 +723,7 @@ int gmx_disre(int argc, char *argv[])
     };
 #define NFILE asize(fnm)
 
-    cr  = init_par(&argc, &argv);
+    cr  = init_par();
     parse_common_args(&argc, argv, PCA_CAN_TIME | PCA_CAN_VIEW | PCA_BE_NICE,
                       NFILE, fnm, asize(pa), pa, asize(desc), desc, 0, NULL, &oenv);
 
@@ -942,8 +942,6 @@ int gmx_disre(int argc, char *argv[])
         do_view(oenv, opt2fn("-dm", NFILE, fnm), "-nxy");
     }
 
-    gmx_finalize_par();
-
     gmx_log_close(fplog);
 
     return 0;
index 88b9d261638930ff4b6b8f8a87cbf784e4efbb13..a9916ca2101106c32ff97979ad750d54ea69c74d 100644 (file)
@@ -52,8 +52,6 @@
 #include "main.h"
 #include "macros.h"
 
-#include "gromacs/utility/programinfo.h"
-
 /* We use the same defines as in mvdata.c here */
 #define  block_bc(cr,   d) gmx_bcast(     sizeof(d),     &(d), (cr))
 #define nblock_bc(cr, nr, d) gmx_bcast((nr)*sizeof((d)[0]), (d), (cr))
@@ -1123,14 +1121,12 @@ int gmx_pme_error(int argc, char *argv[])
 
 #define NFILE asize(fnm)
 
-    cr = init_par(&argc, &argv);
-    gmx::ProgramInfo::init(argc, argv);
-
+    cr = init_par();
 #ifdef GMX_LIB_MPI
     MPI_Barrier(MPI_COMM_WORLD);
 #endif
 
-    PCA_Flags  = PCA_NOEXIT_ON_ARGS | PCA_STANDALONE;
+    PCA_Flags  = PCA_NOEXIT_ON_ARGS;
     PCA_Flags |= (MASTER(cr) ? 0 : PCA_QUIET);
 
     parse_common_args(&argc, argv, PCA_Flags,
@@ -1203,7 +1199,5 @@ int gmx_pme_error(int argc, char *argv[])
         fclose(fp);
     }
 
-    gmx_finalize_par();
-
     return 0;
 }
index 6e0794a8f3d8731a5f31f2c78bea4e7aa294fa6f..99229e00529ada12fed1ee71e0ba6fc1ff29a119 100644 (file)
@@ -78,32 +78,6 @@ static gmx_bool be_cool(void)
 #endif
 }
 
-static void space(FILE *out, int n)
-{
-    fprintf(out, "%*s", n, "");
-}
-
-static void sp_print(FILE *out, const char *s)
-{
-    int slen;
-
-    slen = strlen(s);
-    space(out, (80-slen)/2);
-    fprintf(out, "%s\n", s);
-}
-
-static void ster_print(FILE *out, const char *s)
-{
-    int  slen;
-    char buf[128];
-
-    snprintf(buf, 128, ":-)  %s  (-:", s);
-    slen = strlen(buf);
-    space(out, (80-slen)/2);
-    fprintf(out, "%s\n", buf);
-}
-
-
 static void pukeit(const char *db, const char *defstring, char *retstring,
                    int retsize, int *cqnum)
 {
@@ -179,55 +153,45 @@ void cool_quote(char *retstring, int retsize, int *cqnum)
     sfree(tmpstr);
 }
 
-static void CopyRight(FILE *out)
+static void printCopyright(FILE *fp)
 {
     static const char * const CopyrightText[] = {
-        "Written by Emile Apol, Rossen Apostolov, Herman J.C. Berendsen,",
-        "Aldert van Buuren, Pär Bjelkmar, Rudi van Drunen, Anton Feenstra, ",
-        "Gerrit Groenhof, Peter Kasson, Per Larsson, Pieter Meulenhoff, ",
-        "Teemu Murtola, Szilard Pall, Sander Pronk, Roland Schulz, ",
+        "GROMACS is written by:",
+        "Emile Apol, Rossen Apostolov, Herman J.C. Berendsen,",
+        "Aldert van Buuren, Pär Bjelkmar, Rudi van Drunen, Anton Feenstra,",
+        "Gerrit Groenhof, Peter Kasson, Per Larsson, Pieter Meulenhoff,",
+        "Teemu Murtola, Szilard Pall, Sander Pronk, Roland Schulz,",
         "Michael Shirts, Alfons Sijbers, Peter Tieleman,\n",
         "Berk Hess, David van der Spoel, and Erik Lindahl.\n",
         "Copyright (c) 1991-2000, University of Groningen, The Netherlands.",
         "Copyright (c) 2001-2013, The GROMACS development team at",
         "Uppsala University & The Royal Institute of Technology, Sweden.",
-        "check out http://www.gromacs.org for more information.\n"
+        "check out http://www.gromacs.org for more information."
     };
 
     static const char * const LicenseText[] = {
-        "This program is free software; you can redistribute it and/or",
-        "modify it under the terms of the GNU Lesser General Public License",
+        "GROMACS is free software; you can redistribute it and/or modify it",
+        "under the terms of the GNU Lesser General Public License",
         "as published by the Free Software Foundation; either version 2.1",
         "of the License, or (at your option) any later version."
     };
 
 #define NCR (int)asize(CopyrightText)
-/* TODO: Is this exception still needed? */
+// FAH has an exception permission from LGPL to allow digital signatures in Gromacs.
 #ifdef GMX_FAHCORE
-#define NLICENSE 0 /*FAH has an exception permission from LGPL to allow digital signatures in Gromacs*/
+#define NLICENSE 0
 #else
 #define NLICENSE (int)asize(LicenseText)
 #endif
 
-    char tmpstr[1024];
-    int  i;
-
-    // TODO: Consider making the output more compact to fit better with
-    // other information written by printBinaryInformation().
-    ster_print(out, "G  R  O  M  A  C  S");
-    fprintf(out, "\n");
-
-    bromacs(tmpstr, 1023);
-    sp_print(out, tmpstr);
-    fprintf(out, "\n");
-
-    for (i = 0; (i < NCR); i++)
+    for (int i = 0; i < NCR; ++i)
     {
-        sp_print(out, CopyrightText[i]);
+        fprintf(fp, "%s\n", CopyrightText[i]);
     }
-    for (i = 0; (i < NLICENSE); i++)
+    fprintf(fp, "\n");
+    for (int i = 0; i < NLICENSE; ++i)
     {
-        sp_print(out, LicenseText[i]);
+        fprintf(fp, "%s\n", LicenseText[i]);
     }
 }
 
@@ -711,19 +675,30 @@ void printBinaryInformation(FILE *fp, const ProgramInfo &programInfo,
     {
         fprintf(fp, "%sCreated by:%s\n", prefix, suffix);
     }
-    fprintf(fp, "%sGROMACS:    %s, %s%s%s\n", prefix, name.c_str(),
-            GromacsVersion(), precisionString, suffix);
-    fprintf(fp, "%sExecutable: %s%s\n", prefix,
-            programInfo.programNameWithPath().c_str(), suffix);
-    fprintf(fp, "%sCommand line:%s\n%s  %s%s\n",
-            prefix, suffix, prefix, programInfo.commandLine().c_str(), suffix);
     if (settings.bCopyright_)
     {
         GMX_RELEASE_ASSERT(prefix[0] == '\0' && suffix[0] == '\0',
                            "Prefix/suffix not supported with copyright");
+        // This line is printed again after the copyright notice to make it
+        // appear together with all the other information, so that it is not
+        // necessary to read stuff above the copyright notice.
+        // The line above the copyright notice puts the copyright notice is
+        // context, though.
+        // TODO: It would be nice to know here whether we are really running a
+        // Gromacs binary or some other binary that is calling Gromacs; we
+        // could then print "%s is part of GROMACS" or some alternative text.
+        fprintf(fp, "%sGROMACS:    %s, %s%s%s\n", prefix, name.c_str(),
+                GromacsVersion(), precisionString, suffix);
+        fprintf(fp, "\n");
+        printCopyright(fp);
         fprintf(fp, "\n");
-        CopyRight(fp);
     }
+    fprintf(fp, "%sGROMACS:    %s, %s%s%s\n", prefix, name.c_str(),
+            GromacsVersion(), precisionString, suffix);
+    fprintf(fp, "%sExecutable: %s%s\n", prefix,
+            programInfo.programNameWithPath().c_str(), suffix);
+    fprintf(fp, "%sCommand line:%s\n%s  %s%s\n",
+            prefix, suffix, prefix, programInfo.commandLine().c_str(), suffix);
     if (settings.bExtendedInfo_)
     {
         GMX_RELEASE_ASSERT(prefix[0] == '\0' && suffix[0] == '\0',
similarity index 99%
rename from src/gromacs/gmxlib/futil.c
rename to src/gromacs/gmxlib/futil.cpp
index befa0679a8a676084e9c3fdb2a7a97b25f6cd9dd..c1303f43adad3a3d5273bf4dc10a807a9ddf08e3 100644 (file)
@@ -486,8 +486,7 @@ gmx_bool make_backup(const char * name)
         env = getenv("GMX_MAXBACKUP");
         if (env != NULL)
         {
-            count_max = 0;
-            sscanf(env, "%d", &count_max);
+            count_max = strtol(env, NULL, 10);
             if (count_max == -1)
             {
                 /* Do not make backups and possibly overwrite old files */
@@ -522,7 +521,7 @@ FILE *ffopen(const char *file, const char *mode)
     return fopen(file, mode);
 #else
     FILE    *ff = NULL;
-    char     buf[256], *bf, *bufsize = 0, *ptr;
+    char     buf[256], *bufsize = 0, *ptr;
     gmx_bool bRead;
     int      bs;
 
@@ -850,7 +849,7 @@ gmx_bool get_libdir(char *libdir)
     char     buf[GMX_BINNAME_MAX];
     char     full_path[GMX_PATH_MAX+GMX_BINNAME_MAX];
     char     system_path[GMX_PATH_MAX];
-    char    *dir, *ptr, *s, *pdum;
+    char    *dir, *ptr, *s;
     gmx_bool found = FALSE;
     int      i;
 
index bde720f9e2e25272fac877a895afde26afeb8904..4ff83bf311b06f46f57507278e27d13d6aaac554 100644 (file)
@@ -360,40 +360,6 @@ void gmx_log_close(FILE *fp)
     }
 }
 
-static void comm_args(const t_commrec *cr, int *argc, char ***argv)
-{
-    int i, len;
-
-    if (PAR(cr))
-    {
-        gmx_bcast(sizeof(*argc), argc, cr);
-    }
-
-    if (!MASTER(cr))
-    {
-        snew(*argv, *argc+1);
-    }
-    if (debug)
-    {
-        fprintf(debug, "NODEID=%d argc=%d\n", cr->nodeid, *argc);
-    }
-    for (i = 0; (i < *argc); i++)
-    {
-        if (MASTER(cr))
-        {
-            len = strlen((*argv)[i])+1;
-        }
-        gmx_bcast(sizeof(len), &len, cr);
-        if (!MASTER(cr))
-        {
-            snew((*argv)[i], len);
-        }
-        /*gmx_bcast(len*sizeof((*argv)[i][0]),(*argv)[i],cr);*/
-        gmx_bcast(len*sizeof(char), (*argv)[i], cr);
-    }
-    debug_gmx();
-}
-
 void init_multisystem(t_commrec *cr, int nsim, char **multidirs,
                       int nfile, const t_filenm fnm[], gmx_bool bParFn)
 {
@@ -507,16 +473,19 @@ void init_multisystem(t_commrec *cr, int nsim, char **multidirs,
     }
 }
 
-t_commrec *init_par(int gmx_unused *argc, char ***argv_ptr)
+t_commrec *init_par()
 {
     t_commrec    *cr;
 
     snew(cr, 1);
 
 #if defined GMX_MPI && !defined GMX_THREAD_MPI
-    char **argv = argv_ptr ? *argv_ptr : NULL;
-    cr->sim_nodeid = gmx_setup(argc, argv, &cr->nnodes);
-
+    if (!gmx_mpi_initialized())
+    {
+        gmx_comm("MPI has not been initialized properly");
+    }
+    cr->nnodes     = gmx_node_num();
+    cr->sim_nodeid = gmx_node_rank();
     if (!PAR(cr) && (cr->sim_nodeid != 0))
     {
         gmx_comm("(!PAR(cr) && (cr->sim_nodeid != 0))");
@@ -536,14 +505,6 @@ t_commrec *init_par(int gmx_unused *argc, char ***argv_ptr)
 
     cr->duty = (DUTY_PP | DUTY_PME);
 
-    /* Communicate arguments if parallel */
-#ifndef GMX_THREAD_MPI
-    if (PAR(cr))
-    {
-        comm_args(cr, argc, argv_ptr);
-    }
-#endif /* GMX_THREAD_MPI */
-
 #ifdef GMX_MPI
 #if !defined(GMX_THREAD_MPI) && !defined(MPI_IN_PLACE_EXISTS)
     /* initialize the MPI_IN_PLACE replacement buffers */
index fbc746290f65639245a9d53d02447b7d9a9ab544..2ccfdb3df274733668c8f194be69c573912ea572 100644 (file)
@@ -64,7 +64,7 @@ gmx_bool gmx_mpi_initialized(void)
 #endif
 }
 
-int gmx_setup(int gmx_unused *argc, char gmx_unused **argv, int *nnodes)
+int gmx_setup(int gmx_unused *argc, char gmx_unused ***argv, int *nnodes)
 {
 #ifndef GMX_MPI
     gmx_call("gmx_setup");
@@ -80,9 +80,9 @@ int gmx_setup(int gmx_unused *argc, char gmx_unused **argv, int *nnodes)
     /* Call the MPI routines */
 #ifdef GMX_LIB_MPI
 #ifdef GMX_FAHCORE
-    (void) fah_MPI_Init(argc, &argv);
+    (void) fah_MPI_Init(argc, argv);
 #else
-    (void) MPI_Init(argc, &argv);
+    (void) MPI_Init(argc, argv);
 #endif
 #endif
     (void) MPI_Comm_size( MPI_COMM_WORLD, &mpi_num_nodes );
index ac75c8ec19bb0895e56984442e3ca5e2a4684f38..54dbf0094eb7b1277ba0f04ac9ed9885474e52b0 100644 (file)
@@ -41,7 +41,6 @@
 #include <cmath>
 #include <cstdlib>
 
-#include "copyrite.h"
 #include "sysstuff.h"
 #include "macros.h"
 #include "string2.h"
@@ -486,8 +485,7 @@ void parse_common_args(int *argc, char *argv[], unsigned long Flags,
                        int nbugs, const char **bugs,
                        output_env_t *oenv)
 {
-    gmx_bool    bHelp    = FALSE, bHidden  = FALSE;
-    gmx_bool    bQuiet   = FALSE, bVerbose = FALSE, bVersion = FALSE;
+    gmx_bool    bHelp    = FALSE, bHidden = FALSE, bVerbose = FALSE;
     const char *manstr[] = {
         NULL, "no", "html", "tex", "nroff", "ascii",
         "completion", "py", "xml", "wiki", NULL
@@ -551,14 +549,10 @@ void parse_common_args(int *argc, char *argv[], unsigned long Flags,
     t_pargs  pca_pa[] = {
         { "-h",    FALSE, etBOOL, {&bHelp},
           "Print help info and quit" },
-        { "-version",  FALSE, etBOOL, {&bVersion},
-          "Print version info and quit" },
         { "-verbose",  FALSE, etBOOL, {&bVerbose},
           "HIDDENShow options during normal run" },
         { "-hidden", FALSE, etBOOL, {&bHidden},
           "HIDDENPrint hidden options" },
-        { "-quiet", FALSE, etBOOL, {&bQuiet},
-          "HIDDENDo not print help info" },
         { "-man",  FALSE, etENUM,  {manstr},
           "HIDDENWrite manual and quit" },
         { "-debug", FALSE, etINT, {&debug_level},
@@ -573,9 +567,6 @@ void parse_common_args(int *argc, char *argv[], unsigned long Flags,
     // The FF macro returns whether or not the bit is set
 #define FF(arg) ((Flags & arg) == arg)
 
-    // Ensure that the program info is initialized; if already done, returns
-    // the already initialized object.
-    const gmx::ProgramInfo &programInfo = gmx::ProgramInfo::init(*argc, argv);
     /* Check for double arguments */
     for (i = 1; (i < *argc); i++)
     {
@@ -693,14 +684,6 @@ void parse_common_args(int *argc, char *argv[], unsigned long Flags,
     output_env_init(oenv, *argc, argv, (time_unit_t)nenum(time_units), bView,
                     (xvg_format_t)nenum(xvg_format), 0, debug_level);
 
-    if (!FF(PCA_QUIET) && FF(PCA_STANDALONE) && (!bQuiet || bVersion))
-    {
-        gmx::BinaryInformationSettings settings;
-        settings.extendedInfo(bVersion);
-        gmx::printBinaryInformation(bVersion ? stdout : stderr,
-                                    programInfo, settings);
-    }
-
     if (FF(PCA_CAN_SET_DEFFNM) && (deffnm != NULL))
     {
         set_default_file_name(deffnm);
@@ -741,7 +724,7 @@ void parse_common_args(int *argc, char *argv[], unsigned long Flags,
         all_pa[i].desc = mk_desc(&(all_pa[i]), output_env_get_time_unit(*oenv));
     }
 
-    bExit = bHelp || bVersion || (strcmp(manstr[0], "no") != 0);
+    bExit = bHelp || (strcmp(manstr[0], "no") != 0);
 
 #if (defined __sgi && USE_SGI_FPE)
     doexceptions();
@@ -776,7 +759,7 @@ void parse_common_args(int *argc, char *argv[], unsigned long Flags,
 #endif
 #endif
 
-    if (!(FF(PCA_QUIET) || bQuiet))
+    if (!(FF(PCA_QUIET)))
     {
         if (bHelp)
         {
index 5c3a1bef1c9c7025626b57dd27de54c0d5b4be0f..e18b161522ec6c41bf6b2e62f5ac2857d23d9eec 100644 (file)
@@ -870,17 +870,42 @@ void free_t_atoms(t_atoms *atoms, gmx_bool bFreeNames)
             }
         }
     }
+    if (bFreeNames && atoms->atomtype != NULL)
+    {
+        for (i = 0; i < atoms->nr; i++)
+        {
+            if (atoms->atomtype[i] != NULL)
+            {
+                sfree(*atoms->atomtype[i]);
+                *atoms->atomtype[i] = NULL;
+            }
+        }
+    }
+    if (bFreeNames && atoms->atomtypeB != NULL)
+    {
+        for (i = 0; i < atoms->nr; i++)
+        {
+            if (atoms->atomtypeB[i] != NULL)
+            {
+                sfree(*atoms->atomtypeB[i]);
+                *atoms->atomtypeB[i] = NULL;
+            }
+        }
+    }
     sfree(atoms->atomname);
-    /* Do we need to free atomtype and atomtypeB as well ? */
+    sfree(atoms->atomtype);
+    sfree(atoms->atomtypeB);
     sfree(atoms->resinfo);
     sfree(atoms->atom);
     sfree(atoms->pdbinfo);
-    atoms->nr       = 0;
-    atoms->nres     = 0;
-    atoms->atomname = NULL;
-    atoms->resinfo  = NULL;
-    atoms->atom     = NULL;
-    atoms->pdbinfo  = NULL;
+    atoms->nr        = 0;
+    atoms->nres      = 0;
+    atoms->atomname  = NULL;
+    atoms->atomtype  = NULL;
+    atoms->atomtypeB = NULL;
+    atoms->resinfo   = NULL;
+    atoms->atom      = NULL;
+    atoms->pdbinfo   = NULL;
 }
 
 real max_cutoff(real cutoff1, real cutoff2)
similarity index 99%
rename from src/gromacs/gmxpreprocess/fflibutil.c
rename to src/gromacs/gmxpreprocess/fflibutil.cpp
index bd34581a9ba67bb848e71e62c9fecfc5db9cba6a..e38ecbb533425aa2104cf7d030b83bb72da54bb6 100644 (file)
@@ -143,15 +143,12 @@ static int low_fflib_search_file_end(const char *ffdir,
                                      char     ***filenames,
                                      char     ***filenames_short)
 {
-    char           *ret = NULL;
     char           *lib, *dir;
-    char            buf[1024];
     char           *libpath;
     gmx_bool        env_is_set;
     int             len_fe, len_name;
     char          **fns, **fns_short;
     char            dir_print[GMX_PATH_MAX];
-    char           *pdum;
     char           *s, fn_dir[GMX_PATH_MAX];
     gmx_directory_t dirhandle;
     char            nextname[STRLEN];
index f52f289d6e924d010df91e64661c3f130eb36b88..d932ce85061f90a58080832e44157075ba827773 100644 (file)
@@ -1921,7 +1921,6 @@ gmx_mm256_sincos_pd(__m256d  x,
 
     const __m256d signmask    = _mm256_castsi256_pd( _mm256_set_epi32(0x7FFFFFFF, 0xFFFFFFFF, 0x7FFFFFFF, 0xFFFFFFFF,
                                                                       0x7FFFFFFF, 0xFFFFFFFF, 0x7FFFFFFF, 0xFFFFFFFF) );
-    const __m128i signbit_epi32  = _mm_set1_epi32(0x80000000);
 
     const __m256d tabscale      = _mm256_set1_pd(32.0/M_PI);
     const __m256d invtabscale0  = _mm256_set1_pd(9.81747508049011230469e-02);
@@ -1944,12 +1943,11 @@ gmx_mm256_sincos_pd(__m256d  x,
     __m128i       tabidx, corridx;
     __m256d       xabs, z, z2, polySin, polyCos;
     __m256d       xpoint;
-    __m256d       t1, t2, t3, t4;
+    __m256d       t1, t2;
 
     __m256d       sinpoint, cospoint;
     __m256d       xsign, ssign, csign;
     __m128i       imask, sswapsign, cswapsign;
-    __m256d       minusone;
 
     xsign    = _mm256_andnot_pd(signmask, x);
     xabs     = _mm256_and_pd(x, signmask);
@@ -2075,7 +2073,6 @@ gmx_mm_sincos_pd(__m128d  x,
 #endif
 
     const __m128d signmask       = gmx_mm_castsi128_pd( _mm_set_epi32(0x7FFFFFFF, 0xFFFFFFFF, 0x7FFFFFFF, 0xFFFFFFFF) );
-    const __m128i signbit_epi32  = _mm_set1_epi32(0x80000000);
 
     const __m128d tabscale      = _mm_set1_pd(32.0/M_PI);
     const __m128d invtabscale0  = _mm_set1_pd(9.81747508049011230469e-02);
@@ -2103,7 +2100,6 @@ gmx_mm_sincos_pd(__m128d  x,
     __m128d       sinpoint, cospoint;
     __m128d       xsign, ssign, csign;
     __m128i       imask, sswapsign, cswapsign;
-    __m128d       minusone;
 
     xsign    = _mm_andnot_pd(signmask, x);
     xabs     = _mm_and_pd(x, signmask);
@@ -2250,7 +2246,6 @@ gmx_mm256_asin_pd(__m256d x)
     const __m256d limit1    = _mm256_set1_pd(0.625);
     const __m256d limit2    = _mm256_set1_pd(1e-8);
     const __m256d one       = _mm256_set1_pd(1.0);
-    const __m256d halfpi    = _mm256_set1_pd(M_PI/2.0);
     const __m256d quarterpi = _mm256_set1_pd(M_PI/4.0);
     const __m256d morebits  = _mm256_set1_pd(6.123233995736765886130e-17);
 
@@ -2281,7 +2276,7 @@ gmx_mm256_asin_pd(__m256d x)
     __m256d       sign;
     __m256d       mask;
     __m256d       xabs;
-    __m256d       zz, ww, z, q, w, y, zz2, ww2;
+    __m256d       zz, ww, z, q, w, zz2, ww2;
     __m256d       PA, PB;
     __m256d       QA, QB;
     __m256d       RA, RB;
@@ -2377,7 +2372,6 @@ gmx_mm_asin_pd(__m128d x)
     const __m128d limit1    = _mm_set1_pd(0.625);
     const __m128d limit2    = _mm_set1_pd(1e-8);
     const __m128d one       = _mm_set1_pd(1.0);
-    const __m128d halfpi    = _mm_set1_pd(M_PI/2.0);
     const __m128d quarterpi = _mm_set1_pd(M_PI/4.0);
     const __m128d morebits  = _mm_set1_pd(6.123233995736765886130e-17);
 
@@ -2408,7 +2402,7 @@ gmx_mm_asin_pd(__m128d x)
     __m128d       sign;
     __m128d       mask;
     __m128d       xabs;
-    __m128d       zz, ww, z, q, w, y, zz2, ww2;
+    __m128d       zz, ww, z, q, w, zz2, ww2;
     __m128d       PA, PB;
     __m128d       QA, QB;
     __m128d       RA, RB;
@@ -2500,11 +2494,8 @@ gmx_mm_asin_pd(__m128d x)
 static __m256d
 gmx_mm256_acos_pd(__m256d x)
 {
-    const __m256d signmask  = _mm256_castsi256_pd( _mm256_set_epi32(0x7FFFFFFF, 0xFFFFFFFF, 0x7FFFFFFF, 0xFFFFFFFF,
-                                                                    0x7FFFFFFF, 0xFFFFFFFF, 0x7FFFFFFF, 0xFFFFFFFF) );
     const __m256d one        = _mm256_set1_pd(1.0);
     const __m256d half       = _mm256_set1_pd(0.5);
-    const __m256d pi         = _mm256_set1_pd(M_PI);
     const __m256d quarterpi0 = _mm256_set1_pd(7.85398163397448309616e-1);
     const __m256d quarterpi1 = _mm256_set1_pd(6.123233995736765886130e-17);
 
@@ -2534,10 +2525,8 @@ gmx_mm256_acos_pd(__m256d x)
 static __m128d
 gmx_mm_acos_pd(__m128d x)
 {
-    const __m128d signmask   = gmx_mm_castsi128_pd( _mm_set_epi32(0x7FFFFFFF, 0xFFFFFFFF, 0x7FFFFFFF, 0xFFFFFFFF) );
     const __m128d one        = _mm_set1_pd(1.0);
     const __m128d half       = _mm_set1_pd(0.5);
-    const __m128d pi         = _mm_set1_pd(M_PI);
     const __m128d quarterpi0 = _mm_set1_pd(7.85398163397448309616e-1);
     const __m128d quarterpi1 = _mm_set1_pd(6.123233995736765886130e-17);
 
index 0e92aecfe8fa063452ec7cf553fde1b93a6822bd..49aa6eae6b6b88e6fb61528504ea46ab21877f85 100644 (file)
@@ -153,13 +153,13 @@ gmx_mm256_log_ps(__m256 x)
     const __m256  CE_0        = _mm256_set1_ps(1.3429983063133937f);
     const __m256  CE_1        = _mm256_set1_ps(1.807420826584643f);
 
-    __m256        fexp, fexp1;
+    __m256        fexp;
     __m256i       iexp;
     __m128i       iexp128a, iexp128b;
     __m256        mask;
     __m256i       imask;
     __m128i       imask128a, imask128b;
-    __m256        x1, x2;
+    __m256        x2;
     __m256        y;
     __m256        pA, pB, pC, pD, pE, tB, tC, tD, tE;
 
@@ -251,10 +251,10 @@ gmx_mm_log_ps(__m128 x)
     const __m128  CE_0        = _mm_set1_ps(1.3429983063133937f);
     const __m128  CE_1        = _mm_set1_ps(1.807420826584643f);
 
-    __m128        fexp, fexp1;
+    __m128        fexp;
     __m128i       iexp;
     __m128        mask;
-    __m128        x1, x2;
+    __m128        x2;
     __m128        y;
     __m128        pA, pB, pC, pD, pE, tB, tC, tD, tE;
 
index bfc001adc0c4f331844ce55308b4948733fc6b5f..6a33f7efd96fc7d748a9f8628e43d80b70e8975e 100644 (file)
@@ -1053,7 +1053,6 @@ gmx_mm_sincos_pd(__m128d  x,
 #endif
 
     const __m128d signmask       = gmx_mm_castsi128_pd( _mm_set_epi32(0x7FFFFFFF, 0xFFFFFFFF, 0x7FFFFFFF, 0xFFFFFFFF) );
-    const __m128i signbit_epi32  = _mm_set1_epi32(0x80000000);
 
     const __m128d tabscale      = _mm_set1_pd(32.0/M_PI);
     const __m128d invtabscale0  = _mm_set1_pd(9.81747508049011230469e-02);
@@ -1081,7 +1080,6 @@ gmx_mm_sincos_pd(__m128d  x,
     __m128d       sinpoint, cospoint;
     __m128d       xsign, ssign, csign;
     __m128i       imask, sswapsign, cswapsign;
-    __m128d       minusone;
 
     xsign    = _mm_andnot_pd(signmask, x);
     xabs     = _mm_and_pd(x, signmask);
@@ -1199,7 +1197,6 @@ gmx_mm_asin_pd(__m128d x)
     const __m128d limit1    = _mm_set1_pd(0.625);
     const __m128d limit2    = _mm_set1_pd(1e-8);
     const __m128d one       = _mm_set1_pd(1.0);
-    const __m128d halfpi    = _mm_set1_pd(M_PI/2.0);
     const __m128d quarterpi = _mm_set1_pd(M_PI/4.0);
     const __m128d morebits  = _mm_set1_pd(6.123233995736765886130e-17);
 
@@ -1230,7 +1227,7 @@ gmx_mm_asin_pd(__m128d x)
     __m128d       sign;
     __m128d       mask;
     __m128d       xabs;
-    __m128d       zz, ww, z, q, w, y, zz2, ww2;
+    __m128d       zz, ww, z, q, w, zz2, ww2;
     __m128d       PA, PB;
     __m128d       QA, QB;
     __m128d       RA, RB;
@@ -1322,10 +1319,8 @@ gmx_mm_asin_pd(__m128d x)
 static __m128d
 gmx_mm_acos_pd(__m128d x)
 {
-    const __m128d signmask   = gmx_mm_castsi128_pd( _mm_set_epi32(0x7FFFFFFF, 0xFFFFFFFF, 0x7FFFFFFF, 0xFFFFFFFF) );
     const __m128d one        = _mm_set1_pd(1.0);
     const __m128d half       = _mm_set1_pd(0.5);
-    const __m128d pi         = _mm_set1_pd(M_PI);
     const __m128d quarterpi0 = _mm_set1_pd(7.85398163397448309616e-1);
     const __m128d quarterpi1 = _mm_set1_pd(6.123233995736765886130e-17);
 
index 885a2ef082e8fd7e454bcbf0e55b3e9979c9367c..a57cb1092f1f871f3146c3a2915ba892d182707c 100644 (file)
@@ -109,10 +109,10 @@ gmx_mm_log_ps(__m128 x)
     const __m128  CE_0        = _mm_set1_ps(1.3429983063133937f);
     const __m128  CE_1        = _mm_set1_ps(1.807420826584643f);
 
-    __m128        fexp, fexp1;
+    __m128        fexp;
     __m128i       iexp;
     __m128        mask;
-    __m128        x1, x2;
+    __m128        x2;
     __m128        y;
     __m128        pA, pB, pC, pD, pE, tB, tC, tD, tE;
 
index ba2a550611bf442c72887a36f39b2209640308a7..4724aa611fcc4725d477243a194042d4aacdc62e 100644 (file)
@@ -79,12 +79,9 @@ void init_multisystem(t_commrec *cr, int nsim, char **multidirs,
  * If bParFn is set, the nodeid is appended to the tpx and each output file.
  */
 
-t_commrec *init_par(int *argc, char ***argv_ptr);
+t_commrec *init_par(void);
 /* Initiate the parallel computer. Return the communication record
- * (see network.h). The command line arguments are communicated so that they can be
- * parsed on each processor.
- * Arguments are the number of command line arguments, and a pointer to the
- * array of argument strings. Both are allowed to be NULL.
+ * (see network.h).
  */
 
 t_commrec *init_par_threads(const t_commrec *cro);
index 921c7f41c4995d2a37626664280224d8c5080f5a..727f6f0998480b3dbb7c1a1f3ff821c71bae18d1 100644 (file)
@@ -53,7 +53,7 @@
 extern "C" {
 #endif
 
-int gmx_setup(int *argc, char **argv, int *nnodes);
+int gmx_setup(int *argc, char ***argv, int *nnodes);
 /* Initializes the parallel communication, return the ID of the node */
 
 int gmx_node_num(void);
index 0751fec668f67185787c3046c1af838c04069710..430a266f98368aef90fb0f22e3a2e1eb86efca53 100644 (file)
@@ -252,8 +252,6 @@ t_topology *read_top(const char *fn, int *ePBC);
 /* set time unit for output */
 #define PCA_KEEP_ARGS      (1<<8)
 /* keep parsed args in argv (doesn't make sense without NOEXIT_ON_ARGS) */
-#define PCA_STANDALONE     (1<<9)
-/* add options for standalone programs and print a header */
 #define PCA_CAN_SET_DEFFNM (1<<10)
 /* does something for non-master mdrun nodes */
 #define PCA_NOEXIT_ON_ARGS (1<<11)
index 37fa948faf5a085c357dab4b1cd482b7f6f80415..e9491b838b574c00d2db62e80427602dbb5a04aa 100644 (file)
@@ -188,10 +188,6 @@ t_mdebin *init_mdebin(ener_file_t       fp_ene,
         md->bEInd[i] = FALSE;
     }
 
-    /* Even though the OpenMM build has moved to contrib, it's not
-     * practical to move/remove this code fragment, because of the
-     * fundamental mess that is the GROMACS library structure. */
-#ifndef GMX_OPENMM
     for (i = 0; i < F_NRE; i++)
     {
         md->bEner[i] = FALSE;
@@ -303,13 +299,6 @@ t_mdebin *init_mdebin(ener_file_t       fp_ene,
             md->bEner[i] = (gmx_mtop_ftype_count(mtop, i) > 0);
         }
     }
-#else
-    /* OpenMM always produces only the following 4 energy terms */
-    md->bEner[F_EPOT] = TRUE;
-    md->bEner[F_EKIN] = TRUE;
-    md->bEner[F_ETOT] = TRUE;
-    md->bEner[F_TEMP] = TRUE;
-#endif
 
     /* for adress simulations, most energy terms are not meaningfull, and thus disabled*/
     if (ir->bAdress && !debug)
index 6c2b258e47db58ad8d7ad5b3fe58cb684fbba268..de0acc0efc313987134ad95fc6e3bb52af2e905e 100644 (file)
@@ -52,7 +52,7 @@
 const unsigned supercl_interaction_mask = ((1U << NCL_PER_SUPERCL) - 1U);
 
 /*! Interpolate Ewald coulomb force using the table through the tex_nbfp texture.
- *  Original idea: OpenMM
+ *  Original idea: from the OpenMM project
  */
 static inline __device__
 float interpolate_coulomb_force_r(float r, float scale)
index 3c297c7f70e1edff7f131f26d41c575e23505c3a..d92ce70c2502878f6ba5dc36c3e1d13efd6b56ec 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2010,2011,2012, by the GROMACS development team, led by
+ * Copyright (c) 2010,2011,2012,2013, 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.
@@ -229,16 +229,25 @@ void OptionsAssigner::startSubSection(const char *name)
 }
 
 void OptionsAssigner::startOption(const char *name)
+{
+    if (!tryStartOption(name))
+    {
+        GMX_THROW(InvalidInputError("Unknown option"));
+    }
+}
+
+bool OptionsAssigner::tryStartOption(const char *name)
 {
     GMX_RELEASE_ASSERT(impl_->currentOption_ == NULL, "finishOption() not called");
     AbstractOptionStorage *option = impl_->findOption(name);
     if (option == NULL)
     {
-        GMX_THROW(InvalidInputError("Unknown option"));
+        return false;
     }
     option->startSet();
     impl_->currentOption_     = option;
     impl_->currentValueCount_ = 0;
+    return true;
 }
 
 void OptionsAssigner::appendValue(const std::string &value)
index 506ba395cfa8766495f2d3710ec4bd62046ead46..19ee5fcfae7fd9129543fb3063a319021677d1ff 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2010,2011,2012, by the GROMACS development team, led by
+ * Copyright (c) 2010,2011,2012,2013, 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.
@@ -127,13 +127,13 @@ class OptionsAssigner
         void setNoStrictSectioning(bool bEnabled);
 
         /*! \brief
-         * Start assigning values.
+         * Starts assigning values.
          *
          * Does not throw.
          */
         void start();
         /*! \brief
-         * Start assigning values to options in a subsection.
+         * Starts assigning values to options in a subsection.
          *
          * \param[in] name  Name of the subsection to start assigning to.
          * \throws InvalidInputError if such a subsection is not found.
@@ -142,15 +142,22 @@ class OptionsAssigner
          */
         void startSubSection(const char *name);
         /*! \brief
-         * Start assigning values for an option.
+         * Starts assigning values for an option.
          *
          * \param[in] name  Name of the option to start assigning to.
          * \throws InvalidInputError if such an option is not found, or if the
          *      option is specified more than once but doesn't support it.
-         *
-         * Strong exception safety guarantee.
          */
         void startOption(const char *name);
+        /*! \brief
+         * Starts assigning values for an option.
+         *
+         * \param[in] name  Name of the option to start assigning to.
+         * \returns   true if \p name is a valid option name.
+         * \throws InvalidInputError if the option is specified more than once
+         *      but doesn't support it.
+         */
+        bool tryStartOption(const char *name);
         /*! \brief
          * Appends a value to the value list of the current option.
          *
index 819340f2a8f35a5259d091b32d15d3c4f3b0cd67..ad640ae8173150bd91a0925c9076153f7bd74973 100644 (file)
@@ -138,22 +138,22 @@ gmx_ana_indexgrps_init(gmx_ana_indexgrps_t **g, t_topology *top,
     }
     catch (...)
     {
-        done_blocka(block);
-        sfree(block);
         for (int i = 0; i < block->nr; ++i)
         {
             sfree(names[i]);
         }
         sfree(names);
+        done_blocka(block);
+        sfree(block);
         throw;
     }
-    done_blocka(block);
-    sfree(block);
     for (int i = 0; i < block->nr; ++i)
     {
         sfree(names[i]);
     }
     sfree(names);
+    done_blocka(block);
+    sfree(block);
 }
 
 /*!
index 9f627a93983d0692ed8efc3f34b34cb02212d3f6..1aa00baa5fd9bbd0b12342007171b75c5f14b295 100644 (file)
@@ -583,16 +583,16 @@ static const yytype_int8 yyrhs[] =
 /* YYRLINE[YYN] -- source line where rule number YYN was defined.  */
 static const yytype_uint16 yyrline[] =
 {
-       0,   199,   199,   204,   215,   216,   238,   244,   250,   262,
-     275,   281,   288,   295,   302,   313,   322,   327,   338,   339,
-     346,   347,   361,   362,   366,   367,   370,   371,   374,   375,
-     383,   394,   405,   416,   420,   431,   439,   449,   450,   455,
-     456,   457,   461,   469,   477,   485,   496,   511,   522,   536,
-     544,   555,   561,   567,   573,   579,   585,   591,   598,   609,
-     624,   633,   637,   647,   661,   669,   677,   690,   692,   698,
-     703,   714,   723,   724,   729,   734,   742,   753,   754,   758,
-     764,   772,   782,   788,   794,   800,   806,   810,   816,   822,
-     829,   833,   839,   845
+       0,   199,   199,   204,   215,   216,   238,   244,   250,   261,
+     273,   279,   286,   293,   300,   311,   320,   325,   336,   337,
+     344,   345,   359,   360,   364,   365,   368,   369,   372,   373,
+     381,   392,   403,   414,   418,   429,   436,   445,   446,   451,
+     452,   453,   457,   465,   473,   481,   492,   507,   518,   532,
+     540,   551,   557,   563,   569,   575,   581,   587,   594,   605,
+     620,   629,   633,   643,   657,   665,   673,   686,   688,   694,
+     699,   710,   719,   720,   725,   730,   738,   749,   750,   754,
+     760,   768,   778,   784,   790,   796,   802,   806,   812,   818,
+     825,   829,   835,   841
 };
 #endif
 
@@ -1993,35 +1993,33 @@ yyreduce:
                  BEGIN_ACTION;
                  SelectionTreeElementPointer s
                         = _gmx_sel_init_group_by_id((yyvsp[(1) - (1)].i), scanner);
-                 if (!s) YYERROR;
                  SelectionTreeElementPointer p
                         = _gmx_sel_init_position(s, NULL, scanner);
                  if (!p) YYERROR;
-                 set((yyval.sel), _gmx_sel_init_selection(s->name().c_str(), p, scanner));
+                 set((yyval.sel), _gmx_sel_init_selection(NULL, p, scanner));
                  END_ACTION;
              }
     break;
 
   case 9:
 /* Line 1787 of yacc.c  */
-#line 263 "parser.y"
+#line 262 "parser.y"
     {
                  BEGIN_ACTION;
                  scoped_ptr_sfree nameGuard((yyvsp[(1) - (1)].str));
                  SelectionTreeElementPointer s
                         = _gmx_sel_init_group_by_name((yyvsp[(1) - (1)].str), scanner);
-                 if (!s) YYERROR;
                  SelectionTreeElementPointer p
                         = _gmx_sel_init_position(s, NULL, scanner);
                  if (!p) YYERROR;
-                 set((yyval.sel), _gmx_sel_init_selection(s->name().c_str(), p, scanner));
+                 set((yyval.sel), _gmx_sel_init_selection(NULL, p, scanner));
                  END_ACTION;
              }
     break;
 
   case 10:
 /* Line 1787 of yacc.c  */
-#line 276 "parser.y"
+#line 274 "parser.y"
     {
                  BEGIN_ACTION;
                  set((yyval.sel), _gmx_sel_init_selection(NULL, get((yyvsp[(1) - (1)].sel)), scanner));
@@ -2031,7 +2029,7 @@ yyreduce:
 
   case 11:
 /* Line 1787 of yacc.c  */
-#line 282 "parser.y"
+#line 280 "parser.y"
     {
                  BEGIN_ACTION;
                  scoped_ptr_sfree nameGuard((yyvsp[(1) - (2)].str));
@@ -2042,7 +2040,7 @@ yyreduce:
 
   case 12:
 /* Line 1787 of yacc.c  */
-#line 289 "parser.y"
+#line 287 "parser.y"
     {
                  BEGIN_ACTION;
                  scoped_ptr_sfree nameGuard((yyvsp[(1) - (3)].str));
@@ -2053,7 +2051,7 @@ yyreduce:
 
   case 13:
 /* Line 1787 of yacc.c  */
-#line 296 "parser.y"
+#line 294 "parser.y"
     {
                  BEGIN_ACTION;
                  scoped_ptr_sfree nameGuard((yyvsp[(1) - (3)].str));
@@ -2064,7 +2062,7 @@ yyreduce:
 
   case 14:
 /* Line 1787 of yacc.c  */
-#line 303 "parser.y"
+#line 301 "parser.y"
     {
                  BEGIN_ACTION;
                  scoped_ptr_sfree nameGuard((yyvsp[(1) - (3)].str));
@@ -2075,7 +2073,7 @@ yyreduce:
 
   case 15:
 /* Line 1787 of yacc.c  */
-#line 314 "parser.y"
+#line 312 "parser.y"
     {
                  BEGIN_ACTION;
                  _gmx_sel_handle_help_cmd(get((yyvsp[(2) - (2)].vlist)), scanner);
@@ -2085,7 +2083,7 @@ yyreduce:
 
   case 16:
 /* Line 1787 of yacc.c  */
-#line 322 "parser.y"
+#line 320 "parser.y"
     {
                  BEGIN_ACTION;
                  set((yyval.vlist), SelectionParserValue::createList());
@@ -2095,7 +2093,7 @@ yyreduce:
 
   case 17:
 /* Line 1787 of yacc.c  */
-#line 328 "parser.y"
+#line 326 "parser.y"
     {
                  BEGIN_ACTION;
                  SelectionParserValueListPointer list(get((yyvsp[(1) - (2)].vlist)));
@@ -2107,13 +2105,13 @@ yyreduce:
 
   case 18:
 /* Line 1787 of yacc.c  */
-#line 338 "parser.y"
+#line 336 "parser.y"
     { (yyval.sel) = (yyvsp[(1) - (1)].sel); }
     break;
 
   case 19:
 /* Line 1787 of yacc.c  */
-#line 340 "parser.y"
+#line 338 "parser.y"
     {
                  BEGIN_ACTION;
                  set((yyval.sel), _gmx_sel_init_position(get((yyvsp[(1) - (1)].sel)), NULL, scanner));
@@ -2124,13 +2122,13 @@ yyreduce:
 
   case 20:
 /* Line 1787 of yacc.c  */
-#line 346 "parser.y"
+#line 344 "parser.y"
     { (yyval.sel) = (yyvsp[(2) - (3)].sel); }
     break;
 
   case 21:
 /* Line 1787 of yacc.c  */
-#line 348 "parser.y"
+#line 346 "parser.y"
     {
                  BEGIN_ACTION;
                  set((yyval.sel), _gmx_sel_init_modifier((yyvsp[(2) - (3)].meth), get((yyvsp[(3) - (3)].plist)), get((yyvsp[(1) - (3)].sel)), scanner));
@@ -2141,55 +2139,55 @@ yyreduce:
 
   case 22:
 /* Line 1787 of yacc.c  */
-#line 361 "parser.y"
+#line 359 "parser.y"
     { (yyval.i) = (yyvsp[(1) - (1)].i); }
     break;
 
   case 23:
 /* Line 1787 of yacc.c  */
-#line 362 "parser.y"
+#line 360 "parser.y"
     { (yyval.i) = -(yyvsp[(2) - (2)].i); }
     break;
 
   case 24:
 /* Line 1787 of yacc.c  */
-#line 366 "parser.y"
+#line 364 "parser.y"
     { (yyval.r) = (yyvsp[(1) - (1)].r); }
     break;
 
   case 25:
 /* Line 1787 of yacc.c  */
-#line 367 "parser.y"
+#line 365 "parser.y"
     { (yyval.r) = -(yyvsp[(2) - (2)].r); }
     break;
 
   case 26:
 /* Line 1787 of yacc.c  */
-#line 370 "parser.y"
+#line 368 "parser.y"
     { (yyval.r) = (yyvsp[(1) - (1)].i); }
     break;
 
   case 27:
 /* Line 1787 of yacc.c  */
-#line 371 "parser.y"
+#line 369 "parser.y"
     { (yyval.r) = (yyvsp[(1) - (1)].r); }
     break;
 
   case 28:
 /* Line 1787 of yacc.c  */
-#line 374 "parser.y"
+#line 372 "parser.y"
     { (yyval.str) = (yyvsp[(1) - (1)].str); }
     break;
 
   case 29:
 /* Line 1787 of yacc.c  */
-#line 375 "parser.y"
+#line 373 "parser.y"
     { (yyval.str) = (yyvsp[(1) - (1)].str); }
     break;
 
   case 30:
 /* Line 1787 of yacc.c  */
-#line 384 "parser.y"
+#line 382 "parser.y"
     {
                  BEGIN_ACTION;
                  SelectionTreeElementPointer arg(get((yyvsp[(2) - (2)].sel)));
@@ -2204,7 +2202,7 @@ yyreduce:
 
   case 31:
 /* Line 1787 of yacc.c  */
-#line 395 "parser.y"
+#line 393 "parser.y"
     {
                  BEGIN_ACTION;
                  SelectionTreeElementPointer arg1(get((yyvsp[(1) - (3)].sel))), arg2(get((yyvsp[(3) - (3)].sel)));
@@ -2219,7 +2217,7 @@ yyreduce:
 
   case 32:
 /* Line 1787 of yacc.c  */
-#line 406 "parser.y"
+#line 404 "parser.y"
     {
                  BEGIN_ACTION;
                  SelectionTreeElementPointer arg1(get((yyvsp[(1) - (3)].sel))), arg2(get((yyvsp[(3) - (3)].sel)));
@@ -2234,13 +2232,13 @@ yyreduce:
 
   case 33:
 /* Line 1787 of yacc.c  */
-#line 416 "parser.y"
+#line 414 "parser.y"
     { (yyval.sel) = (yyvsp[(2) - (3)].sel); }
     break;
 
   case 34:
 /* Line 1787 of yacc.c  */
-#line 421 "parser.y"
+#line 419 "parser.y"
     {
                  BEGIN_ACTION;
                  scoped_ptr_sfree opGuard((yyvsp[(2) - (3)].str));
@@ -2252,60 +2250,58 @@ yyreduce:
 
   case 35:
 /* Line 1787 of yacc.c  */
-#line 432 "parser.y"
+#line 430 "parser.y"
     {
                  BEGIN_ACTION;
                  scoped_ptr_sfree nameGuard((yyvsp[(2) - (2)].str));
                  set((yyval.sel), _gmx_sel_init_group_by_name((yyvsp[(2) - (2)].str), scanner));
-                 CHECK_SEL((yyval.sel));
                  END_ACTION;
              }
     break;
 
   case 36:
 /* Line 1787 of yacc.c  */
-#line 440 "parser.y"
+#line 437 "parser.y"
     {
                  BEGIN_ACTION;
                  set((yyval.sel), _gmx_sel_init_group_by_id((yyvsp[(2) - (2)].i), scanner));
-                 CHECK_SEL((yyval.sel));
                  END_ACTION;
              }
     break;
 
   case 37:
 /* Line 1787 of yacc.c  */
-#line 449 "parser.y"
+#line 445 "parser.y"
     { (yyval.str) = NULL; }
     break;
 
   case 38:
 /* Line 1787 of yacc.c  */
-#line 450 "parser.y"
+#line 446 "parser.y"
     { (yyval.str) = (yyvsp[(1) - (1)].str);   }
     break;
 
   case 39:
 /* Line 1787 of yacc.c  */
-#line 455 "parser.y"
+#line 451 "parser.y"
     { (yyval.smt) = gmx::eStringMatchType_RegularExpression; }
     break;
 
   case 40:
 /* Line 1787 of yacc.c  */
-#line 456 "parser.y"
+#line 452 "parser.y"
     { (yyval.smt) = gmx::eStringMatchType_Wildcard; }
     break;
 
   case 41:
 /* Line 1787 of yacc.c  */
-#line 457 "parser.y"
+#line 453 "parser.y"
     { (yyval.smt) = gmx::eStringMatchType_Exact; }
     break;
 
   case 42:
 /* Line 1787 of yacc.c  */
-#line 462 "parser.y"
+#line 458 "parser.y"
     {
                  BEGIN_ACTION;
                  scoped_ptr_sfree posmodGuard((yyvsp[(1) - (2)].str));
@@ -2317,7 +2313,7 @@ yyreduce:
 
   case 43:
 /* Line 1787 of yacc.c  */
-#line 470 "parser.y"
+#line 466 "parser.y"
     {
                  BEGIN_ACTION;
                  scoped_ptr_sfree posmodGuard((yyvsp[(1) - (3)].str));
@@ -2329,7 +2325,7 @@ yyreduce:
 
   case 44:
 /* Line 1787 of yacc.c  */
-#line 478 "parser.y"
+#line 474 "parser.y"
     {
                  BEGIN_ACTION;
                  scoped_ptr_sfree posmodGuard((yyvsp[(1) - (4)].str));
@@ -2341,7 +2337,7 @@ yyreduce:
 
   case 45:
 /* Line 1787 of yacc.c  */
-#line 486 "parser.y"
+#line 482 "parser.y"
     {
                  BEGIN_ACTION;
                  scoped_ptr_sfree posmodGuard((yyvsp[(1) - (3)].str));
@@ -2353,7 +2349,7 @@ yyreduce:
 
   case 46:
 /* Line 1787 of yacc.c  */
-#line 497 "parser.y"
+#line 493 "parser.y"
     {
                  BEGIN_ACTION;
                  scoped_ptr_sfree posmodGuard((yyvsp[(1) - (3)].str));
@@ -2365,7 +2361,7 @@ yyreduce:
 
   case 47:
 /* Line 1787 of yacc.c  */
-#line 512 "parser.y"
+#line 508 "parser.y"
     {
                  BEGIN_ACTION;
                  SelectionTreeElementPointer sel(
@@ -2380,7 +2376,7 @@ yyreduce:
 
   case 48:
 /* Line 1787 of yacc.c  */
-#line 523 "parser.y"
+#line 519 "parser.y"
     {
                  BEGIN_ACTION;
                  SelectionTreeElementPointer sel(
@@ -2395,7 +2391,7 @@ yyreduce:
 
   case 49:
 /* Line 1787 of yacc.c  */
-#line 537 "parser.y"
+#line 533 "parser.y"
     {
                  BEGIN_ACTION;
                  scoped_ptr_sfree posmodGuard((yyvsp[(1) - (2)].str));
@@ -2407,7 +2403,7 @@ yyreduce:
 
   case 50:
 /* Line 1787 of yacc.c  */
-#line 545 "parser.y"
+#line 541 "parser.y"
     {
                  BEGIN_ACTION;
                  scoped_ptr_sfree posmodGuard((yyvsp[(1) - (3)].str));
@@ -2419,7 +2415,7 @@ yyreduce:
 
   case 51:
 /* Line 1787 of yacc.c  */
-#line 556 "parser.y"
+#line 552 "parser.y"
     {
                  BEGIN_ACTION;
                  set((yyval.sel), _gmx_sel_init_arithmetic(get((yyvsp[(1) - (3)].sel)), get((yyvsp[(3) - (3)].sel)), '+', scanner));
@@ -2429,7 +2425,7 @@ yyreduce:
 
   case 52:
 /* Line 1787 of yacc.c  */
-#line 562 "parser.y"
+#line 558 "parser.y"
     {
                  BEGIN_ACTION;
                  set((yyval.sel), _gmx_sel_init_arithmetic(get((yyvsp[(1) - (3)].sel)), get((yyvsp[(3) - (3)].sel)), '-', scanner));
@@ -2439,7 +2435,7 @@ yyreduce:
 
   case 53:
 /* Line 1787 of yacc.c  */
-#line 568 "parser.y"
+#line 564 "parser.y"
     {
                  BEGIN_ACTION;
                  set((yyval.sel), _gmx_sel_init_arithmetic(get((yyvsp[(1) - (3)].sel)), get((yyvsp[(3) - (3)].sel)), '*', scanner));
@@ -2449,7 +2445,7 @@ yyreduce:
 
   case 54:
 /* Line 1787 of yacc.c  */
-#line 574 "parser.y"
+#line 570 "parser.y"
     {
                  BEGIN_ACTION;
                  set((yyval.sel), _gmx_sel_init_arithmetic(get((yyvsp[(1) - (3)].sel)), get((yyvsp[(3) - (3)].sel)), '/', scanner));
@@ -2459,7 +2455,7 @@ yyreduce:
 
   case 55:
 /* Line 1787 of yacc.c  */
-#line 580 "parser.y"
+#line 576 "parser.y"
     {
                  BEGIN_ACTION;
                  set((yyval.sel), _gmx_sel_init_arithmetic(get((yyvsp[(2) - (2)].sel)), SelectionTreeElementPointer(), '-', scanner));
@@ -2469,7 +2465,7 @@ yyreduce:
 
   case 56:
 /* Line 1787 of yacc.c  */
-#line 586 "parser.y"
+#line 582 "parser.y"
     {
                  BEGIN_ACTION;
                  set((yyval.sel), _gmx_sel_init_arithmetic(get((yyvsp[(1) - (3)].sel)), get((yyvsp[(3) - (3)].sel)), '^', scanner));
@@ -2479,13 +2475,13 @@ yyreduce:
 
   case 57:
 /* Line 1787 of yacc.c  */
-#line 591 "parser.y"
+#line 587 "parser.y"
     { (yyval.sel) = (yyvsp[(2) - (3)].sel); }
     break;
 
   case 58:
 /* Line 1787 of yacc.c  */
-#line 599 "parser.y"
+#line 595 "parser.y"
     {
                  BEGIN_ACTION;
                  SelectionTreeElementPointer sel(
@@ -2500,7 +2496,7 @@ yyreduce:
 
   case 59:
 /* Line 1787 of yacc.c  */
-#line 610 "parser.y"
+#line 606 "parser.y"
     {
                  BEGIN_ACTION;
                  scoped_ptr_sfree posmodGuard((yyvsp[(1) - (2)].str));
@@ -2512,7 +2508,7 @@ yyreduce:
 
   case 60:
 /* Line 1787 of yacc.c  */
-#line 625 "parser.y"
+#line 621 "parser.y"
     {
                  BEGIN_ACTION;
                  set((yyval.sel), _gmx_sel_init_const_position((yyvsp[(2) - (7)].r), (yyvsp[(4) - (7)].r), (yyvsp[(6) - (7)].r)));
@@ -2522,13 +2518,13 @@ yyreduce:
 
   case 61:
 /* Line 1787 of yacc.c  */
-#line 633 "parser.y"
+#line 629 "parser.y"
     { (yyval.sel) = (yyvsp[(2) - (3)].sel); }
     break;
 
   case 62:
 /* Line 1787 of yacc.c  */
-#line 638 "parser.y"
+#line 634 "parser.y"
     {
                  BEGIN_ACTION;
                  set((yyval.sel), _gmx_sel_init_method((yyvsp[(1) - (2)].meth), get((yyvsp[(2) - (2)].plist)), NULL, scanner));
@@ -2539,7 +2535,7 @@ yyreduce:
 
   case 63:
 /* Line 1787 of yacc.c  */
-#line 648 "parser.y"
+#line 644 "parser.y"
     {
                  BEGIN_ACTION;
                  scoped_ptr_sfree keywordGuard((yyvsp[(1) - (3)].str));
@@ -2551,7 +2547,7 @@ yyreduce:
 
   case 64:
 /* Line 1787 of yacc.c  */
-#line 662 "parser.y"
+#line 658 "parser.y"
     {
                  BEGIN_ACTION;
                  set((yyval.sel), _gmx_sel_init_variable_ref(get((yyvsp[(1) - (1)].sel))));
@@ -2561,7 +2557,7 @@ yyreduce:
 
   case 65:
 /* Line 1787 of yacc.c  */
-#line 670 "parser.y"
+#line 666 "parser.y"
     {
                  BEGIN_ACTION;
                  set((yyval.sel), _gmx_sel_init_variable_ref(get((yyvsp[(1) - (1)].sel))));
@@ -2571,7 +2567,7 @@ yyreduce:
 
   case 66:
 /* Line 1787 of yacc.c  */
-#line 678 "parser.y"
+#line 674 "parser.y"
     {
                  BEGIN_ACTION;
                  set((yyval.sel), _gmx_sel_init_variable_ref(get((yyvsp[(1) - (1)].sel))));
@@ -2581,19 +2577,19 @@ yyreduce:
 
   case 67:
 /* Line 1787 of yacc.c  */
-#line 691 "parser.y"
+#line 687 "parser.y"
     { (yyval.plist) = (yyvsp[(1) - (1)].plist); }
     break;
 
   case 68:
 /* Line 1787 of yacc.c  */
-#line 693 "parser.y"
+#line 689 "parser.y"
     { (yyval.plist) = (yyvsp[(1) - (2)].plist); }
     break;
 
   case 69:
 /* Line 1787 of yacc.c  */
-#line 698 "parser.y"
+#line 694 "parser.y"
     {
                  BEGIN_ACTION;
                  set((yyval.plist), SelectionParserParameter::createList());
@@ -2603,7 +2599,7 @@ yyreduce:
 
   case 70:
 /* Line 1787 of yacc.c  */
-#line 704 "parser.y"
+#line 700 "parser.y"
     {
                  BEGIN_ACTION;
                  SelectionParserParameterListPointer list(get((yyvsp[(1) - (2)].plist)));
@@ -2615,7 +2611,7 @@ yyreduce:
 
   case 71:
 /* Line 1787 of yacc.c  */
-#line 715 "parser.y"
+#line 711 "parser.y"
     {
                  BEGIN_ACTION;
                  scoped_ptr_sfree nameGuard((yyvsp[(1) - (2)].str));
@@ -2626,19 +2622,19 @@ yyreduce:
 
   case 72:
 /* Line 1787 of yacc.c  */
-#line 723 "parser.y"
+#line 719 "parser.y"
     { (yyval.vlist) = (yyvsp[(1) - (1)].vlist);   }
     break;
 
   case 73:
 /* Line 1787 of yacc.c  */
-#line 724 "parser.y"
+#line 720 "parser.y"
     { (yyval.vlist) = (yyvsp[(2) - (3)].vlist);   }
     break;
 
   case 74:
 /* Line 1787 of yacc.c  */
-#line 729 "parser.y"
+#line 725 "parser.y"
     {
                  BEGIN_ACTION;
                  set((yyval.vlist), SelectionParserValue::createList());
@@ -2648,7 +2644,7 @@ yyreduce:
 
   case 75:
 /* Line 1787 of yacc.c  */
-#line 735 "parser.y"
+#line 731 "parser.y"
     {
                  BEGIN_ACTION;
                  SelectionParserValueListPointer list(get((yyvsp[(1) - (2)].vlist)));
@@ -2660,7 +2656,7 @@ yyreduce:
 
   case 76:
 /* Line 1787 of yacc.c  */
-#line 743 "parser.y"
+#line 739 "parser.y"
     {
                  BEGIN_ACTION;
                  SelectionParserValueListPointer list(get((yyvsp[(1) - (3)].vlist)));
@@ -2672,19 +2668,19 @@ yyreduce:
 
   case 77:
 /* Line 1787 of yacc.c  */
-#line 753 "parser.y"
+#line 749 "parser.y"
     { (yyval.vlist) = (yyvsp[(1) - (1)].vlist); }
     break;
 
   case 78:
 /* Line 1787 of yacc.c  */
-#line 754 "parser.y"
+#line 750 "parser.y"
     { (yyval.vlist) = (yyvsp[(2) - (3)].vlist); }
     break;
 
   case 79:
 /* Line 1787 of yacc.c  */
-#line 759 "parser.y"
+#line 755 "parser.y"
     {
                  BEGIN_ACTION;
                  set((yyval.vlist), SelectionParserValue::createList(get((yyvsp[(1) - (1)].val))));
@@ -2694,7 +2690,7 @@ yyreduce:
 
   case 80:
 /* Line 1787 of yacc.c  */
-#line 765 "parser.y"
+#line 761 "parser.y"
     {
                  BEGIN_ACTION;
                  SelectionParserValueListPointer list(get((yyvsp[(1) - (2)].vlist)));
@@ -2706,7 +2702,7 @@ yyreduce:
 
   case 81:
 /* Line 1787 of yacc.c  */
-#line 773 "parser.y"
+#line 769 "parser.y"
     {
                  BEGIN_ACTION;
                  SelectionParserValueListPointer list(get((yyvsp[(1) - (3)].vlist)));
@@ -2718,7 +2714,7 @@ yyreduce:
 
   case 82:
 /* Line 1787 of yacc.c  */
-#line 783 "parser.y"
+#line 779 "parser.y"
     {
                  BEGIN_ACTION;
                  set((yyval.val), SelectionParserValue::createExpr(get((yyvsp[(1) - (1)].sel))));
@@ -2728,7 +2724,7 @@ yyreduce:
 
   case 83:
 /* Line 1787 of yacc.c  */
-#line 789 "parser.y"
+#line 785 "parser.y"
     {
                  BEGIN_ACTION;
                  set((yyval.val), SelectionParserValue::createExpr(get((yyvsp[(1) - (1)].sel))));
@@ -2738,7 +2734,7 @@ yyreduce:
 
   case 84:
 /* Line 1787 of yacc.c  */
-#line 795 "parser.y"
+#line 791 "parser.y"
     {
                  BEGIN_ACTION;
                  set((yyval.val), SelectionParserValue::createExpr(get((yyvsp[(1) - (1)].sel))));
@@ -2748,7 +2744,7 @@ yyreduce:
 
   case 85:
 /* Line 1787 of yacc.c  */
-#line 801 "parser.y"
+#line 797 "parser.y"
     {
                  BEGIN_ACTION;
                  set((yyval.val), SelectionParserValue::createExpr(get((yyvsp[(1) - (1)].sel))));
@@ -2758,13 +2754,13 @@ yyreduce:
 
   case 86:
 /* Line 1787 of yacc.c  */
-#line 806 "parser.y"
+#line 802 "parser.y"
     { (yyval.val) = (yyvsp[(1) - (1)].val); }
     break;
 
   case 87:
 /* Line 1787 of yacc.c  */
-#line 811 "parser.y"
+#line 807 "parser.y"
     {
                  BEGIN_ACTION;
                  set((yyval.val), SelectionParserValue::createInteger((yyvsp[(1) - (1)].i)));
@@ -2774,7 +2770,7 @@ yyreduce:
 
   case 88:
 /* Line 1787 of yacc.c  */
-#line 817 "parser.y"
+#line 813 "parser.y"
     {
                  BEGIN_ACTION;
                  set((yyval.val), SelectionParserValue::createReal((yyvsp[(1) - (1)].r)));
@@ -2784,7 +2780,7 @@ yyreduce:
 
   case 89:
 /* Line 1787 of yacc.c  */
-#line 823 "parser.y"
+#line 819 "parser.y"
     {
                  BEGIN_ACTION;
                  scoped_ptr_sfree stringGuard((yyvsp[(1) - (1)].str));
@@ -2795,13 +2791,13 @@ yyreduce:
 
   case 90:
 /* Line 1787 of yacc.c  */
-#line 829 "parser.y"
+#line 825 "parser.y"
     { (yyval.val) = (yyvsp[(1) - (1)].val); }
     break;
 
   case 91:
 /* Line 1787 of yacc.c  */
-#line 834 "parser.y"
+#line 830 "parser.y"
     {
                  BEGIN_ACTION;
                  set((yyval.val), SelectionParserValue::createIntegerRange((yyvsp[(1) - (3)].i), (yyvsp[(3) - (3)].i)));
@@ -2811,7 +2807,7 @@ yyreduce:
 
   case 92:
 /* Line 1787 of yacc.c  */
-#line 840 "parser.y"
+#line 836 "parser.y"
     {
                  BEGIN_ACTION;
                  set((yyval.val), SelectionParserValue::createRealRange((yyvsp[(1) - (3)].i), (yyvsp[(3) - (3)].r)));
@@ -2821,7 +2817,7 @@ yyreduce:
 
   case 93:
 /* Line 1787 of yacc.c  */
-#line 846 "parser.y"
+#line 842 "parser.y"
     {
                  BEGIN_ACTION;
                  set((yyval.val), SelectionParserValue::createRealRange((yyvsp[(1) - (3)].r), (yyvsp[(3) - (3)].r)));
@@ -2831,7 +2827,7 @@ yyreduce:
 
 
 /* Line 1787 of yacc.c  */
-#line 2835 "parser.cpp"
+#line 2831 "parser.cpp"
       default: break;
     }
   /* User semantic actions sometimes alter yychar, and that requires
index 757ce0cbbb8ffd8352431eaf82653a8eb7562d7f..81f140a4e3c24fabbaec17f48d8f2f6c66bff707 100644 (file)
@@ -252,11 +252,10 @@ cmd_plain:   /* empty */
                  BEGIN_ACTION;
                  SelectionTreeElementPointer s
                         = _gmx_sel_init_group_by_id($1, scanner);
-                 if (!s) YYERROR;
                  SelectionTreeElementPointer p
                         = _gmx_sel_init_position(s, NULL, scanner);
                  if (!p) YYERROR;
-                 set($$, _gmx_sel_init_selection(s->name().c_str(), p, scanner));
+                 set($$, _gmx_sel_init_selection(NULL, p, scanner));
                  END_ACTION;
              }
            | string
@@ -265,11 +264,10 @@ cmd_plain:   /* empty */
                  scoped_ptr_sfree nameGuard($1);
                  SelectionTreeElementPointer s
                         = _gmx_sel_init_group_by_name($1, scanner);
-                 if (!s) YYERROR;
                  SelectionTreeElementPointer p
                         = _gmx_sel_init_position(s, NULL, scanner);
                  if (!p) YYERROR;
-                 set($$, _gmx_sel_init_selection(s->name().c_str(), p, scanner));
+                 set($$, _gmx_sel_init_selection(NULL, p, scanner));
                  END_ACTION;
              }
            | selection
@@ -433,14 +431,12 @@ sel_expr:    GROUP string
                  BEGIN_ACTION;
                  scoped_ptr_sfree nameGuard($2);
                  set($$, _gmx_sel_init_group_by_name($2, scanner));
-                 CHECK_SEL($$);
                  END_ACTION;
              }
            | GROUP TOK_INT
              {
                  BEGIN_ACTION;
                  set($$, _gmx_sel_init_group_by_id($2, scanner));
-                 CHECK_SEL($$);
                  END_ACTION;
              }
 ;
index 6790798160d3bd6c0db71558c729a003841c4573..b98cbba819d6618519dba2d48c0f8957a13aad18 100644 (file)
 #include "gromacs/utility/exceptions.h"
 #include "gromacs/utility/file.h"
 #include "gromacs/utility/messagestringcollector.h"
+#include "gromacs/utility/stringutil.h"
 
 #include "keywords.h"
 #include "parsetree.h"
@@ -271,8 +272,20 @@ _gmx_selparser_error(yyscan_t scanner, const char *fmt, ...)
 }
 
 bool
-_gmx_selparser_handle_exception(yyscan_t scanner, const std::exception & /*ex*/)
+_gmx_selparser_handle_exception(yyscan_t scanner, const std::exception &ex)
 {
+    if (dynamic_cast<const gmx::UserInputError *>(&ex) != NULL)
+    {
+        // TODO: Consider whether also the non-interactive parser should
+        // postpone the exception such that the whole selection can be added as
+        // context.
+        if (_gmx_sel_is_lexer_interactive(scanner))
+        {
+            // TODO: Handle exceptions that printing the message may produce.
+            gmx::formatExceptionMessageToFile(stderr, ex);
+            return true;
+        }
+    }
     _gmx_sel_lexer_set_exception(scanner, boost::current_exception());
     return false;
 }
@@ -903,8 +916,7 @@ _gmx_sel_init_const_position(real x, real y, real z)
 /*!
  * \param[in] name  Name of an index group to search for.
  * \param[in] scanner Scanner data structure.
- * \returns   The created constant selection element, or NULL if no matching
- *     index group found.
+ * \returns   The created selection element.
  *
  * See gmx_ana_indexgrps_find() for information on how \p name is matched
  * against the index groups.
@@ -912,67 +924,42 @@ _gmx_sel_init_const_position(real x, real y, real z)
 SelectionTreeElementPointer
 _gmx_sel_init_group_by_name(const char *name, yyscan_t scanner)
 {
-    gmx_ana_indexgrps_t *grps = _gmx_sel_lexer_indexgrps(scanner);
 
-    if (!_gmx_sel_lexer_has_groups_set(scanner))
-    {
-        SelectionTreeElementPointer sel(new SelectionTreeElement(SEL_GROUPREF));
-        _gmx_selelem_set_vtype(sel, GROUP_VALUE);
-        sel->setName(name);
-        sel->u.gref.name = strdup(name);
-        sel->u.gref.id   = -1;
-        return sel;
-    }
-    if (!grps)
-    {
-        _gmx_selparser_error(scanner, "No index groups set; cannot match 'group %s'", name);
-        return SelectionTreeElementPointer();
-    }
-    SelectionTreeElementPointer sel(new SelectionTreeElement(SEL_CONST));
+    SelectionTreeElementPointer sel(new SelectionTreeElement(SEL_GROUPREF));
     _gmx_selelem_set_vtype(sel, GROUP_VALUE);
-    std::string                 foundName;
-    if (!gmx_ana_indexgrps_find(&sel->u.cgrp, &foundName, grps, name))
+    sel->setName(gmx::formatString("group \"%s\"", name));
+    sel->u.gref.name = strdup(name);
+    sel->u.gref.id   = -1;
+
+    if (_gmx_sel_lexer_has_groups_set(scanner))
     {
-        _gmx_selparser_error(scanner, "Cannot match 'group %s'", name);
-        return SelectionTreeElementPointer();
+        gmx_ana_indexgrps_t *grps = _gmx_sel_lexer_indexgrps(scanner);
+        sel->resolveIndexGroupReference(grps);
     }
-    sel->setName(foundName);
+
     return sel;
 }
 
 /*!
  * \param[in] id    Zero-based index number of the group to extract.
  * \param[in] scanner Scanner data structure.
- * \returns   The created constant selection element, or NULL if no matching
- *     index group found.
+ * \returns   The created selection element.
  */
 SelectionTreeElementPointer
 _gmx_sel_init_group_by_id(int id, yyscan_t scanner)
 {
-    gmx_ana_indexgrps_t *grps = _gmx_sel_lexer_indexgrps(scanner);
-
-    if (!_gmx_sel_lexer_has_groups_set(scanner))
-    {
-        SelectionTreeElementPointer sel(new SelectionTreeElement(SEL_GROUPREF));
-        _gmx_selelem_set_vtype(sel, GROUP_VALUE);
-        sel->u.gref.name = NULL;
-        sel->u.gref.id   = id;
-        return sel;
-    }
-    if (!grps)
-    {
-        _gmx_selparser_error(scanner, "No index groups set; cannot match 'group %d'", id);
-        return SelectionTreeElementPointer();
-    }
-    SelectionTreeElementPointer sel(new SelectionTreeElement(SEL_CONST));
+    SelectionTreeElementPointer sel(new SelectionTreeElement(SEL_GROUPREF));
     _gmx_selelem_set_vtype(sel, GROUP_VALUE);
-    std::string                 foundName;
-    if (!gmx_ana_indexgrps_extract(&sel->u.cgrp, &foundName, grps, id))
+    sel->setName(gmx::formatString("group %d", id));
+    sel->u.gref.name = NULL;
+    sel->u.gref.id   = id;
+
+    if (_gmx_sel_lexer_has_groups_set(scanner))
     {
-        _gmx_selparser_error(scanner, "Cannot match 'group %d'", id);
-        return SelectionTreeElementPointer();
+        gmx_ana_indexgrps_t *grps = _gmx_sel_lexer_indexgrps(scanner);
+        sel->resolveIndexGroupReference(grps);
     }
-    sel->setName(foundName);
+
     return sel;
 }
 
@@ -1038,35 +1025,7 @@ _gmx_sel_init_selection(const char                        *name,
     /* Update the flags */
     _gmx_selelem_update_flags(root, scanner);
 
-    /* If there is no name provided by the user, check whether the actual
-     * selection given was from an external group, and if so, use the name
-     * of the external group. */
-    if (root->name().empty())
-    {
-        SelectionTreeElementPointer child = root->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
-            && child->child->child->type == SEL_CONST
-            && child->child->child->v.type == GROUP_VALUE)
-        {
-            root->setName(child->child->child->name());
-        }
-    }
-    /* If there still is no name, use the selection string */
-    if (root->name().empty())
-    {
-        root->setName(_gmx_sel_lexer_pselstr(scanner));
-    }
+    root->fillNameIfMissing(_gmx_sel_lexer_pselstr(scanner));
 
     /* Print out some information if the parser is interactive */
     if (_gmx_sel_is_lexer_interactive(scanner))
index 573b086ba1bae83f3d17f1ccc179cc76807ffa9f..ea476706647ade23ae96ae20b22d1d1afbb6bb39 100644 (file)
@@ -170,6 +170,13 @@ void computeMassesAndCharges(const t_topology *top, const gmx_ana_pos_t &pos,
 
 }       // namespace
 
+void
+SelectionData::refreshName()
+{
+    rootElement_.fillNameIfMissing(selectionText_.c_str());
+    name_ = rootElement_.name();
+}
+
 void
 SelectionData::initializeMassesAndCharges(const t_topology *top)
 {
index f910ab817bcb36e1d72453389240f1d25f1b1595..861f407633135c11cd760302f8ed1a7e617b600a 100644 (file)
@@ -96,6 +96,8 @@ class SelectionData
         SelectionData(SelectionTreeElement *elem, const char *selstr);
         ~SelectionData();
 
+        //! Returns the name for this selection.
+        const char *name() const { return name_.c_str(); }
         //! Returns the string that was parsed to produce this selection.
         const char *selectionText() const { return selectionText_.c_str(); }
         //! Returns true if the size of the selection (posCount()) is dynamic.
@@ -119,6 +121,18 @@ class SelectionData
         //! \copydoc Selection::initCoveredFraction()
         bool initCoveredFraction(e_coverfrac_t type);
 
+        /*! \brief
+         * Updates the name of the selection if missing.
+         *
+         * \throws    std::bad_alloc if out of memory.
+         *
+         * If selections get their value from a group reference that cannot be
+         * resolved during parsing, the name is final only after group
+         * references have been resolved.
+         *
+         * This function is called by SelectionCollection::setIndexGroups().
+         */
+        void refreshName();
         /*! \brief
          * Computes total masses and charges for all selection positions.
          *
@@ -287,7 +301,7 @@ class Selection
         explicit Selection(internal::SelectionData *sel) : sel_(sel) {}
 
         //! Returns the name of the selection.
-        const char *name() const  { return data().name_.c_str(); }
+        const char *name() const  { return data().name(); }
         //! Returns the string that was parsed to produce this selection.
         const char *selectionText() const { return data().selectionText(); }
         //! Returns true if the size of the selection (posCount()) is dynamic.
index 6d0dc6ce439eb3eb837e65cce8611c4635789cfe..d423b3e0db9d71cd20768e13732e15816983d024 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2009,2010,2011,2012, by the GROMACS development team, led by
+ * Copyright (c) 2009,2010,2011,2012,2013, 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.
@@ -111,7 +111,7 @@ struct gmx_ana_selcollection_t
 namespace gmx
 {
 
-class MessageStringCollector;
+class ExceptionInitializer;
 
 /*! \internal \brief
  * Private implemention class for SelectionCollection.
@@ -140,18 +140,16 @@ class SelectionCollection::Impl
          *
          * \param[in]    root    Root of selection tree to process.
          * \param        errors  Object for reporting any error messages.
+         * \throws std::bad_alloc if out of memory.
          *
          * Recursively searches the selection tree for unresolved external
          * references.  If one is found, finds the referenced group in
          * \a grps_ and replaces the reference with a constant element that
          * contains the atoms from the referenced group.  Any failures to
          * resolve references are reported to \p errors.
-         *
-         * Does not throw currently, but this is subject to change when more
-         * underlying code is converted to C++.
          */
         void resolveExternalGroups(const gmx::SelectionTreeElementPointer &root,
-                                   MessageStringCollector                 *errors);
+                                   ExceptionInitializer                   *errors);
 
         //! Internal data, used for interfacing with old C code.
         gmx_ana_selcollection_t sc_;
index 656ccb78c78b52bb3001f9e756460f2b03014737..62865880f6326d57dbfd2221288d2925fe2c6e28 100644 (file)
@@ -300,45 +300,18 @@ early_termination:
 
 void SelectionCollection::Impl::resolveExternalGroups(
         const SelectionTreeElementPointer &root,
-        MessageStringCollector            *errors)
+        ExceptionInitializer              *errors)
 {
 
     if (root->type == SEL_GROUPREF)
     {
-        bool        bOk = true;
-        std::string foundName;
-        if (grps_ == NULL)
+        try
         {
-            // TODO: Improve error messages
-            errors->append("Unknown group referenced in a selection");
-            bOk = false;
+            root->resolveIndexGroupReference(grps_);
         }
-        else if (root->u.gref.name != NULL)
+        catch (const UserInputError &)
         {
-            char *name = root->u.gref.name;
-            bOk = gmx_ana_indexgrps_find(&root->u.cgrp, &foundName, grps_, name);
-            sfree(name);
-            root->u.gref.name = NULL;
-            if (!bOk)
-            {
-                // TODO: Improve error messages
-                errors->append("Unknown group referenced in a selection");
-            }
-        }
-        else
-        {
-            if (!gmx_ana_indexgrps_extract(&root->u.cgrp, &foundName, grps_,
-                                           root->u.gref.id))
-            {
-                // TODO: Improve error messages
-                errors->append("Unknown group referenced in a selection");
-                bOk = false;
-            }
-        }
-        if (bOk)
-        {
-            root->type = SEL_CONST;
-            root->setName(foundName);
+            errors->addCurrentExceptionAsNested();
         }
     }
 
@@ -466,16 +439,20 @@ SelectionCollection::setIndexGroups(gmx_ana_indexgrps_t *grps)
     impl_->grps_               = grps;
     impl_->bExternalGroupsSet_ = true;
 
-    MessageStringCollector      errors;
+    ExceptionInitializer        errors("Unknown index group references encountered");
     SelectionTreeElementPointer root = impl_->sc_.root;
     while (root)
     {
         impl_->resolveExternalGroups(root, &errors);
         root = root->next;
     }
-    if (!errors.isEmpty())
+    if (errors.hasNestedExceptions())
     {
-        GMX_THROW(InvalidInputError(errors.toString()));
+        GMX_THROW(InconsistentInputError(errors));
+    }
+    for (size_t i = 0; i < impl_->sc_.sel.size(); ++i)
+    {
+        impl_->sc_.sel[i]->refreshName();
     }
 }
 
index 2e8947fb1bf5d043dc70567c50142703fc47d0af..a00ae0484b30b0ba2b222655b00a2af63a16332e 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2010,2011,2012, by the GROMACS development team, led by
+ * Copyright (c) 2010,2011,2012,2013, 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.
@@ -223,14 +223,14 @@ class SelectionCollection
          *
          * \param[in]  grps  Index groups to use for the selections.
          * \throws  std::bad_alloc if out of memory.
-         * \throws  InvalidInputError if a group reference cannot be resolved.
+         * \throws  InconsistentInputError if a group reference cannot be resolved.
          *
          * Only the first call to this method can have a non-NULL \p grps.
          * At this point, any selections that have already been provided are
          * searched for references to external groups, and the references are
          * replaced by the contents of the groups.  If any referenced group
          * cannot be found in \p grps (or if \p grps is NULL and there are any
-         * references), InvalidInputError is thrown.
+         * references), InconsistentInputError is thrown.
          *
          * The selection collection keeps a reference to \p grps until this
          * method is called with a NULL \p grps.
index bc9d99388abb889c551f902b593a37ff7ec4334a..e1996fd80b34c36e8a19f01f8ff477bee73d34da 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2009,2010,2011,2012, by the GROMACS development team, led by
+ * Copyright (c) 2009,2010,2011,2012,2013, 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.
@@ -49,6 +49,7 @@
 #include "gromacs/selection/selmethod.h"
 #include "gromacs/utility/exceptions.h"
 #include "gromacs/utility/gmxassert.h"
+#include "gromacs/utility/stringutil.h"
 
 #include "keywords.h"
 #include "mempool.h"
@@ -290,6 +291,99 @@ 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::resolveIndexGroupReference(gmx_ana_indexgrps_t *grps)
+{
+    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))
+    {
+        gmx_ana_index_deinit(&foundGroup);
+        std::string message = formatString(
+                    "Group '%s' ('%s') cannot be used in selections, "
+                    "because atom indices in it are not sorted and/or "
+                    "it contains duplicate atoms.",
+                    foundName.c_str(), name().c_str());
+        GMX_THROW(InconsistentInputError(message));
+    }
+
+    sfree(u.gref.name);
+    type = SEL_CONST;
+    gmx_ana_index_set(&u.cgrp, foundGroup.isize, foundGroup.index,
+                      foundGroup.nalloc_index);
+    setName(foundName);
+}
+
 } // namespace gmx
 
 /*!
index 5971c051bf09ae2de3820a30a6b4b25ea13c920e..c89adf0ecb0bf1a199afbe4cefcc6a95ab686457 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2009,2010,2011,2012, by the GROMACS development team, led by
+ * Copyright (c) 2009,2010,2011,2012,2013, 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.
@@ -306,6 +306,28 @@ class SelectionTreeElement
         void setName(const char *name) { name_ = (name != NULL ? name : ""); }
         //! \copydoc setName(const char *)
         void setName(const std::string &name) { name_ = name; }
+        /*! \brief
+         * Sets the name of a root element if it is missing.
+         *
+         * \param[in] selectionText  Full selection text to use as a fallback.
+         * \throws    std::bad_alloc if out of memory.
+         *
+         * If index groups have not yet been set and the selection is a result
+         * of a group reference, the name may still be empty after this call.
+         *
+         * Strong exception safety guarantee.
+         */
+        void fillNameIfMissing(const char *selectionText);
+
+        /*! \brief
+         * Resolved an unresolved reference to an index group.
+         *
+         * \param[in] grps  Index groups to use to resolve the reference.
+         * \throws    std::bad_alloc if out of memory.
+         * \throws    InconsistentInputError if the reference cannot be
+         *     resolved.
+         */
+        void resolveIndexGroupReference(gmx_ana_indexgrps_t *grps);
 
         //! Type of the element.
         e_selelem_t                         type;
index b364904e48393693afb3b8534d6e3de08f8baab7..97c20e2d9b4c6ccf3c60c8d8d277532986603140 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2009,2010,2011,2012, by the GROMACS development team, led by
+ * Copyright (c) 2009,2010,2011,2012,2013, 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.
@@ -867,6 +867,9 @@ evaluate_coord(t_trxframe *fr, gmx_ana_index_t *g, real out[],
     }
     else
     {
+        // TODO: This loop is never reached in the current code.
+        // It would be useful to change the code such that it is, mostly for
+        // memory efficiency reasons.
         for (i = 0; i < g->isize; ++i)
         {
             out[i] = fr->x[g->index[i]][d];
index 63feebf7c9c83ff424ed48cb902104eb9176cd19..bb21453cedb7992a9396c03975a03b9df02bccd5 100644 (file)
@@ -4,19 +4,16 @@
   <ParsedSelections Name="Parsed">
     <ParsedSelection Name="Selection1">
       <String Name="Input">name CB</String>
-      <String Name="Name">name CB</String>
       <String Name="Text">name CB</String>
       <Bool Name="Dynamic">false</Bool>
     </ParsedSelection>
     <ParsedSelection Name="Selection2">
       <String Name="Input">y &gt; 2</String>
-      <String Name="Name">y &gt; 2</String>
       <String Name="Text">y &gt; 2</String>
       <Bool Name="Dynamic">true</Bool>
     </ParsedSelection>
     <ParsedSelection Name="Selection3">
       <String Name="Input">res_cog of y &gt; 2</String>
-      <String Name="Name">res_cog of y &gt; 2</String>
       <String Name="Text">res_cog of y &gt; 2</String>
       <Bool Name="Dynamic">true</Bool>
     </ParsedSelection>
index f8380a2128b3becfcbb09cf4a164279bf9cef8fe..6e1871c19e90da64db1eab9c76d8e702f34e07eb 100644 (file)
@@ -4,19 +4,16 @@
   <ParsedSelections Name="Parsed">
     <ParsedSelection Name="Selection1">
       <String Name="Input">atomnr 1 to 3 8 to 9</String>
-      <String Name="Name">atomnr 1 to 3 8 to 9</String>
       <String Name="Text">atomnr 1 to 3 8 to 9</String>
       <Bool Name="Dynamic">false</Bool>
     </ParsedSelection>
     <ParsedSelection Name="Selection2">
       <String Name="Input">y &gt; 2</String>
-      <String Name="Name">y &gt; 2</String>
       <String Name="Text">y &gt; 2</String>
       <Bool Name="Dynamic">true</Bool>
     </ParsedSelection>
     <ParsedSelection Name="Selection3">
       <String Name="Input">cog of (y &gt; 2)</String>
-      <String Name="Name">cog of (y &gt; 2)</String>
       <String Name="Text">cog of (y &gt; 2)</String>
       <Bool Name="Dynamic">true</Bool>
     </ParsedSelection>
index 23b96ddac76ce595774d00515158c359d3b5329a..262279ec52cff60545dcca5797bb8f96976495fd 100644 (file)
@@ -4,13 +4,11 @@
   <ParsedSelections Name="Parsed">
     <ParsedSelection Name="Selection1">
       <String Name="Input">all</String>
-      <String Name="Name">all</String>
       <String Name="Text">all</String>
       <Bool Name="Dynamic">false</Bool>
     </ParsedSelection>
     <ParsedSelection Name="Selection2">
       <String Name="Input">none</String>
-      <String Name="Name">none</String>
       <String Name="Text">none</String>
       <Bool Name="Dynamic">false</Bool>
     </ParsedSelection>
index f95763c81b93f6dc530fdd3e47275512af1e7fe7..ead707ebb2a28beccdd2fc6da590cfef43b4a5d3 100644 (file)
@@ -4,13 +4,11 @@
   <ParsedSelections Name="Parsed">
     <ParsedSelection Name="Selection1">
       <String Name="Input">altloc " "</String>
-      <String Name="Name">altloc " "</String>
       <String Name="Text">altloc " "</String>
       <Bool Name="Dynamic">false</Bool>
     </ParsedSelection>
     <ParsedSelection Name="Selection2">
       <String Name="Input">altloc A</String>
-      <String Name="Name">altloc A</String>
       <String Name="Text">altloc A</String>
       <Bool Name="Dynamic">false</Bool>
     </ParsedSelection>
index a2c3be1da8cbf43944a09b2149e7b0909fef7ce0..186ebb6307db247d5e7dc239d37bb78bcff9ef1b 100644 (file)
@@ -4,25 +4,21 @@
   <ParsedSelections Name="Parsed">
     <ParsedSelection Name="Selection1">
       <String Name="Input">x+1 &gt; 3</String>
-      <String Name="Name">x+1 &gt; 3</String>
       <String Name="Text">x+1 &gt; 3</String>
       <Bool Name="Dynamic">true</Bool>
     </ParsedSelection>
     <ParsedSelection Name="Selection2">
       <String Name="Input">(y-1)^2 &lt;= 1</String>
-      <String Name="Name">(y-1)^2 &lt;= 1</String>
       <String Name="Text">(y-1)^2 &lt;= 1</String>
       <Bool Name="Dynamic">true</Bool>
     </ParsedSelection>
     <ParsedSelection Name="Selection3">
       <String Name="Input">x+--1 &gt; 3</String>
-      <String Name="Name">x+--1 &gt; 3</String>
       <String Name="Text">x+--1 &gt; 3</String>
       <Bool Name="Dynamic">true</Bool>
     </ParsedSelection>
     <ParsedSelection Name="Selection4">
       <String Name="Input">-x+-1 &lt; -3</String>
-      <String Name="Name">-x+-1 &lt; -3</String>
       <String Name="Text">-x+-1 &lt; -3</String>
       <Bool Name="Dynamic">true</Bool>
     </ParsedSelection>
index 85a8d625c0d60e0c26814f27909a76b146f134a7..2db05aff253948554d52a981e0a0edbf20b95d44 100644 (file)
@@ -4,13 +4,11 @@
   <ParsedSelections Name="Parsed">
     <ParsedSelection Name="Selection1">
       <String Name="Input">name CB</String>
-      <String Name="Name">name CB</String>
       <String Name="Text">name CB</String>
       <Bool Name="Dynamic">false</Bool>
     </ParsedSelection>
     <ParsedSelection Name="Selection2">
       <String Name="Input">atomname S1 S2</String>
-      <String Name="Name">atomname S1 S2</String>
       <String Name="Text">atomname S1 S2</String>
       <Bool Name="Dynamic">false</Bool>
     </ParsedSelection>
index d04eeae488dc009ac69dcddd7d66b0ddf094593d..d0af612a0e3a4aa605390346380c23ca20f20aa4 100644 (file)
@@ -4,19 +4,16 @@
   <ParsedSelections Name="Parsed">
     <ParsedSelection Name="Selection1">
       <String Name="Input">atomnr 1 to 3 6 to 8</String>
-      <String Name="Name">atomnr 1 to 3 6 to 8</String>
       <String Name="Text">atomnr 1 to 3 6 to 8</String>
       <Bool Name="Dynamic">false</Bool>
     </ParsedSelection>
     <ParsedSelection Name="Selection2">
       <String Name="Input">atomnr 4 2 5 to 7</String>
-      <String Name="Name">atomnr 4 2 5 to 7</String>
       <String Name="Text">atomnr 4 2 5 to 7</String>
       <Bool Name="Dynamic">false</Bool>
     </ParsedSelection>
     <ParsedSelection Name="Selection3">
       <String Name="Input">atomnr &lt;= 5</String>
-      <String Name="Name">atomnr &lt;= 5</String>
       <String Name="Text">atomnr &lt;= 5</String>
       <Bool Name="Dynamic">false</Bool>
     </ParsedSelection>
diff --git a/src/gromacs/selection/tests/refdata/SelectionCollectionDataTest_HandlesAtomtype.xml b/src/gromacs/selection/tests/refdata/SelectionCollectionDataTest_HandlesAtomtype.xml
new file mode 100644 (file)
index 0000000..93aa131
--- /dev/null
@@ -0,0 +1,23 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <ParsedSelections Name="Parsed">
+    <ParsedSelection Name="Selection1">
+      <String Name="Input">atomtype CA</String>
+      <String Name="Text">atomtype CA</String>
+      <Bool Name="Dynamic">false</Bool>
+    </ParsedSelection>
+  </ParsedSelections>
+  <CompiledSelections Name="Compiled">
+    <Selection Name="Selection1">
+      <Sequence Name="Atoms">
+        <Int Name="Length">5</Int>
+        <Int>0</Int>
+        <Int>3</Int>
+        <Int>6</Int>
+        <Int>9</Int>
+        <Int>12</Int>
+      </Sequence>
+    </Selection>
+  </CompiledSelections>
+</ReferenceData>
index 0e4a3eff0ee09b2b8c2721a7169cde3dc0f94ca8..54a51087ff0531dff900c5559f6104f9feb4a05a 100644 (file)
@@ -4,31 +4,26 @@
   <ParsedSelections Name="Parsed">
     <ParsedSelection Name="Selection1">
       <String Name="Input">atomnr 1 to 5 and atomnr 2 to 7</String>
-      <String Name="Name">atomnr 1 to 5 and atomnr 2 to 7</String>
       <String Name="Text">atomnr 1 to 5 and atomnr 2 to 7</String>
       <Bool Name="Dynamic">false</Bool>
     </ParsedSelection>
     <ParsedSelection Name="Selection2">
       <String Name="Input">atomnr 1 to 5 or not atomnr 3 to 8</String>
-      <String Name="Name">atomnr 1 to 5 or not atomnr 3 to 8</String>
       <String Name="Text">atomnr 1 to 5 or not atomnr 3 to 8</String>
       <Bool Name="Dynamic">false</Bool>
     </ParsedSelection>
     <ParsedSelection Name="Selection3">
       <String Name="Input">not not atomnr 1 to 5 and atomnr 2 to 6 and not not atomnr 3 to 7</String>
-      <String Name="Name">not not atomnr 1 to 5 and atomnr 2 to 6 and not not atomnr 3 to 7</String>
       <String Name="Text">not not atomnr 1 to 5 and atomnr 2 to 6 and not not atomnr 3 to 7</String>
       <Bool Name="Dynamic">false</Bool>
     </ParsedSelection>
     <ParsedSelection Name="Selection4">
       <String Name="Input">atomnr 1 to 5 and (atomnr 2 to 7 and atomnr 3 to 6)</String>
-      <String Name="Name">atomnr 1 to 5 and (atomnr 2 to 7 and atomnr 3 to 6)</String>
       <String Name="Text">atomnr 1 to 5 and (atomnr 2 to 7 and atomnr 3 to 6)</String>
       <Bool Name="Dynamic">false</Bool>
     </ParsedSelection>
     <ParsedSelection Name="Selection5">
       <String Name="Input">x &lt; 5 and atomnr 1 to 5 and y &lt; 3 and atomnr 2 to 4</String>
-      <String Name="Name">x &lt; 5 and atomnr 1 to 5 and y &lt; 3 and atomnr 2 to 4</String>
       <String Name="Text">x &lt; 5 and atomnr 1 to 5 and y &lt; 3 and atomnr 2 to 4</String>
       <Bool Name="Dynamic">true</Bool>
     </ParsedSelection>
index ea7d01d4d4c0412240965291a11cbfa0606c035d..a03266b272c1b9884040c03f86e65cd73d7c28db 100644 (file)
@@ -4,13 +4,11 @@
   <ParsedSelections Name="Parsed">
     <ParsedSelection Name="Selection1">
       <String Name="Input">beta 0</String>
-      <String Name="Name">betafactor 0</String>
       <String Name="Text">betafactor 0</String>
       <Bool Name="Dynamic">false</Bool>
     </ParsedSelection>
     <ParsedSelection Name="Selection2">
       <String Name="Input">beta &gt;= 0.3</String>
-      <String Name="Name">betafactor &gt;= 0.3</String>
       <String Name="Text">betafactor &gt;= 0.3</String>
       <Bool Name="Dynamic">false</Bool>
     </ParsedSelection>
index 97cd37f815242dc18c048637eea46fccce52d7e4..8c95d044c7ea937b292e4624fa5e2a6e782a3826 100644 (file)
@@ -4,31 +4,26 @@
   <ParsedSelections Name="Parsed">
     <ParsedSelection Name="Selection1">
       <String Name="Input">atomnr 1 to 5 and atomnr 2 to 7 and x &lt; 2</String>
-      <String Name="Name">atomnr 1 to 5 and atomnr 2 to 7 and x &lt; 2</String>
       <String Name="Text">atomnr 1 to 5 and atomnr 2 to 7 and x &lt; 2</String>
       <Bool Name="Dynamic">true</Bool>
     </ParsedSelection>
     <ParsedSelection Name="Selection2">
       <String Name="Input">atomnr 1 to 5 and (atomnr 4 to 7 or x &lt; 2)</String>
-      <String Name="Name">atomnr 1 to 5 and (atomnr 4 to 7 or x &lt; 2)</String>
       <String Name="Text">atomnr 1 to 5 and (atomnr 4 to 7 or x &lt; 2)</String>
       <Bool Name="Dynamic">true</Bool>
     </ParsedSelection>
     <ParsedSelection Name="Selection3">
       <String Name="Input">atomnr 1 to 5 and y &lt; 3 and (atomnr 4 to 7 or x &lt; 2)</String>
-      <String Name="Name">atomnr 1 to 5 and y &lt; 3 and (atomnr 4 to 7 or x &lt; 2)</String>
       <String Name="Text">atomnr 1 to 5 and y &lt; 3 and (atomnr 4 to 7 or x &lt; 2)</String>
       <Bool Name="Dynamic">true</Bool>
     </ParsedSelection>
     <ParsedSelection Name="Selection4">
       <String Name="Input">atomnr 1 to 5 and not (atomnr 4 to 7 or x &lt; 2)</String>
-      <String Name="Name">atomnr 1 to 5 and not (atomnr 4 to 7 or x &lt; 2)</String>
       <String Name="Text">atomnr 1 to 5 and not (atomnr 4 to 7 or x &lt; 2)</String>
       <Bool Name="Dynamic">true</Bool>
     </ParsedSelection>
     <ParsedSelection Name="Selection5">
       <String Name="Input">atomnr 1 to 5 or (atomnr 4 to 6 and (atomnr 5 to 7 or x &lt; 2))</String>
-      <String Name="Name">atomnr 1 to 5 or (atomnr 4 to 6 and (atomnr 5 to 7 or x &lt; 2))</String>
       <String Name="Text">atomnr 1 to 5 or (atomnr 4 to 6 and (atomnr 5 to 7 or x &lt; 2))</String>
       <Bool Name="Dynamic">true</Bool>
     </ParsedSelection>
index fe31e659edb98d88caff23da51c33a4df89948ad..41a489fc997d77a564d6c2c69dc442246ce6abcc 100644 (file)
     </ParsedVariable>
     <ParsedSelection Name="Selection1">
       <String Name="Input">atomnr 1 to 4 and bar</String>
-      <String Name="Name">atomnr 1 to 4 and bar</String>
       <String Name="Text">atomnr 1 to 4 and bar</String>
       <Bool Name="Dynamic">true</Bool>
     </ParsedSelection>
     <ParsedSelection Name="Selection2">
       <String Name="Input">atomnr 2 to 6 and y &lt; 3 and bar2</String>
-      <String Name="Name">atomnr 2 to 6 and y &lt; 3 and bar2</String>
       <String Name="Text">atomnr 2 to 6 and y &lt; 3 and bar2</String>
       <Bool Name="Dynamic">true</Bool>
     </ParsedSelection>
     <ParsedSelection Name="Selection3">
       <String Name="Input">atomnr 6 to 10 and not foo</String>
-      <String Name="Name">atomnr 6 to 10 and not foo</String>
       <String Name="Text">atomnr 6 to 10 and not foo</String>
       <Bool Name="Dynamic">false</Bool>
     </ParsedSelection>
index 826b5234cfef591e0219e5e040271220466b1323..3e9002ec2c111bc2389e7420af8c25c03bc3264d 100644 (file)
@@ -7,19 +7,16 @@
     </ParsedVariable>
     <ParsedSelection Name="Selection1">
       <String Name="Input">atomnr 1 to 4 and foo</String>
-      <String Name="Name">atomnr 1 to 4 and foo</String>
       <String Name="Text">atomnr 1 to 4 and foo</String>
       <Bool Name="Dynamic">true</Bool>
     </ParsedSelection>
     <ParsedSelection Name="Selection2">
       <String Name="Input">atomnr 2 to 6 and y &lt; 3 and foo</String>
-      <String Name="Name">atomnr 2 to 6 and y &lt; 3 and foo</String>
       <String Name="Text">atomnr 2 to 6 and y &lt; 3 and foo</String>
       <Bool Name="Dynamic">true</Bool>
     </ParsedSelection>
     <ParsedSelection Name="Selection3">
       <String Name="Input">atomnr 6 to 10 and not foo</String>
-      <String Name="Name">atomnr 6 to 10 and not foo</String>
       <String Name="Text">atomnr 6 to 10 and not foo</String>
       <Bool Name="Dynamic">true</Bool>
     </ParsedSelection>
index 16dd2873e2b6e352a513c72aa3027970d083b7e3..6b5147fe2bee1151a811ce0ac34a9ab3a276c5e2 100644 (file)
@@ -4,13 +4,11 @@
   <ParsedSelections Name="Parsed">
     <ParsedSelection Name="Selection1">
       <String Name="Input">chain A</String>
-      <String Name="Name">chain A</String>
       <String Name="Text">chain A</String>
       <Bool Name="Dynamic">false</Bool>
     </ParsedSelection>
     <ParsedSelection Name="Selection2">
       <String Name="Input">chain B</String>
-      <String Name="Name">chain B</String>
       <String Name="Text">chain B</String>
       <Bool Name="Dynamic">false</Bool>
     </ParsedSelection>
index 62e2d068b052cbe0398ed1788e28bfc65d837ce0..e10179c949259633688d4e300a2f4d32ee8e6f5e 100644 (file)
@@ -4,7 +4,6 @@
   <ParsedSelections Name="Parsed">
     <ParsedSelection Name="Selection1">
       <String Name="Input">charge &lt; 0.5</String>
-      <String Name="Name">charge &lt; 0.5</String>
       <String Name="Text">charge &lt; 0.5</String>
       <Bool Name="Dynamic">false</Bool>
     </ParsedSelection>
index e8d7e984951e4ec370eee7e2dd5ca0d9367060fd..b1a2ae558b5192b978c01175c7f27b0cd3b0a0b4 100644 (file)
@@ -7,13 +7,11 @@
     </ParsedVariable>
     <ParsedSelection Name="Selection1">
       <String Name="Input">resname RA and value &lt;= 4</String>
-      <String Name="Name">resname RA and value &lt;= 4</String>
       <String Name="Text">resname RA and value &lt;= 4</String>
       <Bool Name="Dynamic">true</Bool>
     </ParsedSelection>
     <ParsedSelection Name="Selection2">
       <String Name="Input">resname RA RB and x &lt; 3 and value &lt;= 4</String>
-      <String Name="Name">resname RA RB and x &lt; 3 and value &lt;= 4</String>
       <String Name="Text">resname RA RB and x &lt; 3 and value &lt;= 4</String>
       <Bool Name="Dynamic">true</Bool>
     </ParsedSelection>
     </ParsedVariable>
     <ParsedSelection Name="Selection3">
       <String Name="Input">resname RA and index &lt; 3</String>
-      <String Name="Name">resname RA and index &lt; 3</String>
       <String Name="Text">resname RA and index &lt; 3</String>
       <Bool Name="Dynamic">false</Bool>
     </ParsedSelection>
     <ParsedSelection Name="Selection4">
       <String Name="Input">resname RB and y &lt; 3 and index &lt; 6</String>
-      <String Name="Name">resname RB and y &lt; 3 and index &lt; 6</String>
       <String Name="Text">resname RB and y &lt; 3 and index &lt; 6</String>
       <Bool Name="Dynamic">true</Bool>
     </ParsedSelection>
index 25226defaddf977af5087a050a135fe752585fb0..ddd50c834ce1f54d9f37539455e823c3b40f887b 100644 (file)
@@ -7,13 +7,11 @@
     </ParsedVariable>
     <ParsedSelection Name="Selection1">
       <String Name="Input">constpos</String>
-      <String Name="Name">constpos</String>
       <String Name="Text">constpos</String>
       <Bool Name="Dynamic">false</Bool>
     </ParsedSelection>
     <ParsedSelection Name="Selection2">
       <String Name="Input">within 2 of constpos</String>
-      <String Name="Name">within 2 of constpos</String>
       <String Name="Text">within 2 of constpos</String>
       <Bool Name="Dynamic">true</Bool>
     </ParsedSelection>
index 6496bb0cdf3e45e0e6926d961f883d44e9f4c3e4..9a8619f01dc3bf85ae690b9081d23524b2f1d040 100644 (file)
@@ -4,7 +4,6 @@
   <ParsedSelections Name="Parsed">
     <ParsedSelection Name="Selection1">
       <String Name="Input">[1, -2, 3.5]</String>
-      <String Name="Name">[1, -2, 3.5]</String>
       <String Name="Text">[1, -2, 3.5]</String>
       <Bool Name="Dynamic">false</Bool>
     </ParsedSelection>
index d65c005cca1eb608a489ef3c4a05c8871fc23ec7..26af6d248b35dc2d553f92cb6b272178ee0b07b7 100644 (file)
@@ -4,19 +4,16 @@
   <ParsedSelections Name="Parsed">
     <ParsedSelection Name="Selection1">
       <String Name="Input">x &lt; 3</String>
-      <String Name="Name">x &lt; 3</String>
       <String Name="Text">x &lt; 3</String>
       <Bool Name="Dynamic">true</Bool>
     </ParsedSelection>
     <ParsedSelection Name="Selection2">
       <String Name="Input">y &gt;= 3</String>
-      <String Name="Name">y &gt;= 3</String>
       <String Name="Text">y &gt;= 3</String>
       <Bool Name="Dynamic">true</Bool>
     </ParsedSelection>
     <ParsedSelection Name="Selection3">
       <String Name="Input">x {-1 to 2}</String>
-      <String Name="Name">x {-1 to 2}</String>
       <String Name="Text">x {-1 to 2}</String>
       <Bool Name="Dynamic">true</Bool>
     </ParsedSelection>
index 767f3a0c46b3e123a9206dc6f71a7252a16f60be..6283ab97ff557c6af644522e010d559855f2e30c 100644 (file)
@@ -4,7 +4,6 @@
   <ParsedSelections Name="Parsed">
     <ParsedSelection Name="Selection1">
       <String Name="Input">distance from cog of resnr 1 &lt; 2</String>
-      <String Name="Name">distance from cog of resnr 1 &lt; 2</String>
       <String Name="Text">distance from cog of resnr 1 &lt; 2</String>
       <Bool Name="Dynamic">true</Bool>
     </ParsedSelection>
index bc1d89ded767b8dec59c6b6cbdcb084fc4e6658f..4ad99dcb678ea7fd2e82958bf6b61e7c2e343753 100644 (file)
@@ -4,14 +4,12 @@
   <ParsedSelections Name="Parsed">
     <ParsedSelection Name="Selection1">
       <String Name="Input">same residue as (atomnr 3 5 13 or y &gt; 5)</String>
-      <String Name="Name">same residue as (atomnr 3 5 13 or y &gt; 5)</String>
       <String Name="Text">same residue as (atomnr 3 5 13 or y &gt; 5)</String>
       <Bool Name="Dynamic">true</Bool>
     </ParsedSelection>
     <ParsedSelection Name="Selection2">
-      <String Name="Input">(resnr 1 3 5 or x &gt; 10) and same residue as (atomnr 3 5 13 or y &gt; 5)</String>
-      <String Name="Name">(resnr 1 3 5 or x &gt; 10) and same residue as (atomnr 3 5 13 or y &gt; 5)</String>
-      <String Name="Text">(resnr 1 3 5 or x &gt; 10) and same residue as (atomnr 3 5 13 or y &gt; 5)</String>
+      <String Name="Input">(resnr 1 3 5 or x &gt; 10) and same residue as (atomnr 3 5 13 or z &gt; 5)</String>
+      <String Name="Text">(resnr 1 3 5 or x &gt; 10) and same residue as (atomnr 3 5 13 or z &gt; 5)</String>
       <Bool Name="Dynamic">true</Bool>
     </ParsedSelection>
   </ParsedSelections>
index 96aed6e9fc3c493a92ed60ade7f721c125309307..be2a3aefab3244d385b1c3e426e4bba2c197700d 100644 (file)
@@ -4,13 +4,11 @@
   <ParsedSelections Name="Parsed">
     <ParsedSelection Name="Selection1">
       <String Name="Input">name = S1 "C?"</String>
-      <String Name="Name">name = S1 "C?"</String>
       <String Name="Text">name = S1 "C?"</String>
       <Bool Name="Dynamic">false</Bool>
     </ParsedSelection>
     <ParsedSelection Name="Selection2">
       <String Name="Input">name ? S1 "C?"</String>
-      <String Name="Name">name ? S1 "C?"</String>
       <String Name="Text">name ? S1 "C?"</String>
       <Bool Name="Dynamic">false</Bool>
     </ParsedSelection>
index 14469a4d4a9e3ad977c94a9e9faebef7e863d03e..cc666aad5b901e2f02201a76e3ae8f2f81a9cef0 100644 (file)
@@ -4,13 +4,11 @@
   <ParsedSelections Name="Parsed">
     <ParsedSelection Name="Selection1">
       <String Name="Input">resname TP and not insolidangle center cog of resname C span resname R cutoff 20</String>
-      <String Name="Name">resname TP and not insolidangle center cog of resname C span resname R cutoff 20</String>
       <String Name="Text">resname TP and not insolidangle center cog of resname C span resname R cutoff 20</String>
       <Bool Name="Dynamic">true</Bool>
     </ParsedSelection>
     <ParsedSelection Name="Selection2">
       <String Name="Input">resname TN and insolidangle center cog of resname C span resname R cutoff 20</String>
-      <String Name="Name">resname TN and insolidangle center cog of resname C span resname R cutoff 20</String>
       <String Name="Text">resname TN and insolidangle center cog of resname C span resname R cutoff 20</String>
       <Bool Name="Dynamic">true</Bool>
     </ParsedSelection>
diff --git a/src/gromacs/selection/tests/refdata/SelectionCollectionDataTest_HandlesIndexGroupsInSelections.xml b/src/gromacs/selection/tests/refdata/SelectionCollectionDataTest_HandlesIndexGroupsInSelections.xml
new file mode 100644 (file)
index 0000000..9cd47b9
--- /dev/null
@@ -0,0 +1,74 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <ParsedSelections Name="Parsed">
+    <ParsedSelection Name="Selection1">
+      <String Name="Input">group "GrpA"</String>
+      <String Name="Name">GrpA</String>
+      <String Name="Text">group "GrpA"</String>
+      <Bool Name="Dynamic">false</Bool>
+    </ParsedSelection>
+    <ParsedSelection Name="Selection2">
+      <String Name="Input">GrpB</String>
+      <String Name="Name">GrpB</String>
+      <String Name="Text">GrpB</String>
+      <Bool Name="Dynamic">false</Bool>
+    </ParsedSelection>
+    <ParsedSelection Name="Selection3">
+      <String Name="Input">1</String>
+      <String Name="Name">GrpB</String>
+      <String Name="Text">1</String>
+      <Bool Name="Dynamic">false</Bool>
+    </ParsedSelection>
+    <ParsedSelection Name="Selection4">
+      <String Name="Input">group "GrpB" and resname RB</String>
+      <String Name="Name">group "GrpB" and resname RB</String>
+      <String Name="Text">group "GrpB" and resname RB</String>
+      <Bool Name="Dynamic">false</Bool>
+    </ParsedSelection>
+  </ParsedSelections>
+  <CompiledSelections Name="Compiled">
+    <Selection Name="Selection1">
+      <String Name="Name">GrpA</String>
+      <Sequence Name="Atoms">
+        <Int Name="Length">5</Int>
+        <Int>0</Int>
+        <Int>1</Int>
+        <Int>2</Int>
+        <Int>3</Int>
+        <Int>4</Int>
+      </Sequence>
+    </Selection>
+    <Selection Name="Selection2">
+      <String Name="Name">GrpB</String>
+      <Sequence Name="Atoms">
+        <Int Name="Length">5</Int>
+        <Int>3</Int>
+        <Int>4</Int>
+        <Int>5</Int>
+        <Int>6</Int>
+        <Int>7</Int>
+      </Sequence>
+    </Selection>
+    <Selection Name="Selection3">
+      <String Name="Name">GrpB</String>
+      <Sequence Name="Atoms">
+        <Int Name="Length">5</Int>
+        <Int>3</Int>
+        <Int>4</Int>
+        <Int>5</Int>
+        <Int>6</Int>
+        <Int>7</Int>
+      </Sequence>
+    </Selection>
+    <Selection Name="Selection4">
+      <String Name="Name">group "GrpB" and resname RB</String>
+      <Sequence Name="Atoms">
+        <Int Name="Length">3</Int>
+        <Int>3</Int>
+        <Int>4</Int>
+        <Int>5</Int>
+      </Sequence>
+    </Selection>
+  </CompiledSelections>
+</ReferenceData>
diff --git a/src/gromacs/selection/tests/refdata/SelectionCollectionDataTest_HandlesIndexGroupsInSelectionsDelayed.xml b/src/gromacs/selection/tests/refdata/SelectionCollectionDataTest_HandlesIndexGroupsInSelectionsDelayed.xml
new file mode 100644 (file)
index 0000000..b840304
--- /dev/null
@@ -0,0 +1,74 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <ParsedSelections Name="Parsed">
+    <ParsedSelection Name="Selection1">
+      <String Name="Input">group "GrpA"</String>
+      <String Name="Name"/>
+      <String Name="Text">group "GrpA"</String>
+      <Bool Name="Dynamic">false</Bool>
+    </ParsedSelection>
+    <ParsedSelection Name="Selection2">
+      <String Name="Input">GrpB</String>
+      <String Name="Name"/>
+      <String Name="Text">GrpB</String>
+      <Bool Name="Dynamic">false</Bool>
+    </ParsedSelection>
+    <ParsedSelection Name="Selection3">
+      <String Name="Input">1</String>
+      <String Name="Name"/>
+      <String Name="Text">1</String>
+      <Bool Name="Dynamic">false</Bool>
+    </ParsedSelection>
+    <ParsedSelection Name="Selection4">
+      <String Name="Input">group "GrpB" and resname RB</String>
+      <String Name="Name">group "GrpB" and resname RB</String>
+      <String Name="Text">group "GrpB" and resname RB</String>
+      <Bool Name="Dynamic">false</Bool>
+    </ParsedSelection>
+  </ParsedSelections>
+  <CompiledSelections Name="Compiled">
+    <Selection Name="Selection1">
+      <String Name="Name">GrpA</String>
+      <Sequence Name="Atoms">
+        <Int Name="Length">5</Int>
+        <Int>0</Int>
+        <Int>1</Int>
+        <Int>2</Int>
+        <Int>3</Int>
+        <Int>4</Int>
+      </Sequence>
+    </Selection>
+    <Selection Name="Selection2">
+      <String Name="Name">GrpB</String>
+      <Sequence Name="Atoms">
+        <Int Name="Length">5</Int>
+        <Int>3</Int>
+        <Int>4</Int>
+        <Int>5</Int>
+        <Int>6</Int>
+        <Int>7</Int>
+      </Sequence>
+    </Selection>
+    <Selection Name="Selection3">
+      <String Name="Name">GrpB</String>
+      <Sequence Name="Atoms">
+        <Int Name="Length">5</Int>
+        <Int>3</Int>
+        <Int>4</Int>
+        <Int>5</Int>
+        <Int>6</Int>
+        <Int>7</Int>
+      </Sequence>
+    </Selection>
+    <Selection Name="Selection4">
+      <String Name="Name">group "GrpB" and resname RB</String>
+      <Sequence Name="Atoms">
+        <Int Name="Length">3</Int>
+        <Int>3</Int>
+        <Int>4</Int>
+        <Int>5</Int>
+      </Sequence>
+    </Selection>
+  </CompiledSelections>
+</ReferenceData>
index 1f9c9d5e038549be2e603924a61cd2edf3e4c105..02a96c8cc98a85cd849417b57c926e0e1fbfa096 100644 (file)
@@ -4,13 +4,11 @@
   <ParsedSelections Name="Parsed">
     <ParsedSelection Name="Selection1">
       <String Name="Input">insertcode " "</String>
-      <String Name="Name">insertcode " "</String>
       <String Name="Text">insertcode " "</String>
       <Bool Name="Dynamic">false</Bool>
     </ParsedSelection>
     <ParsedSelection Name="Selection2">
       <String Name="Input">insertcode A</String>
-      <String Name="Name">insertcode A</String>
       <String Name="Text">insertcode A</String>
       <Bool Name="Dynamic">false</Bool>
     </ParsedSelection>
index 76b1e464fa12579762e71337357ea41e724fa534..fce3db2485c1fc386b6b108207bcad006286e0da 100644 (file)
@@ -4,7 +4,6 @@
   <ParsedSelections Name="Parsed">
     <ParsedSelection Name="Selection1">
       <String Name="Input">mass &gt; 5</String>
-      <String Name="Name">mass &gt; 5</String>
       <String Name="Text">mass &gt; 5</String>
       <Bool Name="Dynamic">false</Bool>
     </ParsedSelection>
index ebff377a2e54c665ed242a5aca267a477efddfc8..c6d5bddff89b486ee9765ee842bd80b5f5ae7b22 100644 (file)
@@ -4,19 +4,16 @@
   <ParsedSelections Name="Parsed">
     <ParsedSelection Name="Selection1">
       <String Name="Input">name S2 merge name S1</String>
-      <String Name="Name">name S2 merge name S1</String>
       <String Name="Text">name S2 merge name S1</String>
       <Bool Name="Dynamic">false</Bool>
     </ParsedSelection>
     <ParsedSelection Name="Selection2">
       <String Name="Input">resnr 1 2 and name S2 merge resnr 1 2 and name S1 merge res_cog of resnr 1 2</String>
-      <String Name="Name">resnr 1 2 and name S2 merge resnr 1 2 and name S1 merge res_cog of resnr 1 2</String>
       <String Name="Text">resnr 1 2 and name S2 merge resnr 1 2 and name S1 merge res_cog of resnr 1 2</String>
       <Bool Name="Dynamic">false</Bool>
     </ParsedSelection>
     <ParsedSelection Name="Selection3">
       <String Name="Input">name S1 and x &lt; 2.5 merge res_cog of x &lt; 2.5</String>
-      <String Name="Name">name S1 and x &lt; 2.5 merge res_cog of x &lt; 2.5</String>
       <String Name="Text">name S1 and x &lt; 2.5 merge res_cog of x &lt; 2.5</String>
       <Bool Name="Dynamic">true</Bool>
     </ParsedSelection>
index d5319f1c811b557f862fd0b64aa05b64cee0cdfa..b180d475e74364f78dbae29d08c648081b03adb4 100644 (file)
@@ -4,7 +4,6 @@
   <ParsedSelections Name="Parsed">
     <ParsedSelection Name="Selection1">
       <String Name="Input">mindistance from resnr 1 &lt; 2</String>
-      <String Name="Name">mindistance from resnr 1 &lt; 2</String>
       <String Name="Text">mindistance from resnr 1 &lt; 2</String>
       <Bool Name="Dynamic">true</Bool>
     </ParsedSelection>
diff --git a/src/gromacs/selection/tests/refdata/SelectionCollectionDataTest_HandlesMolIndex.xml b/src/gromacs/selection/tests/refdata/SelectionCollectionDataTest_HandlesMolIndex.xml
new file mode 100644 (file)
index 0000000..ab2195e
--- /dev/null
@@ -0,0 +1,43 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <ParsedSelections Name="Parsed">
+    <ParsedSelection Name="Selection1">
+      <String Name="Input">molindex 1 4</String>
+      <String Name="Text">molindex 1 4</String>
+      <Bool Name="Dynamic">false</Bool>
+    </ParsedSelection>
+    <ParsedSelection Name="Selection2">
+      <String Name="Input">molecule 2 3 5</String>
+      <String Name="Text">molecule 2 3 5</String>
+      <Bool Name="Dynamic">false</Bool>
+    </ParsedSelection>
+  </ParsedSelections>
+  <CompiledSelections Name="Compiled">
+    <Selection Name="Selection1">
+      <Sequence Name="Atoms">
+        <Int Name="Length">6</Int>
+        <Int>0</Int>
+        <Int>1</Int>
+        <Int>2</Int>
+        <Int>9</Int>
+        <Int>10</Int>
+        <Int>11</Int>
+      </Sequence>
+    </Selection>
+    <Selection Name="Selection2">
+      <Sequence Name="Atoms">
+        <Int Name="Length">9</Int>
+        <Int>3</Int>
+        <Int>4</Int>
+        <Int>5</Int>
+        <Int>6</Int>
+        <Int>7</Int>
+        <Int>8</Int>
+        <Int>12</Int>
+        <Int>13</Int>
+        <Int>14</Int>
+      </Sequence>
+    </Selection>
+  </CompiledSelections>
+</ReferenceData>
index 6d9a284fdb4d6587df94d246932682a795128920..ab04f31879e65df337df22830f2d0bb1cda67052 100644 (file)
@@ -4,31 +4,26 @@
   <ParsedSelections Name="Parsed">
     <ParsedSelection Name="Selection1">
       <String Name="Input">x &gt; 2</String>
-      <String Name="Name">x &gt; 2</String>
       <String Name="Text">x &gt; 2</String>
       <Bool Name="Dynamic">true</Bool>
     </ParsedSelection>
     <ParsedSelection Name="Selection2">
       <String Name="Input">2 &lt; x</String>
-      <String Name="Name">2 &lt; x</String>
       <String Name="Text">2 &lt; x</String>
       <Bool Name="Dynamic">true</Bool>
     </ParsedSelection>
     <ParsedSelection Name="Selection3">
       <String Name="Input">y &gt; resnr</String>
-      <String Name="Name">y &gt; resnr</String>
       <String Name="Text">y &gt; resnr</String>
       <Bool Name="Dynamic">true</Bool>
     </ParsedSelection>
     <ParsedSelection Name="Selection4">
       <String Name="Input">resnr &lt; 2.5</String>
-      <String Name="Name">resnr &lt; 2.5</String>
       <String Name="Text">resnr &lt; 2.5</String>
       <Bool Name="Dynamic">false</Bool>
     </ParsedSelection>
     <ParsedSelection Name="Selection5">
       <String Name="Input">2.5 &gt; resnr</String>
-      <String Name="Name">2.5 &gt; resnr</String>
       <String Name="Text">2.5 &gt; resnr</String>
       <Bool Name="Dynamic">false</Bool>
     </ParsedSelection>
index d37473a225a17f5cff8f64d7e27d76c03311165e..708af07b5486a5b6089ac6963da723b6591fbdb8 100644 (file)
     </ParsedVariable>
     <ParsedSelection Name="Selection1">
       <String Name="Input">resnr &lt; constint</String>
-      <String Name="Name">resnr &lt; constint</String>
       <String Name="Text">resnr &lt; constint</String>
       <Bool Name="Dynamic">false</Bool>
     </ParsedSelection>
     <ParsedSelection Name="Selection2">
       <String Name="Input">x + constreal1 &lt; constreal2</String>
-      <String Name="Name">x + constreal1 &lt; constreal2</String>
       <String Name="Text">x + constreal1 &lt; constreal2</String>
       <Bool Name="Dynamic">true</Bool>
     </ParsedSelection>
index 5d9f80f2bede8e9ca3787c09827adbd88a271352..db9d6065806389a691cc6f565a37c94644894230 100644 (file)
@@ -7,7 +7,6 @@
     </ParsedVariable>
     <ParsedSelection Name="Selection1">
       <String Name="Input">value &lt;= 4</String>
-      <String Name="Name">value &lt;= 4</String>
       <String Name="Text">value &lt;= 4</String>
       <Bool Name="Dynamic">true</Bool>
     </ParsedSelection>
@@ -16,7 +15,6 @@
     </ParsedVariable>
     <ParsedSelection Name="Selection2">
       <String Name="Input">index &lt; 3</String>
-      <String Name="Name">index &lt; 3</String>
       <String Name="Text">index &lt; 3</String>
       <Bool Name="Dynamic">false</Bool>
     </ParsedSelection>
index 9f0b91b5ed7f042b9d8b300c109a6a20180a0be4..5e463ab94d65e4926c103b5da3da0a6589a9f3cd 100644 (file)
@@ -4,13 +4,11 @@
   <ParsedSelections Name="Parsed">
     <ParsedSelection Name="Selection1">
       <String Name="Input">occupancy 1</String>
-      <String Name="Name">occupancy 1</String>
       <String Name="Text">occupancy 1</String>
       <Bool Name="Dynamic">false</Bool>
     </ParsedSelection>
     <ParsedSelection Name="Selection2">
       <String Name="Input">occupancy &lt; .5</String>
-      <String Name="Name">occupancy &lt; .5</String>
       <String Name="Text">occupancy &lt; .5</String>
       <Bool Name="Dynamic">false</Bool>
     </ParsedSelection>
index 8bfe632e79371c0a4a779c039669e4b0e59e1c54..a5b49d272b0991eb6189ad1364898fe066791ce9 100644 (file)
@@ -4,25 +4,21 @@
   <ParsedSelections Name="Parsed">
     <ParsedSelection Name="Selection1">
       <String Name="Input">name HG21</String>
-      <String Name="Name">name HG21</String>
       <String Name="Text">name HG21</String>
       <Bool Name="Dynamic">false</Bool>
     </ParsedSelection>
     <ParsedSelection Name="Selection2">
       <String Name="Input">name 1HG2</String>
-      <String Name="Name">name 1HG2</String>
       <String Name="Text">name 1HG2</String>
       <Bool Name="Dynamic">false</Bool>
     </ParsedSelection>
     <ParsedSelection Name="Selection3">
       <String Name="Input">pdbname HG21 CB</String>
-      <String Name="Name">pdbname HG21 CB</String>
       <String Name="Text">pdbname HG21 CB</String>
       <Bool Name="Dynamic">false</Bool>
     </ParsedSelection>
     <ParsedSelection Name="Selection4">
       <String Name="Input">pdbatomname 1HG2</String>
-      <String Name="Name">pdbatomname 1HG2</String>
       <String Name="Text">pdbatomname 1HG2</String>
       <Bool Name="Dynamic">false</Bool>
     </ParsedSelection>
index 261714b7eb5e17a720f49a57be56ba24703ce446..96e7de97dabb0453738c94bd6d50ada4afa6a993 100644 (file)
@@ -4,19 +4,16 @@
   <ParsedSelections Name="Parsed">
     <ParsedSelection Name="Selection1">
       <String Name="Input">all permute 3 1 2</String>
-      <String Name="Name">all permute 3 1 2</String>
       <String Name="Text">all permute 3 1 2</String>
       <Bool Name="Dynamic">false</Bool>
     </ParsedSelection>
     <ParsedSelection Name="Selection2">
       <String Name="Input">res_cog of resnr 1 to 4 permute 2 1</String>
-      <String Name="Name">res_cog of resnr 1 to 4 permute 2 1</String>
       <String Name="Text">res_cog of resnr 1 to 4 permute 2 1</String>
       <Bool Name="Dynamic">false</Bool>
     </ParsedSelection>
     <ParsedSelection Name="Selection3">
       <String Name="Input">name CB S1 and res_cog x &lt; 3 permute 2 1</String>
-      <String Name="Name">name CB S1 and res_cog x &lt; 3 permute 2 1</String>
       <String Name="Text">name CB S1 and res_cog x &lt; 3 permute 2 1</String>
       <Bool Name="Dynamic">true</Bool>
     </ParsedSelection>
index cd4c68f73c13ba8c1c4e518078e1b796f2d28a46..33f9ce241a77ed5200fd7624063d17b98ff6cf65 100644 (file)
@@ -4,19 +4,16 @@
   <ParsedSelections Name="Parsed">
     <ParsedSelection Name="Selection1">
       <String Name="Input">name S2 plus name S1</String>
-      <String Name="Name">name S2 plus name S1</String>
       <String Name="Text">name S2 plus name S1</String>
       <Bool Name="Dynamic">false</Bool>
     </ParsedSelection>
     <ParsedSelection Name="Selection2">
       <String Name="Input">res_cog of resnr 2 plus res_cog of resnr 1 plus res_cog of resnr 3</String>
-      <String Name="Name">res_cog of resnr 2 plus res_cog of resnr 1 plus res_cog of resnr 3</String>
       <String Name="Text">res_cog of resnr 2 plus res_cog of resnr 1 plus res_cog of resnr 3</String>
       <Bool Name="Dynamic">false</Bool>
     </ParsedSelection>
     <ParsedSelection Name="Selection3">
       <String Name="Input">name S1 and y &lt; 3 plus res_cog of x &lt; 2.5</String>
-      <String Name="Name">name S1 and y &lt; 3 plus res_cog of x &lt; 2.5</String>
       <String Name="Text">name S1 and y &lt; 3 plus res_cog of x &lt; 2.5</String>
       <Bool Name="Dynamic">true</Bool>
     </ParsedSelection>
index e6fb1a3b1de7bdbbbf6644b0a162ecd1df17ba8e..1b28c44f218f46b4edf392703273e22b161e5099 100644 (file)
@@ -4,31 +4,26 @@
   <ParsedSelections Name="Parsed">
     <ParsedSelection Name="Selection1">
       <String Name="Input">cog of resnr 1 3</String>
-      <String Name="Name">cog of resnr 1 3</String>
       <String Name="Text">cog of resnr 1 3</String>
       <Bool Name="Dynamic">false</Bool>
     </ParsedSelection>
     <ParsedSelection Name="Selection2">
       <String Name="Input">res_cog of name CB and resnr 1 3</String>
-      <String Name="Name">res_cog of name CB and resnr 1 3</String>
       <String Name="Text">res_cog of name CB and resnr 1 3</String>
       <Bool Name="Dynamic">false</Bool>
     </ParsedSelection>
     <ParsedSelection Name="Selection3">
       <String Name="Input">whole_res_cog of name CB and resnr 1 3</String>
-      <String Name="Name">whole_res_cog of name CB and resnr 1 3</String>
       <String Name="Text">whole_res_cog of name CB and resnr 1 3</String>
       <Bool Name="Dynamic">false</Bool>
     </ParsedSelection>
     <ParsedSelection Name="Selection4">
       <String Name="Input">part_res_cog of x &lt; 3</String>
-      <String Name="Name">part_res_cog of x &lt; 3</String>
       <String Name="Text">part_res_cog of x &lt; 3</String>
       <Bool Name="Dynamic">true</Bool>
     </ParsedSelection>
     <ParsedSelection Name="Selection5">
       <String Name="Input">dyn_res_cog of x &lt; 3</String>
-      <String Name="Name">dyn_res_cog of x &lt; 3</String>
       <String Name="Text">dyn_res_cog of x &lt; 3</String>
       <Bool Name="Dynamic">true</Bool>
     </ParsedSelection>
index a77d3ea633f1b85842b6fb9bf594212a38848904..683c076c265f345b810aad6d7a26839bb53f4e63 100644 (file)
@@ -7,13 +7,11 @@
     </ParsedVariable>
     <ParsedSelection Name="Selection1">
       <String Name="Input">foo</String>
-      <String Name="Name">foo</String>
       <String Name="Text">foo</String>
       <Bool Name="Dynamic">false</Bool>
     </ParsedSelection>
     <ParsedSelection Name="Selection2">
       <String Name="Input">within 1 of foo</String>
-      <String Name="Name">within 1 of foo</String>
       <String Name="Text">within 1 of foo</String>
       <Bool Name="Dynamic">true</Bool>
     </ParsedSelection>
     </ParsedVariable>
     <ParsedSelection Name="Selection3">
       <String Name="Input">bar</String>
-      <String Name="Name">bar</String>
       <String Name="Text">bar</String>
       <Bool Name="Dynamic">false</Bool>
     </ParsedSelection>
     <ParsedSelection Name="Selection4">
       <String Name="Input">within 1 of bar</String>
-      <String Name="Name">within 1 of bar</String>
       <String Name="Text">within 1 of bar</String>
       <Bool Name="Dynamic">true</Bool>
     </ParsedSelection>
index ce4d40c5e8518170372d227f0d82afd62ae10173..ca65954321007e72dbd0205317e9f07b172aa5d6 100644 (file)
@@ -4,13 +4,11 @@
   <ParsedSelections Name="Parsed">
     <ParsedSelection Name="Selection1">
       <String Name="Input">resname "R[BD]"</String>
-      <String Name="Name">resname "R[BD]"</String>
       <String Name="Text">resname "R[BD]"</String>
       <Bool Name="Dynamic">false</Bool>
     </ParsedSelection>
     <ParsedSelection Name="Selection2">
       <String Name="Input">resname ~ "R[BD]"</String>
-      <String Name="Name">resname ~ "R[BD]"</String>
       <String Name="Text">resname ~ "R[BD]"</String>
       <Bool Name="Dynamic">false</Bool>
     </ParsedSelection>
index 5351607e59174b243f8bbb5ab2c333574af81db4..f5a5a0303905368f0e077bae05032de5a1a0fac4 100644 (file)
@@ -4,13 +4,11 @@
   <ParsedSelections Name="Parsed">
     <ParsedSelection Name="Selection1">
       <String Name="Input">resindex 1 4</String>
-      <String Name="Name">resindex 1 4</String>
       <String Name="Text">resindex 1 4</String>
       <Bool Name="Dynamic">false</Bool>
     </ParsedSelection>
     <ParsedSelection Name="Selection2">
       <String Name="Input">residue 1 3</String>
-      <String Name="Name">residue 1 3</String>
       <String Name="Text">residue 1 3</String>
       <Bool Name="Dynamic">false</Bool>
     </ParsedSelection>
index 723e96aa4669ddce5be0caec68d9339095d89e1b..9721232f7b5a9c91c6856f569567cbc4d9e46a34 100644 (file)
@@ -4,13 +4,11 @@
   <ParsedSelections Name="Parsed">
     <ParsedSelection Name="Selection1">
       <String Name="Input">resname RA</String>
-      <String Name="Name">resname RA</String>
       <String Name="Text">resname RA</String>
       <Bool Name="Dynamic">false</Bool>
     </ParsedSelection>
     <ParsedSelection Name="Selection2">
       <String Name="Input">resname RB RC</String>
-      <String Name="Name">resname RB RC</String>
       <String Name="Text">resname RB RC</String>
       <Bool Name="Dynamic">false</Bool>
     </ParsedSelection>
index d44e6b351275787543846da87548229e87250f0c..7ef039bb79c1a5641289f5a9a642719e55255121 100644 (file)
@@ -4,13 +4,11 @@
   <ParsedSelections Name="Parsed">
     <ParsedSelection Name="Selection1">
       <String Name="Input">resnr 1 2 5</String>
-      <String Name="Name">resnr 1 2 5</String>
       <String Name="Text">resnr 1 2 5</String>
       <Bool Name="Dynamic">false</Bool>
     </ParsedSelection>
     <ParsedSelection Name="Selection2">
       <String Name="Input">resid 4 to 3</String>
-      <String Name="Name">resid 4 to 3</String>
       <String Name="Text">resid 4 to 3</String>
       <Bool Name="Dynamic">false</Bool>
     </ParsedSelection>
index 266440711287d5c6db93149656946b974834518c..c065526f163c2bc658edbf531ebee3f7a19e5e60 100644 (file)
@@ -4,7 +4,6 @@
   <ParsedSelections Name="Parsed">
     <ParsedSelection Name="Selection1">
       <String Name="Input">same residue as atomnr 1 4 12</String>
-      <String Name="Name">same residue as atomnr 1 4 12</String>
       <String Name="Text">same residue as atomnr 1 4 12</String>
       <Bool Name="Dynamic">false</Bool>
     </ParsedSelection>
index 5d398352e15d09387f3951767b3931e2820e61ab..7798e0db9d5fbc8239cacc33b6065560e29a9923 100644 (file)
@@ -4,7 +4,6 @@
   <ParsedSelections Name="Parsed">
     <ParsedSelection Name="Selection1">
       <String Name="Input">same resname as atomnr 1 14</String>
-      <String Name="Name">same resname as atomnr 1 14</String>
       <String Name="Text">same resname as atomnr 1 14</String>
       <Bool Name="Dynamic">false</Bool>
     </ParsedSelection>
diff --git a/src/gromacs/selection/tests/refdata/SelectionCollectionDataTest_HandlesSelectionNames.xml b/src/gromacs/selection/tests/refdata/SelectionCollectionDataTest_HandlesSelectionNames.xml
new file mode 100644 (file)
index 0000000..b1c43e5
--- /dev/null
@@ -0,0 +1,69 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <ParsedSelections Name="Parsed">
+    <ParsedSelection Name="Selection1">
+      <String Name="Input">"GroupSelection" group "GrpA"</String>
+      <String Name="Name">GroupSelection</String>
+      <String Name="Text">"GroupSelection" group "GrpA"</String>
+      <Bool Name="Dynamic">false</Bool>
+    </ParsedSelection>
+    <ParsedSelection Name="Selection2">
+      <String Name="Input">"DynamicSelection" x &lt; 5</String>
+      <String Name="Name">DynamicSelection</String>
+      <String Name="Text">"DynamicSelection" x &lt; 5</String>
+      <Bool Name="Dynamic">true</Bool>
+    </ParsedSelection>
+    <ParsedSelection Name="Selection3">
+      <String Name="Input">y &lt; 3</String>
+      <String Name="Name">y &lt; 3</String>
+      <String Name="Text">y &lt; 3</String>
+      <Bool Name="Dynamic">true</Bool>
+    </ParsedSelection>
+  </ParsedSelections>
+  <CompiledSelections Name="Compiled">
+    <Selection Name="Selection1">
+      <String Name="Name">GroupSelection</String>
+      <Sequence Name="Atoms">
+        <Int Name="Length">5</Int>
+        <Int>0</Int>
+        <Int>1</Int>
+        <Int>2</Int>
+        <Int>3</Int>
+        <Int>4</Int>
+      </Sequence>
+    </Selection>
+    <Selection Name="Selection2">
+      <String Name="Name">DynamicSelection</String>
+      <Sequence Name="Atoms">
+        <Int Name="Length">10</Int>
+        <Int>0</Int>
+        <Int>1</Int>
+        <Int>2</Int>
+        <Int>3</Int>
+        <Int>4</Int>
+        <Int>5</Int>
+        <Int>6</Int>
+        <Int>7</Int>
+        <Int>8</Int>
+        <Int>9</Int>
+      </Sequence>
+    </Selection>
+    <Selection Name="Selection3">
+      <String Name="Name">y &lt; 3</String>
+      <Sequence Name="Atoms">
+        <Int Name="Length">10</Int>
+        <Int>0</Int>
+        <Int>1</Int>
+        <Int>2</Int>
+        <Int>3</Int>
+        <Int>4</Int>
+        <Int>5</Int>
+        <Int>6</Int>
+        <Int>7</Int>
+        <Int>8</Int>
+        <Int>9</Int>
+      </Sequence>
+    </Selection>
+  </CompiledSelections>
+</ReferenceData>
index 2463037dfe7b1a2703b3bab0aa1a61620c7ea02e..8b8ca0518c039a68b6e2ba4096036ab512a19801 100644 (file)
@@ -10,7 +10,6 @@
     </ParsedVariable>
     <ParsedSelection Name="Selection1">
       <String Name="Input">atomnr 1 to 6 and foo</String>
-      <String Name="Name">atomnr 1 to 6 and foo</String>
       <String Name="Text">atomnr 1 to 6 and foo</String>
       <Bool Name="Dynamic">false</Bool>
     </ParsedSelection>
index 598cd21e25feb1771259101e34cfd1a41681be9d..20ae1d36b387c7c345c4fcef9e48c137fd482c11 100644 (file)
@@ -7,19 +7,16 @@
     </ParsedVariable>
     <ParsedSelection Name="Selection1">
       <String Name="Input">atomnr 1 to 6 and foo</String>
-      <String Name="Name">atomnr 1 to 6 and foo</String>
       <String Name="Text">atomnr 1 to 6 and foo</String>
       <Bool Name="Dynamic">true</Bool>
     </ParsedSelection>
     <ParsedSelection Name="Selection2">
       <String Name="Input">within 1 of foo</String>
-      <String Name="Name">within 1 of foo</String>
       <String Name="Text">within 1 of foo</String>
       <Bool Name="Dynamic">true</Bool>
     </ParsedSelection>
     <ParsedSelection Name="Selection3">
       <String Name="Input">foo</String>
-      <String Name="Name">foo</String>
       <String Name="Text">foo</String>
       <Bool Name="Dynamic">true</Bool>
     </ParsedSelection>
index 46be47d1abbb21fd495b2bcbc6a2a3c3cbc2d139..5f7109555edf67ca00a9f720f2f9249830156492 100644 (file)
@@ -7,13 +7,11 @@
     </ParsedVariable>
     <ParsedSelection Name="Selection1">
       <String Name="Input">atomnr 1 to 5 and y &lt; 10 and foo</String>
-      <String Name="Name">atomnr 1 to 5 and y &lt; 10 and foo</String>
       <String Name="Text">atomnr 1 to 5 and y &lt; 10 and foo</String>
       <Bool Name="Dynamic">true</Bool>
     </ParsedSelection>
     <ParsedSelection Name="Selection2">
       <String Name="Input">foo</String>
-      <String Name="Name">foo</String>
       <String Name="Text">foo</String>
       <Bool Name="Dynamic">true</Bool>
     </ParsedSelection>
index 41537e0c6876583d3117292380a73e188970190b..b382cf5d7d2e2120b3bc4f55fbad4cf0617d51f9 100644 (file)
@@ -7,13 +7,11 @@
     </ParsedVariable>
     <ParsedSelection Name="Selection1">
       <String Name="Input">atomnr 1 to 5 and foo</String>
-      <String Name="Name">atomnr 1 to 5 and foo</String>
       <String Name="Text">atomnr 1 to 5 and foo</String>
       <Bool Name="Dynamic">true</Bool>
     </ParsedSelection>
     <ParsedSelection Name="Selection2">
       <String Name="Input">atomnr 3 to 7 and foo</String>
-      <String Name="Name">atomnr 3 to 7 and foo</String>
       <String Name="Text">atomnr 3 to 7 and foo</String>
       <Bool Name="Dynamic">true</Bool>
     </ParsedSelection>
index 9c19c9f0b8c52dcbb24595baaf6333a0a5c4d4d7..8c1ab7af40ea820a586e5d500b8b524becf4983d 100644 (file)
@@ -4,13 +4,11 @@
   <ParsedSelections Name="Parsed">
     <ParsedSelection Name="Selection1">
       <String Name="Input">name "S?"</String>
-      <String Name="Name">name "S?"</String>
       <String Name="Text">name "S?"</String>
       <Bool Name="Dynamic">false</Bool>
     </ParsedSelection>
     <ParsedSelection Name="Selection2">
       <String Name="Input">name ? "S?"</String>
-      <String Name="Name">name ? "S?"</String>
       <String Name="Text">name ? "S?"</String>
       <Bool Name="Dynamic">false</Bool>
     </ParsedSelection>
index 3d621c380a0ebe055519706d4b2fca9a36b25d14..03a24afe2c4d442d0af39ab3704d6c40aa17bb71 100644 (file)
@@ -4,7 +4,6 @@
   <ParsedSelections Name="Parsed">
     <ParsedSelection Name="Selection1">
       <String Name="Input">within 1 of [2, 1, 0]</String>
-      <String Name="Name">within 1 of [2, 1, 0]</String>
       <String Name="Text">within 1 of [2, 1, 0]</String>
       <Bool Name="Dynamic">true</Bool>
     </ParsedSelection>
index 194c56cde0f97a0eead65d38bdeb61555b7ead22..789876618b25d65d21228ac5cc36c4c968a37a3b 100644 (file)
@@ -4,7 +4,6 @@
   <ParsedSelections Name="Parsed">
     <ParsedSelection Name="Selection1">
       <String Name="Input">within 1 of resnr 2</String>
-      <String Name="Name">within 1 of resnr 2</String>
       <String Name="Text">within 1 of resnr 2</String>
       <Bool Name="Dynamic">true</Bool>
     </ParsedSelection>
index 5f6cb924d267b745064a2cea77f589b965149baf..5c4cb5fedf1c08fb920c6c8626a0bb2df8a65e93 100644 (file)
         <tr>
             <th/>
             <th>Input</th>
-            <th>Name</th>
+            <xsl:if test="*/String[@Name='Name']">
+                <th>Name</th>
+            </xsl:if>
             <th>Text</th>
             <th>Dynamic</th>
         </tr>
         <tr>
             <td><xsl:value-of select="@Name"/></td>
             <td><xsl:value-of select="String[@Name='Input']"/></td>
-            <td><xsl:value-of select="String[@Name='Name']"/></td>
+            <xsl:if test="String[@Name='Name']">
+                <td><xsl:value-of select="String[@Name='Name']"/></td>
+            </xsl:if>
             <td><xsl:value-of select="String[@Name='Text']"/></td>
             <td><xsl:value-of select="Bool[@Name='Dynamic']"/></td>
         </tr>
 
 <xsl:template match="Selection">
     <h3><xsl:value-of select="@Name"/></h3>
-    <p>
-        Selection text:<br/>
-        <xsl:value-of select="key('SelectionName', @Name)/String[@Name='Text']"/>
-    </p>
-    <xsl:apply-templates />
-</xsl:template>
-
-<xsl:template match="Selection/Sequence[@Name='Atoms']">
-    <p>
-        Atoms:
-        <xsl:call-template name="SequenceAsHorizontalTable"/>
-    </p>
+    <table>
+        <xsl:if test="String[@Name='Name']">
+            <tr>
+                <td>Name:</td>
+                <td><xsl:value-of select="String[@Name='Name']"/></td>
+            </tr>
+        </xsl:if>
+        <tr>
+            <td>Selection text:</td>
+            <td>
+                <xsl:value-of select="key('SelectionName', @Name)/String[@Name='Text']"/>
+            </td>
+        </tr>
+        <xsl:if test="Sequence[@Name='Atoms']">
+            <tr>
+                <td>Atoms (<xsl:value-of select="Sequence[@Name='Atoms']/Int[@Name='Length']"/>):</td>
+                <td>
+                    <xsl:call-template name="SequenceAsCSV">
+                        <xsl:with-param name="root" select="Sequence[@Name='Atoms']"/>
+                    </xsl:call-template>
+                </td>
+            </tr>
+        </xsl:if>
+    </table>
+    <xsl:apply-templates select="Sequence[@Name='Positions']"/>
 </xsl:template>
 
 <xsl:template match="Selection/Sequence[@Name='Positions']">
index 32caba123cac5ae61d415f29540b5e48a23953c1..ffa1b914107179885b2edfb20eb1643c18536ab7 100644 (file)
@@ -43,6 +43,7 @@
 
 #include "gromacs/options/basicoptions.h"
 #include "gromacs/options/options.h"
+#include "gromacs/selection/indexutil.h"
 #include "gromacs/selection/selectioncollection.h"
 #include "gromacs/selection/selection.h"
 #include "gromacs/utility/exceptions.h"
@@ -67,38 +68,38 @@ namespace
 class SelectionCollectionTest : public ::testing::Test
 {
     public:
-        static void SetUpTestCase();
-
         static int               s_debugLevel;
 
         SelectionCollectionTest();
+        ~SelectionCollectionTest();
 
         void setAtomCount(int natoms)
         {
             ASSERT_NO_THROW_GMX(sc_.setTopology(NULL, natoms));
         }
         void loadTopology(const char *filename);
+        void setTopology();
+        void loadIndexGroups(const char *filename);
 
-        gmx::SelectionCollection sc_;
-        gmx::SelectionList       sel_;
-        t_topology              *top_;
-        t_trxframe              *frame_;
-
-    private:
         gmx::test::TopologyManager  topManager_;
+        gmx::SelectionCollection    sc_;
+        gmx::SelectionList          sel_;
+        t_topology                 *top_;
+        t_trxframe                 *frame_;
+        gmx_ana_indexgrps_t        *grps_;
 };
 
 int SelectionCollectionTest::s_debugLevel = 0;
 
-void SelectionCollectionTest::SetUpTestCase()
+GMX_TEST_OPTIONS(SelectionCollectionTestOptions, options)
 {
-    gmx::Options options(NULL, NULL);
-    options.addOption(gmx::IntegerOption("seldebug").store(&s_debugLevel));
-    gmx::test::parseTestOptions(&options);
+    options->addOption(gmx::IntegerOption("seldebug")
+                           .store(&SelectionCollectionTest::s_debugLevel)
+                           .description("Set selection debug level"));
 }
 
 SelectionCollectionTest::SelectionCollectionTest()
-    : top_(NULL), frame_(NULL)
+    : top_(NULL), frame_(NULL), grps_(NULL)
 {
     topManager_.requestFrame();
     sc_.setDebugLevel(s_debugLevel);
@@ -106,16 +107,41 @@ SelectionCollectionTest::SelectionCollectionTest()
     sc_.setOutputPosType("atom");
 }
 
+SelectionCollectionTest::~SelectionCollectionTest()
+{
+    if (grps_ != NULL)
+    {
+        gmx_ana_indexgrps_free(grps_);
+    }
+}
+
 void
 SelectionCollectionTest::loadTopology(const char *filename)
 {
     topManager_.loadTopology(filename);
+    setTopology();
+}
+
+void
+SelectionCollectionTest::setTopology()
+{
     top_   = topManager_.topology();
     frame_ = topManager_.frame();
 
     ASSERT_NO_THROW_GMX(sc_.setTopology(top_, -1));
 }
 
+void
+SelectionCollectionTest::loadIndexGroups(const char *filename)
+{
+    GMX_RELEASE_ASSERT(grps_ == NULL,
+                       "External groups can only be loaded once");
+    std::string fullpath =
+        gmx::test::TestFileManager::getInputFilePath(filename);
+    gmx_ana_indexgrps_init(&grps_, NULL, fullpath.c_str());
+    sc_.setIndexGroups(grps_);
+}
+
 
 /********************************************************************
  * Test fixture for selection testing with reference data
@@ -132,6 +158,7 @@ class SelectionCollectionDataTest : public SelectionCollectionTest
             efTestPositionMapping       = 1<<3,
             efTestPositionMasses        = 1<<4,
             efTestPositionCharges       = 1<<5,
+            efTestSelectionNames        = 1<<6,
             efDontTestCompiledAtoms     = 1<<8
         };
         typedef gmx::FlagsTemplate<TestFlag> TestFlags;
@@ -263,7 +290,10 @@ SelectionCollectionDataTest::runParser(const char *const *selections,
             TestReferenceChecker selcompound(
                     compound.checkCompound("ParsedSelection", id.c_str()));
             selcompound.checkString(selections[i], "Input");
-            selcompound.checkString(sel_[count_].name(), "Name");
+            if (flags_.test(efTestSelectionNames))
+            {
+                selcompound.checkString(sel_[count_].name(), "Name");
+            }
             selcompound.checkString(sel_[count_].selectionText(), "Text");
             selcompound.checkBoolean(sel_[count_].isDynamic(), "Dynamic");
             ++count_;
@@ -295,6 +325,10 @@ SelectionCollectionDataTest::checkCompiled()
         std::string          id = gmx::formatString("Selection%d", static_cast<int>(i + 1));
         TestReferenceChecker selcompound(
                 compound.checkCompound("Selection", id.c_str()));
+        if (flags_.test(efTestSelectionNames))
+        {
+            selcompound.checkString(sel_[i].name(), "Name");
+        }
         if (!flags_.test(efDontTestCompiledAtoms))
         {
             checkSelection(&selcompound, sel_[i], flags_ & mask);
@@ -442,11 +476,48 @@ TEST_F(SelectionCollectionTest, HandlesHelpKeywordInInvalidContext)
 
 // TODO: Tests for more parser errors
 
-TEST_F(SelectionCollectionTest, RecoversFromUnknownGroupReference)
+TEST_F(SelectionCollectionTest, HandlesUnknownGroupReferenceParser1)
+{
+    ASSERT_NO_THROW_GMX(sc_.setIndexGroups(NULL));
+    EXPECT_THROW_GMX(sc_.parseFromString("group \"foo\""), gmx::InconsistentInputError);
+    EXPECT_THROW_GMX(sc_.parseFromString("4"), gmx::InconsistentInputError);
+}
+
+TEST_F(SelectionCollectionTest, HandlesUnknownGroupReferenceParser2)
+{
+    ASSERT_NO_THROW_GMX(loadIndexGroups("simple.ndx"));
+    EXPECT_THROW_GMX(sc_.parseFromString("group \"foo\""), gmx::InconsistentInputError);
+    EXPECT_THROW_GMX(sc_.parseFromString("4"), gmx::InconsistentInputError);
+}
+
+TEST_F(SelectionCollectionTest, HandlesUnknownGroupReferenceDelayed1)
 {
     ASSERT_NO_THROW_GMX(sc_.parseFromString("group \"foo\""));
     ASSERT_NO_FATAL_FAILURE(setAtomCount(10));
-    EXPECT_THROW_GMX(sc_.setIndexGroups(NULL), gmx::InvalidInputError);
+    EXPECT_THROW_GMX(sc_.setIndexGroups(NULL), gmx::InconsistentInputError);
+    EXPECT_THROW_GMX(sc_.compile(), gmx::APIError);
+}
+
+TEST_F(SelectionCollectionTest, HandlesUnknownGroupReferenceDelayed2)
+{
+    ASSERT_NO_THROW_GMX(sc_.parseFromString("group 4; group \"foo\""));
+    ASSERT_NO_FATAL_FAILURE(setAtomCount(10));
+    EXPECT_THROW_GMX(loadIndexGroups("simple.ndx"), gmx::InconsistentInputError);
+    EXPECT_THROW_GMX(sc_.compile(), gmx::APIError);
+}
+
+TEST_F(SelectionCollectionTest, HandlesUnsortedGroupReference)
+{
+    ASSERT_NO_THROW_GMX(loadIndexGroups("simple.ndx"));
+    EXPECT_THROW_GMX(sc_.parseFromString("group \"GrpUnsorted\""),
+                     gmx::InconsistentInputError);
+    EXPECT_THROW_GMX(sc_.parseFromString("2"), gmx::InconsistentInputError);
+}
+
+TEST_F(SelectionCollectionTest, HandlesUnsortedGroupReferenceDelayed)
+{
+    ASSERT_NO_THROW_GMX(sc_.parseFromString("group 2; group \"GrpUnsorted\""));
+    EXPECT_THROW_GMX(loadIndexGroups("simple.ndx"), gmx::InconsistentInputError);
     EXPECT_THROW_GMX(sc_.compile(), gmx::APIError);
 }
 
@@ -537,7 +608,17 @@ TEST_F(SelectionCollectionDataTest, HandlesResIndex)
     runTest("simple.pdb", selections);
 }
 
-// TODO: Add test for "molindex"
+TEST_F(SelectionCollectionDataTest, HandlesMolIndex)
+{
+    static const char * const selections[] = {
+        "molindex 1 4",
+        "molecule 2 3 5"
+    };
+    ASSERT_NO_FATAL_FAILURE(runParser(selections));
+    ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
+    topManager_.initUniformMolecules(3);
+    ASSERT_NO_FATAL_FAILURE(runCompiler());
+}
 
 TEST_F(SelectionCollectionDataTest, HandlesAtomname)
 {
@@ -559,7 +640,18 @@ TEST_F(SelectionCollectionDataTest, HandlesPdbAtomname)
     runTest("simple.pdb", selections);
 }
 
-// TODO: Add test for atomtype
+
+TEST_F(SelectionCollectionDataTest, HandlesAtomtype)
+{
+    static const char * const selections[] = {
+        "atomtype CA"
+    };
+    ASSERT_NO_FATAL_FAILURE(runParser(selections));
+    ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
+    const char *const types[] = { "CA", "SA", "SB" };
+    topManager_.initAtomTypes(types);
+    ASSERT_NO_FATAL_FAILURE(runCompiler());
+}
 
 TEST_F(SelectionCollectionDataTest, HandlesChain)
 {
@@ -811,6 +903,46 @@ TEST_F(SelectionCollectionDataTest, ComputesMassesAndChargesWithoutTopology)
  * Tests for selection syntactic constructs
  */
 
+TEST_F(SelectionCollectionDataTest, HandlesSelectionNames)
+{
+    static const char * const selections[] = {
+        "\"GroupSelection\" group \"GrpA\"",
+        "\"DynamicSelection\" x < 5",
+        "y < 3"
+    };
+    setFlags(TestFlags() | efTestSelectionNames);
+    ASSERT_NO_THROW_GMX(loadIndexGroups("simple.ndx"));
+    runTest(10, selections);
+}
+
+TEST_F(SelectionCollectionDataTest, HandlesIndexGroupsInSelections)
+{
+    static const char * const selections[] = {
+        "group \"GrpA\"",
+        "GrpB",
+        "1",
+        "group \"GrpB\" and resname RB"
+    };
+    setFlags(TestFlags() | efTestSelectionNames);
+    ASSERT_NO_THROW_GMX(loadIndexGroups("simple.ndx"));
+    runTest("simple.gro", selections);
+}
+
+TEST_F(SelectionCollectionDataTest, HandlesIndexGroupsInSelectionsDelayed)
+{
+    static const char * const selections[] = {
+        "group \"GrpA\"",
+        "GrpB",
+        "1",
+        "group \"GrpB\" and resname RB"
+    };
+    setFlags(TestFlags() | efTestSelectionNames);
+    ASSERT_NO_FATAL_FAILURE(runParser(selections));
+    ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
+    ASSERT_NO_THROW_GMX(loadIndexGroups("simple.ndx"));
+    ASSERT_NO_FATAL_FAILURE(runCompiler());
+}
+
 TEST_F(SelectionCollectionDataTest, HandlesConstantPositions)
 {
     static const char * const selections[] = {
@@ -881,7 +1013,7 @@ TEST_F(SelectionCollectionDataTest, HandlesDynamicAtomValuedParameters)
 {
     static const char * const selections[] = {
         "same residue as (atomnr 3 5 13 or y > 5)",
-        "(resnr 1 3 5 or x > 10) and same residue as (atomnr 3 5 13 or y > 5)"
+        "(resnr 1 3 5 or x > 10) and same residue as (atomnr 3 5 13 or z > 5)"
     };
     setFlags(TestFlags() | efTestEvaluation);
     runTest("simple.gro", selections);
diff --git a/src/gromacs/selection/tests/simple.ndx b/src/gromacs/selection/tests/simple.ndx
new file mode 100644 (file)
index 0000000..4ca7873
--- /dev/null
@@ -0,0 +1,8 @@
+[ GrpA ]
+1 2 3 4 5
+
+[ GrpB ]
+4 5 6 7 8
+
+[ GrpUnsorted ]
+1 2 4 3 2
index c75e95ef2145415c7d90c791267b5f71645f67b1..36e8c97e9dc5c0f6952d9ebe9354491d95a2942b 100644 (file)
@@ -45,6 +45,7 @@
 
 #include "gromacs/legacyheaders/smalloc.h"
 #include "gromacs/legacyheaders/statutil.h"
+#include "gromacs/legacyheaders/string2.h"
 #include "gromacs/legacyheaders/tpxio.h"
 #include "gromacs/legacyheaders/typedefs.h"
 #include "gromacs/legacyheaders/vec.h"
@@ -166,6 +167,25 @@ void TopologyManager::initAtoms(int count)
     }
 }
 
+void TopologyManager::initAtomTypes(int count, const char *const types[])
+{
+    GMX_RELEASE_ASSERT(top_ != NULL, "Topology not initialized");
+    atomtypes_.reserve(count);
+    for (int i = 0; i < count; ++i)
+    {
+        atomtypes_.push_back(strdup(types[i]));
+    }
+    snew(top_->atoms.atomtype, top_->atoms.nr);
+    for (int i = 0, j = 0; i < top_->atoms.nr; ++i, ++j)
+    {
+        if (j == count)
+        {
+            j = 0;
+        }
+        top_->atoms.atomtype[i] = &atomtypes_[j];
+    }
+}
+
 void TopologyManager::initUniformResidues(int residueSize)
 {
     GMX_RELEASE_ASSERT(top_ != NULL, "Topology not initialized");
index 893cbc206fe6fe05505012a72c53e8b10baac256..a778bbd72c213eb8f46302c5ece7c1074e3f40b8 100644 (file)
@@ -42,6 +42,8 @@
 #ifndef GMX_SELECTION_TESTS_TOPUTILS_H
 #define GMX_SELECTION_TESTS_TOPUTILS_H
 
+#include <vector>
+
 #include "gromacs/legacyheaders/typedefs.h"
 
 namespace gmx
@@ -61,6 +63,12 @@ class TopologyManager
 
         void loadTopology(const char *filename);
         void initAtoms(int count);
+        void initAtomTypes(int count, const char *const types[]);
+        template <int count>
+        void initAtomTypes(const char *const (&types)[count])
+        {
+            initAtomTypes(count, types);
+        }
         void initUniformResidues(int residueSize);
         void initUniformMolecules(int moleculeSize);
 
@@ -68,8 +76,9 @@ class TopologyManager
         t_trxframe *frame() { return frame_; }
 
     private:
-        t_topology *top_;
-        t_trxframe *frame_;
+        t_topology             *top_;
+        t_trxframe             *frame_;
+        std::vector<char *>     atomtypes_;
 };
 
 } // namespace test
index 6e35c2d7d7cbb3a6d4b762ee96fe7aa864f32c63..c18667934fbe4fa8d4137f00c9af35ccbedfaca5 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2010,2011,2012, by the GROMACS development team, led by
+ * Copyright (c) 2010,2011,2012,2013, 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.
@@ -338,6 +338,7 @@ AbstractAnalysisData &TrajectoryAnalysisModule::datasetFromName(const char *name
 void TrajectoryAnalysisModule::registerBasicDataset(AbstractAnalysisData *data,
                                                     const char           *name)
 {
+    GMX_RELEASE_ASSERT(data != NULL, "Attempting to register NULL data");
     // TODO: Strong exception safety should be possible to implement.
     GMX_RELEASE_ASSERT(impl_->datasets_.find(name) == impl_->datasets_.end(),
                        "Duplicate data set name registered");
index 569a0a0cdff72efb425e558a949e7de37b594d96..b40188071387ef3fc34b47b418e1c3a23187da51 100644 (file)
@@ -105,22 +105,24 @@ Angle::initOptions(Options *options, TrajectoryAnalysisSettings * /*settings*/)
         "The type of the angle is specified with [TT]-g1[tt] and [TT]-g2[tt].",
         "If [TT]-g1[tt] is [TT]angle[tt] or [TT]dihedral[tt], [TT]-g2[tt]",
         "should not be specified.",
-        "In this case, [TT]-group1[tt] should specify one selection,",
-        "and it should contain triplets or quartets of positions that define",
+        "In this case, [TT]-group1[tt] should specify one or more selections,",
+        "and each should contain triplets or quartets of positions that define",
         "the angles to be calculated.[PAR]",
         "If [TT]-g1[tt] is [TT]vector[tt] or [TT]plane[tt], [TT]-group1[tt]",
-        "should specify a selection that has either pairs ([TT]vector[tt])",
+        "should specify selections that contain either pairs ([TT]vector[tt])",
         "or triplets ([TT]plane[tt]) of positions. For vectors, the positions",
         "set the endpoints of the vector, and for planes, the three positions",
         "are used to calculate the normal of the plane. In both cases,",
         "[TT]-g2[tt] specifies the other vector to use (see below).[PAR]",
         "With [TT]-g2 vector[tt] or [TT]-g2 plane[tt], [TT]-group2[tt] should",
-        "specify another set of vectors. Both selections should specify the",
-        "same number of vectors.[PAR]",
-        "With [TT]-g2 sphnorm[tt], [TT]-group2[tt] should specify a single",
-        "position that is the center of the sphere. The second vector is then",
-        "calculated as the vector from the center to the midpoint of the",
-        "positions specified by [TT]-group1[tt].[PAR]",
+        "specify another set of vectors. [TT]-group1[tt] and [TT]-group2[tt]",
+        "should specify the same number of selections, and for each selection",
+        "in [TT]-group1[tt], the corresponding selection in [TT]-group2[tt]",
+        "should specify the same number of vectors.[PAR]",
+        "With [TT]-g2 sphnorm[tt], each selection in [TT]-group2[tt] should",
+        "specify a single position that is the center of the sphere.",
+        "The second vector is calculated as the vector from the center to the",
+        "midpoint of the positions specified by [TT]-group1[tt].[PAR]",
         "With [TT]-g2 z[tt], [TT]-group2[tt] is not necessary, and angles",
         "between the first vectors and the positive Z axis are calculated.[PAR]",
         "With [TT]-g2 t0[tt], [TT]-group2[tt] is not necessary, and angles",
@@ -130,13 +132,9 @@ Angle::initOptions(Options *options, TrajectoryAnalysisSettings * /*settings*/)
         "for each frame.",
         "[TT]-oall[tt] writes all the individual angles.",
         "[TT]-oh[tt] writes a histogram of the angles. The bin width can be",
-        "set with [TT]-binw[tt]."
-        /* TODO: Consider if the dump option is necessary and how to best
-         * implement it.
-           "[TT]-od[tt] can be used to dump all the individual angles,",
-           "each on a separate line. This format is better suited for",
-           "further processing, e.g., if angles from multiple runs are needed."
-         */
+        "set with [TT]-binw[tt].",
+        "For [TT]-oav[tt] and [TT]-oh[tt], separate average/histogram is",
+        "computed for each selection in [TT]-group1[tt]."
     };
     static const char *const cGroup1TypeEnum[] =
     { "angle", "dihedral", "vector", "plane" };
@@ -164,17 +162,13 @@ Angle::initOptions(Options *options, TrajectoryAnalysisSettings * /*settings*/)
     options->addOption(DoubleOption("binw").store(&binWidth_)
                            .description("Binwidth for -oh in degrees"));
 
-    // TODO: Allow multiple angles to be computed in one invocation.
-    // Most of the code already supports it, but requires a solution for
-    // Redmine issue #1010.
-    // TODO: Consider what is the best way to support dynamic selections.
-    // Again, most of the code already supports it, but it needs to be
-    // considered how should -oall work, and additional checks should be added.
     sel1info_ = options->addOption(SelectionOption("group1")
-                                       .required().onlyStatic().storeVector(&sel1_)
+                                       .required().dynamicMask().storeVector(&sel1_)
+                                       .multiValue()
                                        .description("First analysis/vector selection"));
     sel2info_ = options->addOption(SelectionOption("group2")
-                                       .onlyStatic().storeVector(&sel2_)
+                                       .dynamicMask().storeVector(&sel2_)
+                                       .multiValue()
                                        .description("Second analysis/vector selection"));
 }
 
@@ -240,8 +234,8 @@ Angle::checkSelections(const SelectionList &sel1,
 
     for (size_t g = 0; g < sel1.size(); ++g)
     {
-        int na1 = sel1[g].posCount();
-        int na2 = (natoms2_ > 0) ? sel2[g].posCount() : 0;
+        const int na1 = sel1[g].posCount();
+        const int na2 = (natoms2_ > 0) ? sel2[g].posCount() : 0;
         if (natoms1_ > 1 && na1 % natoms1_ != 0)
         {
             GMX_THROW(InconsistentInputError(formatString(
@@ -264,6 +258,30 @@ Angle::checkSelections(const SelectionList &sel1,
             GMX_THROW(InconsistentInputError(
                               "The second group should contain a single position with -g2 sphnorm"));
         }
+        if (sel1[g].isDynamic() || (natoms2_ > 0 && sel2[g].isDynamic()))
+        {
+            for (int i = 0, j = 0; i < na1; i += natoms1_, j += natoms2_)
+            {
+                const bool bSelected = sel1[g].position(i).selected();
+                bool       bOk       = true;
+                for (int k = 1; k < natoms1_ && bOk; ++k)
+                {
+                    bOk = (sel1[g].position(i+k).selected() == bSelected);
+                }
+                for (int k = 1; k < natoms2_ && bOk; ++k)
+                {
+                    bOk = (sel2[g].position(j+k).selected() == bSelected);
+                }
+                if (!bOk)
+                {
+                    std::string message =
+                        formatString("Dynamic selection %d does not select "
+                                     "a consistent set of angles over the frames",
+                                     static_cast<int>(g + 1));
+                    GMX_THROW(InconsistentInputError(message));
+                }
+            }
+        }
     }
 }
 
@@ -274,7 +292,12 @@ Angle::initAnalysis(const TrajectoryAnalysisSettings &settings,
 {
     checkSelections(sel1_, sel2_);
 
-    angles_.setColumnCount(sel1_[0].posCount() / natoms1_);
+    // checkSelections() ensures that both selection lists have the same size.
+    angles_.setDataSetCount(sel1_.size());
+    for (size_t i = 0; i < sel1_.size(); ++i)
+    {
+        angles_.setColumnCount(i, sel1_[i].posCount() / natoms1_);
+    }
     double histogramMin = (g1type_ == "dihedral" ? -180.0 : 0);
     histogramModule_->init(histogramFromRange(histogramMin, 180.0)
                                .binWidth(binWidth_).includeAll());
@@ -407,12 +430,16 @@ Angle::analyzeFrame(int frnr, const t_trxframe &fr, t_pbc *pbc,
                 copy_rvec(sel2_[g].position(0).x(), c2);
                 break;
         }
+        dh.selectDataSet(g);
         for (int i = 0, j = 0, n = 0;
              i < sel1[g].posCount();
              i += natoms1_, j += natoms2_, ++n)
         {
             rvec x[4];
             real angle;
+            // checkSelections() ensures that this reflects all the involved
+            // positions.
+            bool bPresent = sel1[g].position(i).selected();
             copy_pos(sel1, natoms1_, g, i, x);
             switch (g1type_[0])
             {
@@ -493,24 +520,7 @@ Angle::analyzeFrame(int frnr, const t_trxframe &fr, t_pbc *pbc,
                 default:
                     GMX_THROW(InternalError("invalid -g1 value"));
             }
-            /* TODO: Should we also calculate distances like g_sgangle?
-             * Could be better to leave that for a separate tool.
-               real dist = 0.0;
-               if (bDumpDist_)
-               {
-                if (pbc)
-                {
-                    rvec dx;
-                    pbc_dx(pbc, c2, c1, dx);
-                    dist = norm(dx);
-                }
-                else
-                {
-                    dist = sqrt(distance2(c1, c2));
-                }
-               }
-             */
-            dh.setPoint(n, angle * RAD2DEG);
+            dh.setPoint(n, angle * RAD2DEG, bPresent);
         }
     }
     dh.finishFrame();
index e7a7b324d9b9c059f4d1fd41e3af14c543c847cd..de2c2fae1304521f62b3aea089c38691158c327f 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2010,2011,2012, by the GROMACS development team, led by
+ * Copyright (c) 2010,2011,2012,2013, 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.
@@ -63,14 +63,28 @@ namespace analysismodules
 
 const char Distance::name[]             = "distance";
 const char Distance::shortDescription[] =
-    "Calculate distances";
+    "Calculate distances between pairs of positions";
 
 Distance::Distance()
     : TrajectoryAnalysisModule(name, shortDescription),
-      avem_(new AnalysisDataAverageModule())
+      meanLength_(0.1), lengthDev_(1.0), binWidth_(0.001)
 {
-    data_.setColumnCount(4);
-    registerAnalysisDataset(&data_, "distance");
+    summaryStatsModule_.reset(new AnalysisDataAverageModule());
+    summaryStatsModule_->setAverageDataSets(true);
+    distances_.addModule(summaryStatsModule_);
+    allStatsModule_.reset(new AnalysisDataAverageModule());
+    distances_.addModule(allStatsModule_);
+    averageModule_.reset(new AnalysisDataFrameAverageModule());
+    distances_.addModule(averageModule_);
+    histogramModule_.reset(new AnalysisDataSimpleHistogramModule());
+    distances_.addModule(histogramModule_);
+
+    registerAnalysisDataset(&distances_, "dist");
+    registerAnalysisDataset(&xyz_, "xyz");
+    registerBasicDataset(summaryStatsModule_.get(), "stats");
+    registerBasicDataset(allStatsModule_.get(), "allstats");
+    registerBasicDataset(averageModule_.get(), "average");
+    registerBasicDataset(&histogramModule_->averager(), "histogram");
 }
 
 
@@ -83,42 +97,173 @@ void
 Distance::initOptions(Options *options, TrajectoryAnalysisSettings * /*settings*/)
 {
     static const char *const desc[] = {
-        "g_dist can calculate the distance between two positions as",
-        "a function of time. The total distance and its",
-        "x, y and z components are plotted."
+        "[TT]gmx distance[tt] calculates distances between pairs of positions",
+        "as a function of time. Each selection specifies an independent set",
+        "of distances to calculate. Each selection should consist of pairs",
+        "of positions, and the distances are computed between positions 1-2,",
+        "3-4, etc.[PAR]",
+        "[TT]-oav[tt] writes the average distance as a function of time for",
+        "each selection.",
+        "[TT]-oall[tt] writes all the individual distances.",
+        "[TT]-oxyz[tt] does the same, but the x, y, and z components of the",
+        "distance are written instead of the norm.",
+        "[TT]-oh[tt] writes a histogram of the distances for each selection.",
+        "The location of the histogram is set with [TT]-len[tt] and",
+        "[TT]-tol[tt]. Bin width is set with [TT]-binw[tt].",
+        "[TT]-oallstat[tt] writes out the average and standard deviation for",
+        "each individual distance, calculated over the frames."
     };
 
     options->setDescription(concatenateStrings(desc));
 
-    options->addOption(FileNameOption("o").filetype(eftPlot).outputFile()
-                           .store(&fnDist_).defaultBasename("dist")
-                           .description("Computed distances"));
-    options->addOption(SelectionOption("select").required().valueCount(2)
-                           .store(sel_));
+    options->addOption(FileNameOption("oav").filetype(eftPlot).outputFile()
+                           .store(&fnAverage_).defaultBasename("distave")
+                           .description("Average distances as function of time"));
+    options->addOption(FileNameOption("oall").filetype(eftPlot).outputFile()
+                           .store(&fnAll_).defaultBasename("dist")
+                           .description("All distances as function of time"));
+    options->addOption(FileNameOption("oxyz").filetype(eftPlot).outputFile()
+                           .store(&fnXYZ_).defaultBasename("distxyz")
+                           .description("Distance components as function of time"));
+    options->addOption(FileNameOption("oh").filetype(eftPlot).outputFile()
+                           .store(&fnHistogram_).defaultBasename("disthist")
+                           .description("Histogram of the distances"));
+    options->addOption(FileNameOption("oallstat").filetype(eftPlot).outputFile()
+                           .store(&fnAllStats_).defaultBasename("diststat")
+                           .description("Statistics for individual distances"));
+    options->addOption(SelectionOption("select").storeVector(&sel_)
+                           .required().dynamicMask().multiValue()
+                           .description("Position pairs to calculate distances for"));
+    // TODO: Extend the histogramming implementation to allow automatic
+    // extension of the histograms to cover the data, removing the need for
+    // the first two options.
+    options->addOption(DoubleOption("len").store(&meanLength_)
+                           .description("Mean distance for histogramming"));
+    options->addOption(DoubleOption("tol").store(&lengthDev_)
+                           .description("Width of full distribution as fraction of [TT]-len[tt]"));
+    options->addOption(DoubleOption("binw").store(&binWidth_)
+                           .description("Bin width for histogramming"));
 }
 
 
+namespace
+{
+
+/*! \brief
+ * Checks that selections conform to the expectations of the tool.
+ */
+void checkSelections(const SelectionList &sel)
+{
+    for (size_t g = 0; g < sel.size(); ++g)
+    {
+        if (sel[g].posCount() % 2 != 0)
+        {
+            std::string message = formatString(
+                        "Selection '%s' does not evaluate into an even number of positions "
+                        "(there are %d positions)",
+                        sel[g].name(), sel[g].posCount());
+            GMX_THROW(InconsistentInputError(message));
+        }
+        if (sel[g].isDynamic())
+        {
+            for (int i = 0; i < sel[g].posCount(); i += 2)
+            {
+                if (sel[g].position(i).selected() != sel[g].position(i+1).selected())
+                {
+                    std::string message =
+                        formatString("Dynamic selection %d does not select "
+                                     "a consistent set of pairs over the frames",
+                                     static_cast<int>(g + 1));
+                    GMX_THROW(InconsistentInputError(message));
+                }
+            }
+        }
+    }
+}
+
+}       // namespace
+
+
 void
 Distance::initAnalysis(const TrajectoryAnalysisSettings &settings,
                        const TopologyInformation         & /*top*/)
 {
-    if (sel_[0].posCount() != 1)
+    checkSelections(sel_);
+
+    distances_.setDataSetCount(sel_.size());
+    xyz_.setDataSetCount(sel_.size());
+    for (size_t i = 0; i < sel_.size(); ++i)
+    {
+        const int distCount = sel_[i].posCount() / 2;
+        distances_.setColumnCount(i, distCount);
+        xyz_.setColumnCount(i, distCount * 3);
+    }
+    const double histogramMin = (1.0 - lengthDev_) * meanLength_;
+    const double histogramMax = (1.0 + lengthDev_) * meanLength_;
+    histogramModule_->init(histogramFromRange(histogramMin, histogramMax)
+                               .binWidth(binWidth_).includeAll());
+
+    if (!fnAverage_.empty())
     {
-        GMX_THROW(InvalidInputError("The first selection does not define a single position"));
+        AnalysisDataPlotModulePointer plotm(
+                new AnalysisDataPlotModule(settings.plotSettings()));
+        plotm->setFileName(fnAverage_);
+        plotm->setTitle("Average distance");
+        plotm->setXAxisIsTime();
+        plotm->setYLabel("Distance (nm)");
+        // TODO: Add legends
+        averageModule_->addModule(plotm);
     }
-    if (sel_[1].posCount() != 1)
+
+    if (!fnAll_.empty())
+    {
+        AnalysisDataPlotModulePointer plotm(
+                new AnalysisDataPlotModule(settings.plotSettings()));
+        plotm->setFileName(fnAll_);
+        plotm->setTitle("Distance");
+        plotm->setXAxisIsTime();
+        plotm->setYLabel("Distance (nm)");
+        // TODO: Add legends? (there can be a massive amount of columns)
+        distances_.addModule(plotm);
+    }
+
+    if (!fnXYZ_.empty())
     {
-        GMX_THROW(InvalidInputError("The second selection does not define a single position"));
+        AnalysisDataPlotModulePointer plotm(
+                new AnalysisDataPlotModule(settings.plotSettings()));
+        plotm->setFileName(fnAll_);
+        plotm->setTitle("Distance");
+        plotm->setXAxisIsTime();
+        plotm->setYLabel("Distance (nm)");
+        // TODO: Add legends? (there can be a massive amount of columns)
+        xyz_.addModule(plotm);
     }
 
-    data_.addModule(avem_);
-    AnalysisDataPlotModulePointer plotm_(new AnalysisDataPlotModule());
-    plotm_->setSettings(settings.plotSettings());
-    plotm_->setFileName(fnDist_);
-    plotm_->setTitle("Distance");
-    plotm_->setXAxisIsTime();
-    plotm_->setYLabel("Distance (nm)");
-    data_.addModule(plotm_);
+    if (!fnHistogram_.empty())
+    {
+        AnalysisDataPlotModulePointer plotm(
+                new AnalysisDataPlotModule(settings.plotSettings()));
+        plotm->setFileName(fnHistogram_);
+        plotm->setTitle("Distance histogram");
+        plotm->setXLabel("Distance (nm)");
+        plotm->setYLabel("Probability");
+        // TODO: Add legends
+        histogramModule_->averager().addModule(plotm);
+    }
+
+    if (!fnAllStats_.empty())
+    {
+        AnalysisDataPlotModulePointer plotm(
+                new AnalysisDataPlotModule(settings.plotSettings()));
+        plotm->setFileName(fnAllStats_);
+        plotm->setErrorsAsSeparateColumn(true);
+        plotm->setTitle("Statistics for individual distances");
+        plotm->setXLabel("Distance index");
+        plotm->setYLabel("Average/standard deviation (nm)");
+        // TODO: Add legends
+        // TODO: Consider whether this output format is the best possible.
+        allStatsModule_->addModule(plotm);
+    }
 }
 
 
@@ -126,41 +271,66 @@ void
 Distance::analyzeFrame(int frnr, const t_trxframe &fr, t_pbc *pbc,
                        TrajectoryAnalysisModuleData *pdata)
 {
-    AnalysisDataHandle       dh   = pdata->dataHandle(data_);
-    const Selection         &sel1 = pdata->parallelSelection(sel_[0]);
-    const Selection         &sel2 = pdata->parallelSelection(sel_[1]);
-    rvec                     dx;
-    real                     r;
-    const SelectionPosition &p1 = sel1.position(0);
-    const SelectionPosition &p2 = sel2.position(0);
-
-    if (pbc != NULL)
-    {
-        pbc_dx(pbc, p1.x(), p2.x(), dx);
-    }
-    else
+    AnalysisDataHandle   distHandle = pdata->dataHandle(distances_);
+    AnalysisDataHandle   xyzHandle  = pdata->dataHandle(xyz_);
+    const SelectionList &sel        = pdata->parallelSelections(sel_);
+
+    checkSelections(sel);
+
+    distHandle.startFrame(frnr, fr.time);
+    xyzHandle.startFrame(frnr, fr.time);
+    for (size_t g = 0; g < sel.size(); ++g)
     {
-        rvec_sub(p1.x(), p2.x(), dx);
+        distHandle.selectDataSet(g);
+        xyzHandle.selectDataSet(g);
+        for (int i = 0, n = 0; i < sel[g].posCount(); i += 2, ++n)
+        {
+            const SelectionPosition &p1 = sel[g].position(i);
+            const SelectionPosition &p2 = sel[g].position(i+1);
+            rvec                     dx;
+            if (pbc != NULL)
+            {
+                pbc_dx(pbc, p2.x(), p1.x(), dx);
+            }
+            else
+            {
+                rvec_sub(p2.x(), p1.x(), dx);
+            }
+            real dist     = norm(dx);
+            bool bPresent = p1.selected() && p2.selected();
+            distHandle.setPoint(n, dist, bPresent);
+            xyzHandle.setPoints(n*3, 3, dx);
+        }
     }
-    r = norm(dx);
-    dh.startFrame(frnr, fr.time);
-    dh.setPoint(0, r);
-    dh.setPoints(1, 3, dx);
-    dh.finishFrame();
+    distHandle.finishFrame();
+    xyzHandle.finishFrame();
 }
 
 
 void
 Distance::finishAnalysis(int /*nframes*/)
 {
+    AbstractAverageHistogram &averageHistogram = histogramModule_->averager();
+    averageHistogram.normalizeProbability();
+    averageHistogram.done();
 }
 
 
 void
 Distance::writeOutput()
 {
-    fprintf(stderr, "Average distance: %f\n", avem_->average(0));
-    fprintf(stderr, "Std. deviation:   %f\n", avem_->stddev(0));
+    SelectionList::const_iterator sel;
+    int                           index;
+    for (sel = sel_.begin(), index = 0; sel != sel_.end(); ++sel, ++index)
+    {
+        printf("%s:\n", sel->name());
+        printf("  Number of samples:  %d\n",
+               summaryStatsModule_->sampleCount(index, 0));
+        printf("  Average distance:   %-6.3f nm\n",
+               summaryStatsModule_->average(index, 0));
+        printf("  Standard deviation: %-6.3f nm\n",
+               summaryStatsModule_->standardDeviation(index, 0));
+    }
 }
 
 } // namespace analysismodules
index 6fa5003ca675661f4e203ae02f394219e9f591de..6fc6d7c423b2ff2d5d208f21368663be277980cc 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2010,2011,2012, by the GROMACS development team, led by
+ * Copyright (c) 2010,2011,2012,2013, 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.
@@ -47,6 +47,7 @@
 #include "../analysismodule.h"
 #include "gromacs/analysisdata/analysisdata.h"
 #include "gromacs/analysisdata/modules/average.h"
+#include "gromacs/analysisdata/modules/histogram.h"
 #include "gromacs/selection/selection.h"
 
 namespace gmx
@@ -76,10 +77,22 @@ class Distance : public TrajectoryAnalysisModule
         virtual void writeOutput();
 
     private:
-        std::string                      fnDist_;
-        Selection                        sel_[2];
-        AnalysisData                     data_;
-        AnalysisDataAverageModulePointer avem_;
+        SelectionList                            sel_;
+        std::string                              fnAverage_;
+        std::string                              fnAll_;
+        std::string                              fnXYZ_;
+        std::string                              fnHistogram_;
+        std::string                              fnAllStats_;
+        double                                   meanLength_;
+        double                                   lengthDev_;
+        double                                   binWidth_;
+
+        AnalysisData                             distances_;
+        AnalysisData                             xyz_;
+        AnalysisDataAverageModulePointer         summaryStatsModule_;
+        AnalysisDataAverageModulePointer         allStatsModule_;
+        AnalysisDataFrameAverageModulePointer    averageModule_;
+        AnalysisDataSimpleHistogramModulePointer histogramModule_;
 
         // Copy and assign disallowed by base.
 };
index 1102b2ee4a761cf4fad2142047d24f4e00512edf..10338826d05c78a759b51a4f18384a1279f053e8 100644 (file)
@@ -76,7 +76,7 @@ FreeVolume::FreeVolume()
       adata_(new AnalysisDataAverageModule())
 {
     // We only compute two numbers per frame
-    data_.setColumnCount(2);
+    data_.setColumnCount(0, 2);
     // Tell the analysis framework that this component exists
     registerAnalysisDataset(&data_, "freevolume");
     rng_         = NULL;
@@ -347,16 +347,16 @@ void
 FreeVolume::writeOutput()
 {
     // Final results come from statistics module in analysis framework
-    double FVaver  = adata_->average(0);
-    double FVerror = adata_->stddev(0);
+    double FVaver  = adata_->average(0, 0);
+    double FVerror = adata_->standardDeviation(0, 0);
     printf("Free volume %.2f +/- %.2f %%\n", FVaver, FVerror);
 
-    double Vaver  = adata_->average(1);
-    double Verror = adata_->stddev(1);
+    double Vaver  = adata_->average(0, 1);
+    double Verror = adata_->standardDeviation(0, 1);
     printf("Total volume %.2f +/- %.2f nm^3\n", Vaver, Verror);
 
     printf("Number of molecules %d total mass %.2f Dalton\n", nmol_, mtot_);
-    double RhoAver  = mtot_ / (adata_->average(1) * 1e-24 * AVOGADRO);
+    double RhoAver  = mtot_ / (Vaver * 1e-24 * AVOGADRO);
     double RhoError = sqr(RhoAver / Vaver)*Verror;
     printf("Average molar mass: %.2f Dalton\n", mtot_/nmol_);
 
index 2f7c6d5a1298a75f09c86673cdc034baa30c03f9..0cee1e54d193c171181ed0869fc2605ad2f62faa 100644 (file)
@@ -45,6 +45,7 @@
 #include <cstring>
 
 #include <algorithm>
+#include <set>
 #include <string>
 #include <vector>
 
@@ -259,17 +260,23 @@ const char Select::shortDescription[] =
 Select::Select()
     : TrajectoryAnalysisModule(name, shortDescription),
       selOpt_(NULL),
-      bDump_(false), bTotNorm_(false), bFracNorm_(false), bResInd_(false),
-      top_(NULL), occupancyModule_(new AnalysisDataAverageModule())
+      bTotNorm_(false), bFracNorm_(false), bResInd_(false),
+      bCumulativeLifetimes_(true), top_(NULL),
+      occupancyModule_(new AnalysisDataAverageModule()),
+      lifetimeModule_(new AnalysisDataLifetimeModule())
 {
+    mdata_.addModule(occupancyModule_);
+    mdata_.addModule(lifetimeModule_);
+
     registerAnalysisDataset(&sdata_, "size");
     registerAnalysisDataset(&cdata_, "cfrac");
-    idata_.setColumnCount(2);
+    idata_.setColumnCount(0, 2);
     idata_.setMultipoint(true);
     registerAnalysisDataset(&idata_, "index");
     registerAnalysisDataset(&mdata_, "mask");
     occupancyModule_->setXAxis(1.0, 1.0);
     registerBasicDataset(occupancyModule_.get(), "occupancy");
+    registerBasicDataset(lifetimeModule_.get(), "lifetime");
 }
 
 
@@ -307,9 +314,7 @@ Select::initOptions(Options *options, TrajectoryAnalysisSettings * /*settings*/)
         "of positions, followed by the atom/residue/molecule numbers.",
         "If more than one selection is specified, the size of the second",
         "group immediately follows the last number of the first group",
-        "and so on. With [TT]-dump[tt], the frame time and the number",
-        "of positions is omitted from the output. In this case, only one",
-        "selection can be given.[PAR]",
+        "and so on.[PAR]",
         "With [TT]-on[tt], the selected atoms are written as a index file",
         "compatible with [TT]make_ndx[tt] and the analyzing tools. Each selection",
         "is written as a selection group and for dynamic selections a",
@@ -325,8 +330,7 @@ Select::initOptions(Options *options, TrajectoryAnalysisSettings * /*settings*/)
         "as a function of time. Each line in the output corresponds to",
         "one frame, and contains either 0/1 for each atom/residue/molecule",
         "possibly selected. 1 stands for the atom/residue/molecule being",
-        "selected for the current frame, 0 for not selected.",
-        "With [TT]-dump[tt], the frame time is omitted from the output.[PAR]",
+        "selected for the current frame, 0 for not selected.[PAR]",
         "With [TT]-of[tt], the occupancy fraction of each position (i.e.,",
         "the fraction of frames where the position is selected) is",
         "printed.[PAR]",
@@ -338,9 +342,12 @@ Select::initOptions(Options *options, TrajectoryAnalysisSettings * /*settings*/)
         "present, with [TT]maxsel[tt] all atoms possibly selected by the",
         "selection are present, and with [TT]selected[tt] only atoms that are",
         "selected at least in one frame are present.[PAR]",
-        "With [TT]-om[tt], [TT]-of[tt] and [TT]-ofpdb[tt], only one selection",
-        "can be provided. [TT]-om[tt] and [TT]-of[tt] only accept dynamic",
-        "selections."
+        "With [TT]-olt[tt], a histogram is produced that shows the number of",
+        "selected positions as a function of the time the position was",
+        "continuously selected. [TT]-cumlt[tt] can be used to control whether",
+        "subintervals of longer intervals are included in the histogram.[PAR]",
+        "[TT]-om[tt], [TT]-of[tt], and [TT]-olt[tt] only make sense with",
+        "dynamic selections."
     };
 
     options->setDescription(concatenateStrings(desc));
@@ -366,13 +373,14 @@ Select::initOptions(Options *options, TrajectoryAnalysisSettings * /*settings*/)
     options->addOption(FileNameOption("ofpdb").filetype(eftPDB).outputFile()
                            .store(&fnPDB_).defaultBasename("occupancy")
                            .description("PDB file with occupied fraction for selected positions"));
+    options->addOption(FileNameOption("olt").filetype(eftPlot).outputFile()
+                           .store(&fnLifetime_).defaultBasename("lifetime")
+                           .description("Lifetime histogram"));
 
     selOpt_ = options->addOption(SelectionOption("select").storeVector(&sel_)
                                      .required().multiValue()
                                      .description("Selections to analyze"));
 
-    options->addOption(BooleanOption("dump").store(&bDump_)
-                           .description("Do not print the frame time (-om, -oi) or the index size (-oi)"));
     options->addOption(BooleanOption("norm").store(&bTotNorm_)
                            .description("Normalize by total number of positions with -os"));
     options->addOption(BooleanOption("cfnorm").store(&bFracNorm_)
@@ -385,6 +393,8 @@ Select::initOptions(Options *options, TrajectoryAnalysisSettings * /*settings*/)
     options->addOption(StringOption("pdbatoms").store(&pdbAtoms_)
                            .enumValue(cPDBAtomsEnum).defaultEnumIndex(0)
                            .description("Atoms to write with -ofpdb"));
+    options->addOption(BooleanOption("cumlt").store(&bCumulativeLifetimes_)
+                           .description("Cumulate subintervals of longer intervals in -olt"));
 }
 
 void
@@ -396,22 +406,12 @@ Select::optionsFinished(Options                     * /*options*/,
         settings->setFlag(TrajectoryAnalysisSettings::efRequireTop);
         settings->setFlag(TrajectoryAnalysisSettings::efUseTopX);
     }
-    if ((!fnIndex_.empty() && bDump_)
-        || !fnMask_.empty() || !fnOccupancy_.empty() || !fnPDB_.empty())
-    {
-        selOpt_->setValueCount(1);
-    }
 }
 
 void
 Select::initAnalysis(const TrajectoryAnalysisSettings &settings,
                      const TopologyInformation        &top)
 {
-    if (!sel_[0].isDynamic() && (!fnMask_.empty() || !fnOccupancy_.empty()))
-    {
-        GMX_THROW(InconsistentInputError(
-                          "-om or -of are not meaningful with a static selection"));
-    }
     bResInd_ = (resNumberType_ == "index");
 
     for (SelectionList::iterator i = sel_.begin(); i != sel_.end(); ++i)
@@ -420,7 +420,7 @@ Select::initAnalysis(const TrajectoryAnalysisSettings &settings,
     }
 
     // TODO: For large systems, a float may not have enough precision
-    sdata_.setColumnCount(sel_.size());
+    sdata_.setColumnCount(0, sel_.size());
     totsize_.reserve(sel_.size());
     for (size_t g = 0; g < sel_.size(); ++g)
     {
@@ -437,7 +437,7 @@ Select::initAnalysis(const TrajectoryAnalysisSettings &settings,
         sdata_.addModule(plot);
     }
 
-    cdata_.setColumnCount(sel_.size());
+    cdata_.setColumnCount(0, sel_.size());
     if (!fnFrac_.empty())
     {
         AnalysisDataPlotModulePointer plot(
@@ -458,15 +458,7 @@ Select::initAnalysis(const TrajectoryAnalysisSettings &settings,
         plot->setFileName(fnIndex_);
         plot->setPlainOutput(true);
         plot->setYFormat(4, 0);
-        if (bDump_)
-        {
-            plot->setOmitX(bDump_);
-            idata_.addColumnModule(1, 1, plot);
-        }
-        else
-        {
-            idata_.addModule(plot);
-        }
+        idata_.addModule(plot);
     }
     if (!fnNdx_.empty())
     {
@@ -479,15 +471,17 @@ Select::initAnalysis(const TrajectoryAnalysisSettings &settings,
         idata_.addModule(writer);
     }
 
-    mdata_.setColumnCount(sel_[0].posCount());
-    mdata_.addModule(occupancyModule_);
+    mdata_.setDataSetCount(sel_.size());
+    for (size_t g = 0; g < sel_.size(); ++g)
+    {
+        mdata_.setColumnCount(g, sel_[g].posCount());
+    }
+    lifetimeModule_->setCumulative(bCumulativeLifetimes_);
     if (!fnMask_.empty())
     {
         AnalysisDataPlotModulePointer plot(
                 new AnalysisDataPlotModule(settings.plotSettings()));
         plot->setFileName(fnMask_);
-        plot->setPlainOutput(bDump_);
-        plot->setOmitX(bDump_);
         plot->setTitle("Selection mask");
         plot->setXAxisIsTime();
         plot->setYLabel("Occupancy");
@@ -502,7 +496,17 @@ Select::initAnalysis(const TrajectoryAnalysisSettings &settings,
         plot->setTitle("Fraction of time selection matches");
         plot->setXLabel("Selected position");
         plot->setYLabel("Occupied fraction");
-        occupancyModule_->addColumnModule(0, 1, plot);
+        occupancyModule_->addModule(plot);
+    }
+    if (!fnLifetime_.empty())
+    {
+        AnalysisDataPlotModulePointer plot(
+                new AnalysisDataPlotModule(settings.plotSettings()));
+        plot->setFileName(fnLifetime_);
+        plot->setTitle("Lifetime histogram");
+        plot->setXAxisIsTime();
+        plot->setYLabel("Number of occurrences");
+        lifetimeModule_->addModule(plot);
     }
 
     top_ = &top;
@@ -561,13 +565,17 @@ Select::analyzeFrame(int frnr, const t_trxframe &fr, t_pbc *pbc,
     idh.finishFrame();
 
     mdh.startFrame(frnr, fr.time);
-    for (int i = 0; i < totsize_[0]; ++i)
-    {
-        mdh.setPoint(i, 0);
-    }
-    for (int i = 0; i < sel[0].posCount(); ++i)
+    for (size_t g = 0; g < sel.size(); ++g)
     {
-        mdh.setPoint(sel[0].position(i).refId(), 1);
+        mdh.selectDataSet(g);
+        for (int i = 0; i < totsize_[g]; ++i)
+        {
+            mdh.setPoint(i, 0);
+        }
+        for (int i = 0; i < sel[g].posCount(); ++i)
+        {
+            mdh.setPoint(sel[g].position(i).refId(), 1);
+        }
     }
     mdh.finishFrame();
 }
@@ -600,13 +608,17 @@ Select::writeOutput()
         {
             pdbinfo[i].occup = 0.0;
         }
-        for (int i = 0; i < sel_[0].posCount(); ++i)
+        for (size_t g = 0; g < sel_.size(); ++g)
         {
-            ConstArrayRef<int>                 atomIndices = sel_[0].position(i).atomIndices();
-            ConstArrayRef<int>::const_iterator ai;
-            for (ai = atomIndices.begin(); ai != atomIndices.end(); ++ai)
+            for (int i = 0; i < sel_[g].posCount(); ++i)
             {
-                pdbinfo[*ai].occup = occupancyModule_->average(i);
+                ConstArrayRef<int>                 atomIndices
+                    = sel_[g].position(i).atomIndices();
+                ConstArrayRef<int>::const_iterator ai;
+                for (ai = atomIndices.begin(); ai != atomIndices.end(); ++ai)
+                {
+                    pdbinfo[*ai].occup += occupancyModule_->average(g, i);
+                }
             }
         }
 
@@ -626,25 +638,27 @@ Select::writeOutput()
         }
         else if (pdbAtoms_ == "maxsel")
         {
-            ConstArrayRef<int> atomIndices = sel_[0].atomIndices();
-            t_trxstatus       *status      = open_trx(fnPDB_.c_str(), "w");
-            write_trxframe_indexed(status, &fr, atomIndices.size(),
-                                   atomIndices.data(), NULL);
+            std::set<int> atomIndicesSet;
+            for (size_t g = 0; g < sel_.size(); ++g)
+            {
+                ConstArrayRef<int> atomIndices = sel_[g].atomIndices();
+                atomIndicesSet.insert(atomIndices.begin(), atomIndices.end());
+            }
+            std::vector<int>  allAtomIndices(atomIndicesSet.begin(),
+                                             atomIndicesSet.end());
+            t_trxstatus      *status = open_trx(fnPDB_.c_str(), "w");
+            write_trxframe_indexed(status, &fr, allAtomIndices.size(),
+                                   &allAtomIndices[0], NULL);
             close_trx(status);
         }
         else if (pdbAtoms_ == "selected")
         {
             std::vector<int> indices;
-            for (int i = 0; i < sel_[0].posCount(); ++i)
+            for (int i = 0; i < atoms.nr; ++i)
             {
-                if (occupancyModule_->average(i) > 0)
+                if (pdbinfo[i].occup > 0.0)
                 {
-                    ConstArrayRef<int>                 atomIndices = sel_[0].position(i).atomIndices();
-                    ConstArrayRef<int>::const_iterator ai;
-                    for (ai = atomIndices.begin(); ai != atomIndices.end(); ++ai)
-                    {
-                        indices.push_back(*ai);
-                    }
+                    indices.push_back(i);
                 }
             }
             t_trxstatus *status = open_trx(fnPDB_.c_str(), "w");
index a7cdac9f287b90c1fb28de97b953791d04e2113d..b25b476c2b1646dc261c81c2936005cc679e64c1 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2011,2012, by the GROMACS development team, led by
+ * Copyright (c) 2011,2012,2013, 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.
@@ -48,6 +48,7 @@
 #include "../analysismodule.h"
 #include "gromacs/analysisdata/analysisdata.h"
 #include "gromacs/analysisdata/modules/average.h"
+#include "gromacs/analysisdata/modules/lifetime.h"
 #include "gromacs/selection/selection.h"
 
 namespace gmx
@@ -81,30 +82,32 @@ class Select : public TrajectoryAnalysisModule
         virtual void writeOutput();
 
     private:
-        SelectionList                    sel_;
-        SelectionOptionInfo             *selOpt_;
-
-        std::string                      fnSize_;
-        std::string                      fnFrac_;
-        std::string                      fnIndex_;
-        std::string                      fnNdx_;
-        std::string                      fnMask_;
-        std::string                      fnOccupancy_;
-        std::string                      fnPDB_;
-        bool                             bDump_;
-        bool                             bTotNorm_;
-        bool                             bFracNorm_;
-        bool                             bResInd_;
-        std::string                      resNumberType_;
-        std::string                      pdbAtoms_;
-
-        const TopologyInformation       *top_;
-        std::vector<int>                 totsize_;
-        AnalysisData                     sdata_;
-        AnalysisData                     cdata_;
-        AnalysisData                     idata_;
-        AnalysisData                     mdata_;
-        AnalysisDataAverageModulePointer occupancyModule_;
+        SelectionList                       sel_;
+        SelectionOptionInfo                *selOpt_;
+
+        std::string                         fnSize_;
+        std::string                         fnFrac_;
+        std::string                         fnIndex_;
+        std::string                         fnNdx_;
+        std::string                         fnMask_;
+        std::string                         fnOccupancy_;
+        std::string                         fnPDB_;
+        std::string                         fnLifetime_;
+        bool                                bTotNorm_;
+        bool                                bFracNorm_;
+        bool                                bResInd_;
+        bool                                bCumulativeLifetimes_;
+        std::string                         resNumberType_;
+        std::string                         pdbAtoms_;
+
+        const TopologyInformation          *top_;
+        std::vector<int>                    totsize_;
+        AnalysisData                        sdata_;
+        AnalysisData                        cdata_;
+        AnalysisData                        idata_;
+        AnalysisData                        mdata_;
+        AnalysisDataAverageModulePointer    occupancyModule_;
+        AnalysisDataLifetimeModulePointer   lifetimeModule_;
 };
 
 } // namespace analysismodules
index ccf7b856078e25e133dbbbeae9a4527f9c5be9a1..bdfc20271c467a68386c442457a324f26c051cc4 100644 (file)
@@ -1,7 +1,7 @@
 #
 # This file is part of the GROMACS molecular simulation package.
 #
-# Copyright (c) 2010,2012, by the GROMACS development team, led by
+# Copyright (c) 2010,2012,2013, 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.
@@ -35,6 +35,7 @@
 gmx_add_unit_test(TrajectoryAnalysisUnitTests trajectoryanalysis-test
                   moduletest.cpp
                   angle.cpp
+                  distance.cpp
                   freevolume.cpp
                   select.cpp)
 
index a1c13501e5e240e2f25d57d49a2f863044991d93..66f2641566d077cd5149b09f9a01c9f8c1dd6cc5 100644 (file)
@@ -143,4 +143,33 @@ TEST_F(AngleModuleTest, ComputesVectorTimeZeroAngles)
     runTest(CommandLine::create(cmdline));
 }
 
+TEST_F(AngleModuleTest, ComputesMultipleAngles)
+{
+    const char *const cmdline[] = {
+        "angle",
+        "-g1", "vector",
+        "-group1",
+        "resname RV1 RV2 and name A1 A2",
+        "resname RV3 RV4 and name A1 A2",
+        "-g2", "plane",
+        "-group2",
+        "resname RP1 RP2 and name A1 A2 A3",
+        "resname RP1 RP2 and name A1 A2 A3",
+        "-binw", "60"
+    };
+    setTopology("angle.gro");
+    runTest(CommandLine::create(cmdline));
+}
+
+TEST_F(AngleModuleTest, HandlesDynamicSelections)
+{
+    const char *const cmdline[] = {
+        "angle",
+        "-g1", "angle", "-group1", "resname RA1 RA2 and name A1 A2 A3 and z < 0.5",
+        "-binw", "60"
+    };
+    setTopology("angle.gro");
+    runTest(CommandLine::create(cmdline));
+}
+
 } // namespace
diff --git a/src/gromacs/trajectoryanalysis/tests/distance.cpp b/src/gromacs/trajectoryanalysis/tests/distance.cpp
new file mode 100644 (file)
index 0000000..2ddd629
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2013, 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.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, 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 http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+/*! \internal \file
+ * \brief
+ * Tests for functionality of the "distance" trajectory analysis module.
+ *
+ * \author Teemu Murtola <teemu.murtola@gmail.com>
+ * \ingroup module_trajectoryanalysis
+ */
+#include <gtest/gtest.h>
+
+#include "gromacs/trajectoryanalysis/modules/distance.h"
+
+#include "testutils/cmdlinetest.h"
+
+#include "moduletest.h"
+
+namespace
+{
+
+using gmx::test::CommandLine;
+
+/********************************************************************
+ * Tests for gmx::analysismodules::Distance.
+ */
+
+//! Test fixture for the angle analysis module.
+typedef gmx::test::TrajectoryAnalysisModuleTestFixture<gmx::analysismodules::Distance>
+    DistanceModuleTest;
+
+TEST_F(DistanceModuleTest, ComputesDistances)
+{
+    const char *const cmdline[] = {
+        "distance",
+        "-select", "atomname S1 S2",
+        "-len", "2", "-binw", "0.5"
+    };
+    setTopology("simple.gro");
+    runTest(CommandLine::create(cmdline));
+}
+
+TEST_F(DistanceModuleTest, ComputesMultipleDistances)
+{
+    const char *const cmdline[] = {
+        "distance",
+        "-select", "atomname S1 S2",
+        "resindex 1 to 4 and atomname CB merge resindex 2 to 5 and atomname CB",
+        "-len", "2", "-binw", "0.5"
+    };
+    setTopology("simple.gro");
+    runTest(CommandLine::create(cmdline));
+}
+
+TEST_F(DistanceModuleTest, HandlesDynamicSelections)
+{
+    const char *const cmdline[] = {
+        "distance",
+        "-select", "atomname S1 S2 and res_cog x < 2.8",
+        "-len", "2", "-binw", "0.5"
+    };
+    setTopology("simple.gro");
+    runTest(CommandLine::create(cmdline));
+}
+
+} // namespace
index cead6c4759fe4da52a9b17980ea0ff165c82ddc9..1f24e40462959273e1dd2b950c7e6921421e17ef 100644 (file)
       <DataFrame Name="Frame0">
         <Real Name="X">-120.000000</Real>
         <DataValues>
-          <Int Name="Count">2</Int>
+          <Int Name="Count">1</Int>
           <DataValue>
             <Real Name="Value">0.002778</Real>
-          </DataValue>
-          <DataValue>
-            <Real Name="Value">0.000000</Real>
+            <Real Name="Error">0.000000</Real>
           </DataValue>
         </DataValues>
       </DataFrame>
       <DataFrame Name="Frame1">
         <Real Name="X">0.000000</Real>
         <DataValues>
-          <Int Name="Count">2</Int>
+          <Int Name="Count">1</Int>
           <DataValue>
             <Real Name="Value">0.002778</Real>
-          </DataValue>
-          <DataValue>
-            <Real Name="Value">0.000000</Real>
+            <Real Name="Error">0.000000</Real>
           </DataValue>
         </DataValues>
       </DataFrame>
       <DataFrame Name="Frame2">
         <Real Name="X">120.000000</Real>
         <DataValues>
-          <Int Name="Count">2</Int>
+          <Int Name="Count">1</Int>
           <DataValue>
             <Real Name="Value">0.002778</Real>
-          </DataValue>
-          <DataValue>
-            <Real Name="Value">0.000000</Real>
+            <Real Name="Error">0.000000</Real>
           </DataValue>
         </DataValues>
       </DataFrame>
diff --git a/src/gromacs/trajectoryanalysis/tests/refdata/AngleModuleTest_ComputesMultipleAngles.xml b/src/gromacs/trajectoryanalysis/tests/refdata/AngleModuleTest_ComputesMultipleAngles.xml
new file mode 100644 (file)
index 0000000..fccc0f7
--- /dev/null
@@ -0,0 +1,90 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <String Name="CommandLine">angle -g1 vector -group1 'resname RV1 RV2 and name A1 A2' 'resname RV3 RV4 and name A1 A2' -g2 plane -group2 'resname RP1 RP2 and name A1 A2 A3' 'resname RP1 RP2 and name A1 A2 A3' -binw 60</String>
+  <OutputData Name="Data">
+    <AnalysisData Name="angle">
+      <DataFrame Name="Frame0">
+        <Real Name="X">0.000000</Real>
+        <DataValues>
+          <Int Name="Count">2</Int>
+          <Int Name="DataSet">0</Int>
+          <DataValue>
+            <Real Name="Value">90.000000</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">45.000000</Real>
+          </DataValue>
+        </DataValues>
+        <DataValues>
+          <Int Name="Count">2</Int>
+          <Int Name="DataSet">1</Int>
+          <DataValue>
+            <Real Name="Value">90.000000</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">135.000000</Real>
+          </DataValue>
+        </DataValues>
+      </DataFrame>
+    </AnalysisData>
+    <AnalysisData Name="average">
+      <DataFrame Name="Frame0">
+        <Real Name="X">0.000000</Real>
+        <DataValues>
+          <Int Name="Count">2</Int>
+          <DataValue>
+            <Real Name="Value">67.500000</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">112.500000</Real>
+          </DataValue>
+        </DataValues>
+      </DataFrame>
+    </AnalysisData>
+    <AnalysisData Name="histogram">
+      <DataFrame Name="Frame0">
+        <Real Name="X">30.000000</Real>
+        <DataValues>
+          <Int Name="Count">2</Int>
+          <DataValue>
+            <Real Name="Value">0.008333</Real>
+            <Real Name="Error">0.000000</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">0.000000</Real>
+            <Real Name="Error">0.000000</Real>
+          </DataValue>
+        </DataValues>
+      </DataFrame>
+      <DataFrame Name="Frame1">
+        <Real Name="X">90.000000</Real>
+        <DataValues>
+          <Int Name="Count">2</Int>
+          <DataValue>
+            <Real Name="Value">0.008333</Real>
+            <Real Name="Error">0.000000</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">0.008333</Real>
+            <Real Name="Error">0.000000</Real>
+          </DataValue>
+        </DataValues>
+      </DataFrame>
+      <DataFrame Name="Frame2">
+        <Real Name="X">150.000000</Real>
+        <DataValues>
+          <Int Name="Count">2</Int>
+          <DataValue>
+            <Real Name="Value">0.000000</Real>
+            <Real Name="Error">0.000000</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">0.008333</Real>
+            <Real Name="Error">0.000000</Real>
+          </DataValue>
+        </DataValues>
+      </DataFrame>
+    </AnalysisData>
+  </OutputData>
+</ReferenceData>
index cdf24955d9daa491b3cef1ff762f34c0d7ad3532..9e58ae81a8b21c952297e4c645887faf6e99b84a 100644 (file)
       <DataFrame Name="Frame0">
         <Real Name="X">30.000000</Real>
         <DataValues>
-          <Int Name="Count">2</Int>
+          <Int Name="Count">1</Int>
           <DataValue>
             <Real Name="Value">0.008333</Real>
-          </DataValue>
-          <DataValue>
-            <Real Name="Value">0.000000</Real>
+            <Real Name="Error">0.000000</Real>
           </DataValue>
         </DataValues>
       </DataFrame>
       <DataFrame Name="Frame1">
         <Real Name="X">90.000000</Real>
         <DataValues>
-          <Int Name="Count">2</Int>
-          <DataValue>
-            <Real Name="Value">0.000000</Real>
-          </DataValue>
+          <Int Name="Count">1</Int>
           <DataValue>
             <Real Name="Value">0.000000</Real>
+            <Real Name="Error">0.000000</Real>
           </DataValue>
         </DataValues>
       </DataFrame>
       <DataFrame Name="Frame2">
         <Real Name="X">150.000000</Real>
         <DataValues>
-          <Int Name="Count">2</Int>
+          <Int Name="Count">1</Int>
           <DataValue>
             <Real Name="Value">0.008333</Real>
-          </DataValue>
-          <DataValue>
-            <Real Name="Value">0.000000</Real>
+            <Real Name="Error">0.000000</Real>
           </DataValue>
         </DataValues>
       </DataFrame>
index b995df6b81f9769db5e9e843cb90cccd3eb5be99..9f4e0e8f06d575efe25bd6e47d3c753fe17f6ac1 100644 (file)
       <DataFrame Name="Frame0">
         <Real Name="X">30.000000</Real>
         <DataValues>
-          <Int Name="Count">2</Int>
+          <Int Name="Count">1</Int>
           <DataValue>
             <Real Name="Value">0.008333</Real>
-          </DataValue>
-          <DataValue>
-            <Real Name="Value">0.000000</Real>
+            <Real Name="Error">0.000000</Real>
           </DataValue>
         </DataValues>
       </DataFrame>
       <DataFrame Name="Frame1">
         <Real Name="X">90.000000</Real>
         <DataValues>
-          <Int Name="Count">2</Int>
-          <DataValue>
-            <Real Name="Value">0.000000</Real>
-          </DataValue>
+          <Int Name="Count">1</Int>
           <DataValue>
             <Real Name="Value">0.000000</Real>
+            <Real Name="Error">0.000000</Real>
           </DataValue>
         </DataValues>
       </DataFrame>
       <DataFrame Name="Frame2">
         <Real Name="X">150.000000</Real>
         <DataValues>
-          <Int Name="Count">2</Int>
+          <Int Name="Count">1</Int>
           <DataValue>
             <Real Name="Value">0.008333</Real>
-          </DataValue>
-          <DataValue>
-            <Real Name="Value">0.000000</Real>
+            <Real Name="Error">0.000000</Real>
           </DataValue>
         </DataValues>
       </DataFrame>
index 1600814cb0affb0e790b2840c4e39668de8e13ba..fe2bd05879cd5e3d51912d5587787ffbce3f62f4 100644 (file)
       <DataFrame Name="Frame0">
         <Real Name="X">30.000000</Real>
         <DataValues>
-          <Int Name="Count">2</Int>
+          <Int Name="Count">1</Int>
           <DataValue>
             <Real Name="Value">0.008333</Real>
-          </DataValue>
-          <DataValue>
-            <Real Name="Value">0.000000</Real>
+            <Real Name="Error">0.000000</Real>
           </DataValue>
         </DataValues>
       </DataFrame>
       <DataFrame Name="Frame1">
         <Real Name="X">90.000000</Real>
         <DataValues>
-          <Int Name="Count">2</Int>
+          <Int Name="Count">1</Int>
           <DataValue>
             <Real Name="Value">0.008333</Real>
-          </DataValue>
-          <DataValue>
-            <Real Name="Value">0.000000</Real>
+            <Real Name="Error">0.000000</Real>
           </DataValue>
         </DataValues>
       </DataFrame>
       <DataFrame Name="Frame2">
         <Real Name="X">150.000000</Real>
         <DataValues>
-          <Int Name="Count">2</Int>
-          <DataValue>
-            <Real Name="Value">0.000000</Real>
-          </DataValue>
+          <Int Name="Count">1</Int>
           <DataValue>
             <Real Name="Value">0.000000</Real>
+            <Real Name="Error">0.000000</Real>
           </DataValue>
         </DataValues>
       </DataFrame>
index 255d191b9243c1d266c31c6e2613876b5314af40..aef2ce6d062a9f6b15c6c67f56f44b3745d2da4b 100644 (file)
       <DataFrame Name="Frame0">
         <Real Name="X">30.000000</Real>
         <DataValues>
-          <Int Name="Count">2</Int>
+          <Int Name="Count">1</Int>
           <DataValue>
             <Real Name="Value">0.008333</Real>
-          </DataValue>
-          <DataValue>
-            <Real Name="Value">0.000000</Real>
+            <Real Name="Error">0.000000</Real>
           </DataValue>
         </DataValues>
       </DataFrame>
       <DataFrame Name="Frame1">
         <Real Name="X">90.000000</Real>
         <DataValues>
-          <Int Name="Count">2</Int>
+          <Int Name="Count">1</Int>
           <DataValue>
             <Real Name="Value">0.008333</Real>
-          </DataValue>
-          <DataValue>
-            <Real Name="Value">0.000000</Real>
+            <Real Name="Error">0.000000</Real>
           </DataValue>
         </DataValues>
       </DataFrame>
       <DataFrame Name="Frame2">
         <Real Name="X">150.000000</Real>
         <DataValues>
-          <Int Name="Count">2</Int>
-          <DataValue>
-            <Real Name="Value">0.000000</Real>
-          </DataValue>
+          <Int Name="Count">1</Int>
           <DataValue>
             <Real Name="Value">0.000000</Real>
+            <Real Name="Error">0.000000</Real>
           </DataValue>
         </DataValues>
       </DataFrame>
index 5392df1bb2482ce288f817299cf977c94a1c9210..20c170c84356d7e22dbd9c78c0173d54d5629f09 100644 (file)
       <DataFrame Name="Frame0">
         <Real Name="X">30.000000</Real>
         <DataValues>
-          <Int Name="Count">2</Int>
+          <Int Name="Count">1</Int>
           <DataValue>
             <Real Name="Value">0.008333</Real>
-          </DataValue>
-          <DataValue>
-            <Real Name="Value">0.000000</Real>
+            <Real Name="Error">0.000000</Real>
           </DataValue>
         </DataValues>
       </DataFrame>
       <DataFrame Name="Frame1">
         <Real Name="X">90.000000</Real>
         <DataValues>
-          <Int Name="Count">2</Int>
+          <Int Name="Count">1</Int>
           <DataValue>
             <Real Name="Value">0.008333</Real>
-          </DataValue>
-          <DataValue>
-            <Real Name="Value">0.000000</Real>
+            <Real Name="Error">0.000000</Real>
           </DataValue>
         </DataValues>
       </DataFrame>
       <DataFrame Name="Frame2">
         <Real Name="X">150.000000</Real>
         <DataValues>
-          <Int Name="Count">2</Int>
-          <DataValue>
-            <Real Name="Value">0.000000</Real>
-          </DataValue>
+          <Int Name="Count">1</Int>
           <DataValue>
             <Real Name="Value">0.000000</Real>
+            <Real Name="Error">0.000000</Real>
           </DataValue>
         </DataValues>
       </DataFrame>
index 50ca1d66c794f61204617c205049f4b511bddc8f..dd0fb8e9347a5b10f0ab059695ad5d5536197da7 100644 (file)
       <DataFrame Name="Frame0">
         <Real Name="X">30.000000</Real>
         <DataValues>
-          <Int Name="Count">2</Int>
+          <Int Name="Count">1</Int>
           <DataValue>
             <Real Name="Value">0.012500</Real>
-          </DataValue>
-          <DataValue>
-            <Real Name="Value">0.005893</Real>
+            <Real Name="Error">0.005893</Real>
           </DataValue>
         </DataValues>
       </DataFrame>
       <DataFrame Name="Frame1">
         <Real Name="X">90.000000</Real>
         <DataValues>
-          <Int Name="Count">2</Int>
+          <Int Name="Count">1</Int>
           <DataValue>
             <Real Name="Value">0.002083</Real>
-          </DataValue>
-          <DataValue>
-            <Real Name="Value">0.002946</Real>
+            <Real Name="Error">0.002946</Real>
           </DataValue>
         </DataValues>
       </DataFrame>
       <DataFrame Name="Frame2">
         <Real Name="X">150.000000</Real>
         <DataValues>
-          <Int Name="Count">2</Int>
+          <Int Name="Count">1</Int>
           <DataValue>
             <Real Name="Value">0.002083</Real>
-          </DataValue>
-          <DataValue>
-            <Real Name="Value">0.002946</Real>
+            <Real Name="Error">0.002946</Real>
           </DataValue>
         </DataValues>
       </DataFrame>
diff --git a/src/gromacs/trajectoryanalysis/tests/refdata/AngleModuleTest_HandlesDynamicSelections.xml b/src/gromacs/trajectoryanalysis/tests/refdata/AngleModuleTest_HandlesDynamicSelections.xml
new file mode 100644 (file)
index 0000000..bbfadfd
--- /dev/null
@@ -0,0 +1,65 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <String Name="CommandLine">angle -g1 angle -group1 'resname RA1 RA2 and name A1 A2 A3 and z &lt; 0.5' -binw 60</String>
+  <OutputData Name="Data">
+    <AnalysisData Name="angle">
+      <DataFrame Name="Frame0">
+        <Real Name="X">0.000000</Real>
+        <DataValues>
+          <Int Name="Count">2</Int>
+          <DataValue>
+            <Real Name="Value">135.000000</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">45.000000</Real>
+            <Bool Name="Present">false</Bool>
+          </DataValue>
+        </DataValues>
+      </DataFrame>
+    </AnalysisData>
+    <AnalysisData Name="average">
+      <DataFrame Name="Frame0">
+        <Real Name="X">0.000000</Real>
+        <DataValues>
+          <Int Name="Count">1</Int>
+          <DataValue>
+            <Real Name="Value">135.000000</Real>
+          </DataValue>
+        </DataValues>
+      </DataFrame>
+    </AnalysisData>
+    <AnalysisData Name="histogram">
+      <DataFrame Name="Frame0">
+        <Real Name="X">30.000000</Real>
+        <DataValues>
+          <Int Name="Count">1</Int>
+          <DataValue>
+            <Real Name="Value">0.000000</Real>
+            <Real Name="Error">0.000000</Real>
+          </DataValue>
+        </DataValues>
+      </DataFrame>
+      <DataFrame Name="Frame1">
+        <Real Name="X">90.000000</Real>
+        <DataValues>
+          <Int Name="Count">1</Int>
+          <DataValue>
+            <Real Name="Value">0.000000</Real>
+            <Real Name="Error">0.000000</Real>
+          </DataValue>
+        </DataValues>
+      </DataFrame>
+      <DataFrame Name="Frame2">
+        <Real Name="X">150.000000</Real>
+        <DataValues>
+          <Int Name="Count">1</Int>
+          <DataValue>
+            <Real Name="Value">0.016667</Real>
+            <Real Name="Error">0.000000</Real>
+          </DataValue>
+        </DataValues>
+      </DataFrame>
+    </AnalysisData>
+  </OutputData>
+</ReferenceData>
diff --git a/src/gromacs/trajectoryanalysis/tests/refdata/DistanceModuleTest_ComputesDistances.xml b/src/gromacs/trajectoryanalysis/tests/refdata/DistanceModuleTest_ComputesDistances.xml
new file mode 100644 (file)
index 0000000..502ab46
--- /dev/null
@@ -0,0 +1,240 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <String Name="CommandLine">distance -select 'atomname S1 S2' -len 2 -binw 0.5</String>
+  <OutputData Name="Data">
+    <AnalysisData Name="allstats">
+      <DataFrame Name="Frame0">
+        <Real Name="X">0.000000</Real>
+        <DataValues>
+          <Int Name="Count">1</Int>
+          <DataValue>
+            <Real Name="Value">1.000000</Real>
+            <Real Name="Error">0.000000</Real>
+          </DataValue>
+        </DataValues>
+      </DataFrame>
+      <DataFrame Name="Frame1">
+        <Real Name="X">1.000000</Real>
+        <DataValues>
+          <Int Name="Count">1</Int>
+          <DataValue>
+            <Real Name="Value">1.000000</Real>
+            <Real Name="Error">0.000000</Real>
+          </DataValue>
+        </DataValues>
+      </DataFrame>
+      <DataFrame Name="Frame2">
+        <Real Name="X">2.000000</Real>
+        <DataValues>
+          <Int Name="Count">1</Int>
+          <DataValue>
+            <Real Name="Value">3.162278</Real>
+            <Real Name="Error">0.000000</Real>
+          </DataValue>
+        </DataValues>
+      </DataFrame>
+      <DataFrame Name="Frame3">
+        <Real Name="X">3.000000</Real>
+        <DataValues>
+          <Int Name="Count">1</Int>
+          <DataValue>
+            <Real Name="Value">1.000000</Real>
+            <Real Name="Error">0.000000</Real>
+          </DataValue>
+        </DataValues>
+      </DataFrame>
+      <DataFrame Name="Frame4">
+        <Real Name="X">4.000000</Real>
+        <DataValues>
+          <Int Name="Count">1</Int>
+          <DataValue>
+            <Real Name="Value">1.000000</Real>
+            <Real Name="Error">0.000000</Real>
+          </DataValue>
+        </DataValues>
+      </DataFrame>
+    </AnalysisData>
+    <AnalysisData Name="average">
+      <DataFrame Name="Frame0">
+        <Real Name="X">0.000000</Real>
+        <DataValues>
+          <Int Name="Count">1</Int>
+          <DataValue>
+            <Real Name="Value">1.432455</Real>
+          </DataValue>
+        </DataValues>
+      </DataFrame>
+    </AnalysisData>
+    <AnalysisData Name="dist">
+      <DataFrame Name="Frame0">
+        <Real Name="X">0.000000</Real>
+        <DataValues>
+          <Int Name="Count">5</Int>
+          <DataValue>
+            <Real Name="Value">1.000000</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">1.000000</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">3.162278</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">1.000000</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">1.000000</Real>
+          </DataValue>
+        </DataValues>
+      </DataFrame>
+    </AnalysisData>
+    <AnalysisData Name="histogram">
+      <DataFrame Name="Frame0">
+        <Real Name="X">0.250000</Real>
+        <DataValues>
+          <Int Name="Count">1</Int>
+          <DataValue>
+            <Real Name="Value">0.000000</Real>
+            <Real Name="Error">0.000000</Real>
+          </DataValue>
+        </DataValues>
+      </DataFrame>
+      <DataFrame Name="Frame1">
+        <Real Name="X">0.750000</Real>
+        <DataValues>
+          <Int Name="Count">1</Int>
+          <DataValue>
+            <Real Name="Value">0.000000</Real>
+            <Real Name="Error">0.000000</Real>
+          </DataValue>
+        </DataValues>
+      </DataFrame>
+      <DataFrame Name="Frame2">
+        <Real Name="X">1.250000</Real>
+        <DataValues>
+          <Int Name="Count">1</Int>
+          <DataValue>
+            <Real Name="Value">1.600000</Real>
+            <Real Name="Error">0.000000</Real>
+          </DataValue>
+        </DataValues>
+      </DataFrame>
+      <DataFrame Name="Frame3">
+        <Real Name="X">1.750000</Real>
+        <DataValues>
+          <Int Name="Count">1</Int>
+          <DataValue>
+            <Real Name="Value">0.000000</Real>
+            <Real Name="Error">0.000000</Real>
+          </DataValue>
+        </DataValues>
+      </DataFrame>
+      <DataFrame Name="Frame4">
+        <Real Name="X">2.250000</Real>
+        <DataValues>
+          <Int Name="Count">1</Int>
+          <DataValue>
+            <Real Name="Value">0.000000</Real>
+            <Real Name="Error">0.000000</Real>
+          </DataValue>
+        </DataValues>
+      </DataFrame>
+      <DataFrame Name="Frame5">
+        <Real Name="X">2.750000</Real>
+        <DataValues>
+          <Int Name="Count">1</Int>
+          <DataValue>
+            <Real Name="Value">0.000000</Real>
+            <Real Name="Error">0.000000</Real>
+          </DataValue>
+        </DataValues>
+      </DataFrame>
+      <DataFrame Name="Frame6">
+        <Real Name="X">3.250000</Real>
+        <DataValues>
+          <Int Name="Count">1</Int>
+          <DataValue>
+            <Real Name="Value">0.400000</Real>
+            <Real Name="Error">0.000000</Real>
+          </DataValue>
+        </DataValues>
+      </DataFrame>
+      <DataFrame Name="Frame7">
+        <Real Name="X">3.750000</Real>
+        <DataValues>
+          <Int Name="Count">1</Int>
+          <DataValue>
+            <Real Name="Value">0.000000</Real>
+            <Real Name="Error">0.000000</Real>
+          </DataValue>
+        </DataValues>
+      </DataFrame>
+    </AnalysisData>
+    <AnalysisData Name="stats">
+      <DataFrame Name="Frame0">
+        <Real Name="X">0.000000</Real>
+        <DataValues>
+          <Int Name="Count">1</Int>
+          <DataValue>
+            <Real Name="Value">1.432456</Real>
+            <Real Name="Error">0.967000</Real>
+          </DataValue>
+        </DataValues>
+      </DataFrame>
+    </AnalysisData>
+    <AnalysisData Name="xyz">
+      <DataFrame Name="Frame0">
+        <Real Name="X">0.000000</Real>
+        <DataValues>
+          <Int Name="Count">15</Int>
+          <DataValue>
+            <Real Name="Value">0.000000</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">1.000000</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">0.000000</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">0.000000</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">1.000000</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">0.000000</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">1.000000</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">-3.000000</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">0.000000</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">0.000000</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">1.000000</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">0.000000</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">0.000000</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">1.000000</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">0.000000</Real>
+          </DataValue>
+        </DataValues>
+      </DataFrame>
+    </AnalysisData>
+  </OutputData>
+</ReferenceData>
diff --git a/src/gromacs/trajectoryanalysis/tests/refdata/DistanceModuleTest_ComputesMultipleDistances.xml b/src/gromacs/trajectoryanalysis/tests/refdata/DistanceModuleTest_ComputesMultipleDistances.xml
new file mode 100644 (file)
index 0000000..bafee7c
--- /dev/null
@@ -0,0 +1,364 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <String Name="CommandLine">distance -select 'atomname S1 S2' 'resindex 1 to 4 and atomname CB merge resindex 2 to 5 and atomname CB' -len 2 -binw 0.5</String>
+  <OutputData Name="Data">
+    <AnalysisData Name="allstats">
+      <DataFrame Name="Frame0">
+        <Real Name="X">0.000000</Real>
+        <DataValues>
+          <Int Name="Count">2</Int>
+          <DataValue>
+            <Real Name="Value">1.000000</Real>
+            <Real Name="Error">0.000000</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">3.000000</Real>
+            <Real Name="Error">0.000000</Real>
+          </DataValue>
+        </DataValues>
+      </DataFrame>
+      <DataFrame Name="Frame1">
+        <Real Name="X">1.000000</Real>
+        <DataValues>
+          <Int Name="Count">2</Int>
+          <DataValue>
+            <Real Name="Value">1.000000</Real>
+            <Real Name="Error">0.000000</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">1.414214</Real>
+            <Real Name="Error">0.000000</Real>
+          </DataValue>
+        </DataValues>
+      </DataFrame>
+      <DataFrame Name="Frame2">
+        <Real Name="X">2.000000</Real>
+        <DataValues>
+          <Int Name="Count">2</Int>
+          <DataValue>
+            <Real Name="Value">3.162278</Real>
+            <Real Name="Error">0.000000</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">1.414214</Real>
+            <Real Name="Error">0.000000</Real>
+          </DataValue>
+        </DataValues>
+      </DataFrame>
+      <DataFrame Name="Frame3">
+        <Real Name="X">3.000000</Real>
+        <DataValues>
+          <Int Name="Count">2</Int>
+          <DataValue>
+            <Real Name="Value">1.000000</Real>
+            <Real Name="Error">0.000000</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">1.414214</Real>
+            <Real Name="Error">0.000000</Real>
+          </DataValue>
+        </DataValues>
+      </DataFrame>
+      <DataFrame Name="Frame4">
+        <Real Name="X">4.000000</Real>
+        <DataValues>
+          <Int Name="Count">2</Int>
+          <DataValue>
+            <Real Name="Value">1.000000</Real>
+            <Real Name="Error">0.000000</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">0.000000</Real>
+            <Real Name="Error">0.000000</Real>
+            <Bool Name="Present">false</Bool>
+          </DataValue>
+        </DataValues>
+      </DataFrame>
+    </AnalysisData>
+    <AnalysisData Name="average">
+      <DataFrame Name="Frame0">
+        <Real Name="X">0.000000</Real>
+        <DataValues>
+          <Int Name="Count">2</Int>
+          <DataValue>
+            <Real Name="Value">1.432455</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">1.810660</Real>
+          </DataValue>
+        </DataValues>
+      </DataFrame>
+    </AnalysisData>
+    <AnalysisData Name="dist">
+      <DataFrame Name="Frame0">
+        <Real Name="X">0.000000</Real>
+        <DataValues>
+          <Int Name="Count">5</Int>
+          <Int Name="DataSet">0</Int>
+          <DataValue>
+            <Real Name="Value">1.000000</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">1.000000</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">3.162278</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">1.000000</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">1.000000</Real>
+          </DataValue>
+        </DataValues>
+        <DataValues>
+          <Int Name="Count">4</Int>
+          <Int Name="DataSet">1</Int>
+          <DataValue>
+            <Real Name="Value">3.000000</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">1.414214</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">1.414214</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">1.414214</Real>
+          </DataValue>
+        </DataValues>
+      </DataFrame>
+    </AnalysisData>
+    <AnalysisData Name="histogram">
+      <DataFrame Name="Frame0">
+        <Real Name="X">0.250000</Real>
+        <DataValues>
+          <Int Name="Count">2</Int>
+          <DataValue>
+            <Real Name="Value">0.000000</Real>
+            <Real Name="Error">0.000000</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">0.000000</Real>
+            <Real Name="Error">0.000000</Real>
+          </DataValue>
+        </DataValues>
+      </DataFrame>
+      <DataFrame Name="Frame1">
+        <Real Name="X">0.750000</Real>
+        <DataValues>
+          <Int Name="Count">2</Int>
+          <DataValue>
+            <Real Name="Value">0.000000</Real>
+            <Real Name="Error">0.000000</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">0.000000</Real>
+            <Real Name="Error">0.000000</Real>
+          </DataValue>
+        </DataValues>
+      </DataFrame>
+      <DataFrame Name="Frame2">
+        <Real Name="X">1.250000</Real>
+        <DataValues>
+          <Int Name="Count">2</Int>
+          <DataValue>
+            <Real Name="Value">1.600000</Real>
+            <Real Name="Error">0.000000</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">1.500000</Real>
+            <Real Name="Error">0.000000</Real>
+          </DataValue>
+        </DataValues>
+      </DataFrame>
+      <DataFrame Name="Frame3">
+        <Real Name="X">1.750000</Real>
+        <DataValues>
+          <Int Name="Count">2</Int>
+          <DataValue>
+            <Real Name="Value">0.000000</Real>
+            <Real Name="Error">0.000000</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">0.000000</Real>
+            <Real Name="Error">0.000000</Real>
+          </DataValue>
+        </DataValues>
+      </DataFrame>
+      <DataFrame Name="Frame4">
+        <Real Name="X">2.250000</Real>
+        <DataValues>
+          <Int Name="Count">2</Int>
+          <DataValue>
+            <Real Name="Value">0.000000</Real>
+            <Real Name="Error">0.000000</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">0.000000</Real>
+            <Real Name="Error">0.000000</Real>
+          </DataValue>
+        </DataValues>
+      </DataFrame>
+      <DataFrame Name="Frame5">
+        <Real Name="X">2.750000</Real>
+        <DataValues>
+          <Int Name="Count">2</Int>
+          <DataValue>
+            <Real Name="Value">0.000000</Real>
+            <Real Name="Error">0.000000</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">0.000000</Real>
+            <Real Name="Error">0.000000</Real>
+          </DataValue>
+        </DataValues>
+      </DataFrame>
+      <DataFrame Name="Frame6">
+        <Real Name="X">3.250000</Real>
+        <DataValues>
+          <Int Name="Count">2</Int>
+          <DataValue>
+            <Real Name="Value">0.400000</Real>
+            <Real Name="Error">0.000000</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">0.500000</Real>
+            <Real Name="Error">0.000000</Real>
+          </DataValue>
+        </DataValues>
+      </DataFrame>
+      <DataFrame Name="Frame7">
+        <Real Name="X">3.750000</Real>
+        <DataValues>
+          <Int Name="Count">2</Int>
+          <DataValue>
+            <Real Name="Value">0.000000</Real>
+            <Real Name="Error">0.000000</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">0.000000</Real>
+            <Real Name="Error">0.000000</Real>
+          </DataValue>
+        </DataValues>
+      </DataFrame>
+    </AnalysisData>
+    <AnalysisData Name="stats">
+      <DataFrame Name="Frame0">
+        <Real Name="X">0.000000</Real>
+        <DataValues>
+          <Int Name="Count">1</Int>
+          <DataValue>
+            <Real Name="Value">1.432456</Real>
+            <Real Name="Error">0.967000</Real>
+          </DataValue>
+        </DataValues>
+      </DataFrame>
+      <DataFrame Name="Frame1">
+        <Real Name="X">1.000000</Real>
+        <DataValues>
+          <Int Name="Count">1</Int>
+          <DataValue>
+            <Real Name="Value">1.810660</Real>
+            <Real Name="Error">0.792893</Real>
+          </DataValue>
+        </DataValues>
+      </DataFrame>
+    </AnalysisData>
+    <AnalysisData Name="xyz">
+      <DataFrame Name="Frame0">
+        <Real Name="X">0.000000</Real>
+        <DataValues>
+          <Int Name="Count">15</Int>
+          <Int Name="DataSet">0</Int>
+          <DataValue>
+            <Real Name="Value">0.000000</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">1.000000</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">0.000000</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">0.000000</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">1.000000</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">0.000000</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">1.000000</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">-3.000000</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">0.000000</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">0.000000</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">1.000000</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">0.000000</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">0.000000</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">1.000000</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">0.000000</Real>
+          </DataValue>
+        </DataValues>
+        <DataValues>
+          <Int Name="Count">12</Int>
+          <Int Name="DataSet">1</Int>
+          <DataValue>
+            <Real Name="Value">0.000000</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">3.000000</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">0.000000</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">1.000000</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">-1.000000</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">0.000000</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">1.000000</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">-1.000000</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">0.000000</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">1.000000</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">-1.000000</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">0.000000</Real>
+          </DataValue>
+        </DataValues>
+      </DataFrame>
+    </AnalysisData>
+  </OutputData>
+</ReferenceData>
diff --git a/src/gromacs/trajectoryanalysis/tests/refdata/DistanceModuleTest_HandlesDynamicSelections.xml b/src/gromacs/trajectoryanalysis/tests/refdata/DistanceModuleTest_HandlesDynamicSelections.xml
new file mode 100644 (file)
index 0000000..6c879f4
--- /dev/null
@@ -0,0 +1,242 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <String Name="CommandLine">distance -select 'atomname S1 S2 and res_cog x &lt; 2.8' -len 2 -binw 0.5</String>
+  <OutputData Name="Data">
+    <AnalysisData Name="allstats">
+      <DataFrame Name="Frame0">
+        <Real Name="X">0.000000</Real>
+        <DataValues>
+          <Int Name="Count">1</Int>
+          <DataValue>
+            <Real Name="Value">1.000000</Real>
+            <Real Name="Error">0.000000</Real>
+          </DataValue>
+        </DataValues>
+      </DataFrame>
+      <DataFrame Name="Frame1">
+        <Real Name="X">1.000000</Real>
+        <DataValues>
+          <Int Name="Count">1</Int>
+          <DataValue>
+            <Real Name="Value">1.000000</Real>
+            <Real Name="Error">0.000000</Real>
+          </DataValue>
+        </DataValues>
+      </DataFrame>
+      <DataFrame Name="Frame2">
+        <Real Name="X">2.000000</Real>
+        <DataValues>
+          <Int Name="Count">1</Int>
+          <DataValue>
+            <Real Name="Value">3.162278</Real>
+            <Real Name="Error">0.000000</Real>
+          </DataValue>
+        </DataValues>
+      </DataFrame>
+      <DataFrame Name="Frame3">
+        <Real Name="X">3.000000</Real>
+        <DataValues>
+          <Int Name="Count">1</Int>
+          <DataValue>
+            <Real Name="Value">0.000000</Real>
+            <Real Name="Error">0.000000</Real>
+          </DataValue>
+        </DataValues>
+      </DataFrame>
+      <DataFrame Name="Frame4">
+        <Real Name="X">4.000000</Real>
+        <DataValues>
+          <Int Name="Count">1</Int>
+          <DataValue>
+            <Real Name="Value">0.000000</Real>
+            <Real Name="Error">0.000000</Real>
+          </DataValue>
+        </DataValues>
+      </DataFrame>
+    </AnalysisData>
+    <AnalysisData Name="average">
+      <DataFrame Name="Frame0">
+        <Real Name="X">0.000000</Real>
+        <DataValues>
+          <Int Name="Count">1</Int>
+          <DataValue>
+            <Real Name="Value">1.720759</Real>
+          </DataValue>
+        </DataValues>
+      </DataFrame>
+    </AnalysisData>
+    <AnalysisData Name="dist">
+      <DataFrame Name="Frame0">
+        <Real Name="X">0.000000</Real>
+        <DataValues>
+          <Int Name="Count">5</Int>
+          <DataValue>
+            <Real Name="Value">1.000000</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">1.000000</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">3.162278</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">1.000000</Real>
+            <Bool Name="Present">false</Bool>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">1.000000</Real>
+            <Bool Name="Present">false</Bool>
+          </DataValue>
+        </DataValues>
+      </DataFrame>
+    </AnalysisData>
+    <AnalysisData Name="histogram">
+      <DataFrame Name="Frame0">
+        <Real Name="X">0.250000</Real>
+        <DataValues>
+          <Int Name="Count">1</Int>
+          <DataValue>
+            <Real Name="Value">0.000000</Real>
+            <Real Name="Error">0.000000</Real>
+          </DataValue>
+        </DataValues>
+      </DataFrame>
+      <DataFrame Name="Frame1">
+        <Real Name="X">0.750000</Real>
+        <DataValues>
+          <Int Name="Count">1</Int>
+          <DataValue>
+            <Real Name="Value">0.000000</Real>
+            <Real Name="Error">0.000000</Real>
+          </DataValue>
+        </DataValues>
+      </DataFrame>
+      <DataFrame Name="Frame2">
+        <Real Name="X">1.250000</Real>
+        <DataValues>
+          <Int Name="Count">1</Int>
+          <DataValue>
+            <Real Name="Value">1.333333</Real>
+            <Real Name="Error">0.000000</Real>
+          </DataValue>
+        </DataValues>
+      </DataFrame>
+      <DataFrame Name="Frame3">
+        <Real Name="X">1.750000</Real>
+        <DataValues>
+          <Int Name="Count">1</Int>
+          <DataValue>
+            <Real Name="Value">0.000000</Real>
+            <Real Name="Error">0.000000</Real>
+          </DataValue>
+        </DataValues>
+      </DataFrame>
+      <DataFrame Name="Frame4">
+        <Real Name="X">2.250000</Real>
+        <DataValues>
+          <Int Name="Count">1</Int>
+          <DataValue>
+            <Real Name="Value">0.000000</Real>
+            <Real Name="Error">0.000000</Real>
+          </DataValue>
+        </DataValues>
+      </DataFrame>
+      <DataFrame Name="Frame5">
+        <Real Name="X">2.750000</Real>
+        <DataValues>
+          <Int Name="Count">1</Int>
+          <DataValue>
+            <Real Name="Value">0.000000</Real>
+            <Real Name="Error">0.000000</Real>
+          </DataValue>
+        </DataValues>
+      </DataFrame>
+      <DataFrame Name="Frame6">
+        <Real Name="X">3.250000</Real>
+        <DataValues>
+          <Int Name="Count">1</Int>
+          <DataValue>
+            <Real Name="Value">0.666667</Real>
+            <Real Name="Error">0.000000</Real>
+          </DataValue>
+        </DataValues>
+      </DataFrame>
+      <DataFrame Name="Frame7">
+        <Real Name="X">3.750000</Real>
+        <DataValues>
+          <Int Name="Count">1</Int>
+          <DataValue>
+            <Real Name="Value">0.000000</Real>
+            <Real Name="Error">0.000000</Real>
+          </DataValue>
+        </DataValues>
+      </DataFrame>
+    </AnalysisData>
+    <AnalysisData Name="stats">
+      <DataFrame Name="Frame0">
+        <Real Name="X">0.000000</Real>
+        <DataValues>
+          <Int Name="Count">1</Int>
+          <DataValue>
+            <Real Name="Value">1.720759</Real>
+            <Real Name="Error">1.248392</Real>
+          </DataValue>
+        </DataValues>
+      </DataFrame>
+    </AnalysisData>
+    <AnalysisData Name="xyz">
+      <DataFrame Name="Frame0">
+        <Real Name="X">0.000000</Real>
+        <DataValues>
+          <Int Name="Count">15</Int>
+          <DataValue>
+            <Real Name="Value">0.000000</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">1.000000</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">0.000000</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">0.000000</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">1.000000</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">0.000000</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">1.000000</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">-3.000000</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">0.000000</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">0.000000</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">1.000000</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">0.000000</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">0.000000</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">1.000000</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">0.000000</Real>
+          </DataValue>
+        </DataValues>
+      </DataFrame>
+    </AnalysisData>
+  </OutputData>
+</ReferenceData>
index 2854405eb8dd085d805435568224caaa937da9d3..fa89932026cd674cb1c49e1267787cee142af882 100644 (file)
         </DataValues>
       </DataFrame>
     </AnalysisData>
+    <AnalysisData Name="lifetime">
+      <DataFrame Name="Frame0">
+        <Real Name="X">0.000000</Real>
+        <DataValues>
+          <Int Name="Count">2</Int>
+          <DataValue>
+            <Real Name="Value">8.000000</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">6.000000</Real>
+          </DataValue>
+        </DataValues>
+      </DataFrame>
+      <DataFrame Name="Frame1">
+        <Real Name="X">0.000000</Real>
+        <DataValues>
+          <Int Name="Count">2</Int>
+          <DataValue>
+            <Real Name="Value">3.000000</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">6.000000</Real>
+          </DataValue>
+        </DataValues>
+      </DataFrame>
+    </AnalysisData>
     <AnalysisData Name="mask">
       <DataFrame Name="Frame0">
         <Real Name="X">0.000000</Real>
         <DataValues>
           <Int Name="Count">15</Int>
+          <Int Name="DataSet">0</Int>
           <DataValue>
             <Real Name="Value">1.000000</Real>
           </DataValue>
             <Real Name="Value">0.000000</Real>
           </DataValue>
         </DataValues>
+        <DataValues>
+          <Int Name="Count">6</Int>
+          <Int Name="DataSet">1</Int>
+          <DataValue>
+            <Real Name="Value">1.000000</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">1.000000</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">1.000000</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">1.000000</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">1.000000</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">1.000000</Real>
+          </DataValue>
+        </DataValues>
       </DataFrame>
       <DataFrame Name="Frame1">
         <Real Name="X">0.000000</Real>
         <DataValues>
           <Int Name="Count">15</Int>
+          <Int Name="DataSet">0</Int>
           <DataValue>
             <Real Name="Value">1.000000</Real>
           </DataValue>
             <Real Name="Value">0.000000</Real>
           </DataValue>
         </DataValues>
+        <DataValues>
+          <Int Name="Count">6</Int>
+          <Int Name="DataSet">1</Int>
+          <DataValue>
+            <Real Name="Value">1.000000</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">1.000000</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">1.000000</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">1.000000</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">1.000000</Real>
+          </DataValue>
+          <DataValue>
+            <Real Name="Value">1.000000</Real>
+          </DataValue>
+        </DataValues>
       </DataFrame>
     </AnalysisData>
     <AnalysisData Name="occupancy">
           <Int Name="Count">2</Int>
           <DataValue>
             <Real Name="Value">1.000000</Real>
+            <Real Name="Error">0.000000</Real>
           </DataValue>
           <DataValue>
-            <Real Name="Value">0.000000</Real>
+            <Real Name="Value">1.000000</Real>
+            <Real Name="Error">0.000000</Real>
           </DataValue>
         </DataValues>
       </DataFrame>
           <Int Name="Count">2</Int>
           <DataValue>
             <Real Name="Value">0.500000</Real>
+            <Real Name="Error">0.707107</Real>
           </DataValue>
           <DataValue>
-            <Real Name="Value">0.707107</Real>
+            <Real Name="Value">1.000000</Real>
+            <Real Name="Error">0.000000</Real>
           </DataValue>
         </DataValues>
       </DataFrame>
           <Int Name="Count">2</Int>
           <DataValue>
             <Real Name="Value">0.500000</Real>
+            <Real Name="Error">0.707107</Real>
           </DataValue>
           <DataValue>
-            <Real Name="Value">0.707107</Real>
+            <Real Name="Value">1.000000</Real>
+            <Real Name="Error">0.000000</Real>
           </DataValue>
         </DataValues>
       </DataFrame>
           <Int Name="Count">2</Int>
           <DataValue>
             <Real Name="Value">0.500000</Real>
+            <Real Name="Error">0.707107</Real>
           </DataValue>
           <DataValue>
-            <Real Name="Value">0.707107</Real>
+            <Real Name="Value">1.000000</Real>
+            <Real Name="Error">0.000000</Real>
           </DataValue>
         </DataValues>
       </DataFrame>
           <Int Name="Count">2</Int>
           <DataValue>
             <Real Name="Value">0.500000</Real>
+            <Real Name="Error">0.707107</Real>
           </DataValue>
           <DataValue>
-            <Real Name="Value">0.707107</Real>
+            <Real Name="Value">1.000000</Real>
+            <Real Name="Error">0.000000</Real>
           </DataValue>
         </DataValues>
       </DataFrame>
           <Int Name="Count">2</Int>
           <DataValue>
             <Real Name="Value">0.500000</Real>
+            <Real Name="Error">0.707107</Real>
           </DataValue>
           <DataValue>
-            <Real Name="Value">0.707107</Real>
+            <Real Name="Value">1.000000</Real>
+            <Real Name="Error">0.000000</Real>
           </DataValue>
         </DataValues>
       </DataFrame>
           <Int Name="Count">2</Int>
           <DataValue>
             <Real Name="Value">0.500000</Real>
+            <Real Name="Error">0.707107</Real>
           </DataValue>
           <DataValue>
-            <Real Name="Value">0.707107</Real>
+            <Real Name="Value">0.000000</Real>
+            <Real Name="Error">0.000000</Real>
+            <Bool Name="Present">false</Bool>
           </DataValue>
         </DataValues>
       </DataFrame>
           <Int Name="Count">2</Int>
           <DataValue>
             <Real Name="Value">0.500000</Real>
+            <Real Name="Error">0.707107</Real>
           </DataValue>
           <DataValue>
-            <Real Name="Value">0.707107</Real>
+            <Real Name="Value">0.000000</Real>
+            <Real Name="Error">0.000000</Real>
+            <Bool Name="Present">false</Bool>
           </DataValue>
         </DataValues>
       </DataFrame>
           <Int Name="Count">2</Int>
           <DataValue>
             <Real Name="Value">1.000000</Real>
+            <Real Name="Error">0.000000</Real>
           </DataValue>
           <DataValue>
             <Real Name="Value">0.000000</Real>
+            <Real Name="Error">0.000000</Real>
+            <Bool Name="Present">false</Bool>
           </DataValue>
         </DataValues>
       </DataFrame>
           <Int Name="Count">2</Int>
           <DataValue>
             <Real Name="Value">0.500000</Real>
+            <Real Name="Error">0.707107</Real>
           </DataValue>
           <DataValue>
-            <Real Name="Value">0.707107</Real>
+            <Real Name="Value">0.000000</Real>
+            <Real Name="Error">0.000000</Real>
+            <Bool Name="Present">false</Bool>
           </DataValue>
         </DataValues>
       </DataFrame>
           <Int Name="Count">2</Int>
           <DataValue>
             <Real Name="Value">0.000000</Real>
+            <Real Name="Error">0.000000</Real>
           </DataValue>
           <DataValue>
             <Real Name="Value">0.000000</Real>
+            <Real Name="Error">0.000000</Real>
+            <Bool Name="Present">false</Bool>
           </DataValue>
         </DataValues>
       </DataFrame>
           <Int Name="Count">2</Int>
           <DataValue>
             <Real Name="Value">0.500000</Real>
+            <Real Name="Error">0.707107</Real>
           </DataValue>
           <DataValue>
-            <Real Name="Value">0.707107</Real>
+            <Real Name="Value">0.000000</Real>
+            <Real Name="Error">0.000000</Real>
+            <Bool Name="Present">false</Bool>
           </DataValue>
         </DataValues>
       </DataFrame>
           <Int Name="Count">2</Int>
           <DataValue>
             <Real Name="Value">1.000000</Real>
+            <Real Name="Error">0.000000</Real>
           </DataValue>
           <DataValue>
             <Real Name="Value">0.000000</Real>
+            <Real Name="Error">0.000000</Real>
+            <Bool Name="Present">false</Bool>
           </DataValue>
         </DataValues>
       </DataFrame>
           <Int Name="Count">2</Int>
           <DataValue>
             <Real Name="Value">0.500000</Real>
+            <Real Name="Error">0.707107</Real>
           </DataValue>
           <DataValue>
-            <Real Name="Value">0.707107</Real>
+            <Real Name="Value">0.000000</Real>
+            <Real Name="Error">0.000000</Real>
+            <Bool Name="Present">false</Bool>
           </DataValue>
         </DataValues>
       </DataFrame>
           <Int Name="Count">2</Int>
           <DataValue>
             <Real Name="Value">0.000000</Real>
+            <Real Name="Error">0.000000</Real>
           </DataValue>
           <DataValue>
             <Real Name="Value">0.000000</Real>
+            <Real Name="Error">0.000000</Real>
+            <Bool Name="Present">false</Bool>
           </DataValue>
         </DataValues>
       </DataFrame>
diff --git a/src/gromacs/trajectoryanalysis/tests/refdata/SelectModuleTest_HandlesDumpOption.xml b/src/gromacs/trajectoryanalysis/tests/refdata/SelectModuleTest_HandlesDumpOption.xml
deleted file mode 100644 (file)
index 761e20d..0000000
+++ /dev/null
@@ -1,89 +0,0 @@
-<?xml version="1.0"?>
-<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
-<ReferenceData>
-  <String Name="CommandLine">select -select 'y &lt; 2.5' -dump</String>
-  <OutputData Name="Data">
-    <AnalysisData Name="index">
-      <DataFrame Name="Frame0">
-        <Real Name="X">0.000000</Real>
-        <DataValues>
-          <Int Name="Count">1</Int>
-          <Int Name="FirstColumn">0</Int>
-          <Int Name="LastColumn">0</Int>
-          <DataValue>
-            <Real Name="Value">8.000000</Real>
-          </DataValue>
-        </DataValues>
-        <DataValues>
-          <Int Name="Count">1</Int>
-          <Int Name="FirstColumn">1</Int>
-          <Int Name="LastColumn">1</Int>
-          <DataValue>
-            <Real Name="Value">1.000000</Real>
-          </DataValue>
-        </DataValues>
-        <DataValues>
-          <Int Name="Count">1</Int>
-          <Int Name="FirstColumn">1</Int>
-          <Int Name="LastColumn">1</Int>
-          <DataValue>
-            <Real Name="Value">2.000000</Real>
-          </DataValue>
-        </DataValues>
-        <DataValues>
-          <Int Name="Count">1</Int>
-          <Int Name="FirstColumn">1</Int>
-          <Int Name="LastColumn">1</Int>
-          <DataValue>
-            <Real Name="Value">5.000000</Real>
-          </DataValue>
-        </DataValues>
-        <DataValues>
-          <Int Name="Count">1</Int>
-          <Int Name="FirstColumn">1</Int>
-          <Int Name="LastColumn">1</Int>
-          <DataValue>
-            <Real Name="Value">6.000000</Real>
-          </DataValue>
-        </DataValues>
-        <DataValues>
-          <Int Name="Count">1</Int>
-          <Int Name="FirstColumn">1</Int>
-          <Int Name="LastColumn">1</Int>
-          <DataValue>
-            <Real Name="Value">9.000000</Real>
-          </DataValue>
-        </DataValues>
-        <DataValues>
-          <Int Name="Count">1</Int>
-          <Int Name="FirstColumn">1</Int>
-          <Int Name="LastColumn">1</Int>
-          <DataValue>
-            <Real Name="Value">10.000000</Real>
-          </DataValue>
-        </DataValues>
-        <DataValues>
-          <Int Name="Count">1</Int>
-          <Int Name="FirstColumn">1</Int>
-          <Int Name="LastColumn">1</Int>
-          <DataValue>
-            <Real Name="Value">13.000000</Real>
-          </DataValue>
-        </DataValues>
-        <DataValues>
-          <Int Name="Count">1</Int>
-          <Int Name="FirstColumn">1</Int>
-          <Int Name="LastColumn">1</Int>
-          <DataValue>
-            <Real Name="Value">14.000000</Real>
-          </DataValue>
-        </DataValues>
-      </DataFrame>
-    </AnalysisData>
-  </OutputData>
-  <OutputFiles Name="Files">
-    <String Name="-oi"><![CDATA[
-    1    2    5    6    9   10   13   14
-]]></String>
-  </OutputFiles>
-</ReferenceData>
index e41478da2d6987b244699dfff95354a9eca29579..15896efd25d4c5d4216fec3239a2930438e39fc5 100644 (file)
@@ -1,7 +1,7 @@
 <?xml version="1.0"?>
 <?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
 <ReferenceData>
-  <String Name="CommandLine">select -select 'resname RA RD and y &lt; 2.5' -pdbatoms maxsel</String>
+  <String Name="CommandLine">select -select 'resname RA RD and y &lt; 2.5' 'resname RA RB' -pdbatoms maxsel</String>
   <OutputData Name="Data">
     <AnalysisData Name="occupancy">
       <DataFrame Name="Frame0">
           <Int Name="Count">2</Int>
           <DataValue>
             <Real Name="Value">1.000000</Real>
+            <Real Name="Error">0.000000</Real>
           </DataValue>
           <DataValue>
-            <Real Name="Value">0.000000</Real>
+            <Real Name="Value">1.000000</Real>
+            <Real Name="Error">0.000000</Real>
           </DataValue>
         </DataValues>
       </DataFrame>
           <Int Name="Count">2</Int>
           <DataValue>
             <Real Name="Value">0.500000</Real>
+            <Real Name="Error">0.707107</Real>
           </DataValue>
           <DataValue>
-            <Real Name="Value">0.707107</Real>
+            <Real Name="Value">1.000000</Real>
+            <Real Name="Error">0.000000</Real>
           </DataValue>
         </DataValues>
       </DataFrame>
           <Int Name="Count">2</Int>
           <DataValue>
             <Real Name="Value">0.500000</Real>
+            <Real Name="Error">0.707107</Real>
           </DataValue>
           <DataValue>
-            <Real Name="Value">0.707107</Real>
+            <Real Name="Value">1.000000</Real>
+            <Real Name="Error">0.000000</Real>
           </DataValue>
         </DataValues>
       </DataFrame>
           <Int Name="Count">2</Int>
           <DataValue>
             <Real Name="Value">0.500000</Real>
+            <Real Name="Error">0.707107</Real>
           </DataValue>
           <DataValue>
-            <Real Name="Value">0.707107</Real>
+            <Real Name="Value">1.000000</Real>
+            <Real Name="Error">0.000000</Real>
           </DataValue>
         </DataValues>
       </DataFrame>
           <Int Name="Count">2</Int>
           <DataValue>
             <Real Name="Value">0.500000</Real>
+            <Real Name="Error">0.707107</Real>
           </DataValue>
           <DataValue>
-            <Real Name="Value">0.707107</Real>
+            <Real Name="Value">1.000000</Real>
+            <Real Name="Error">0.000000</Real>
           </DataValue>
         </DataValues>
       </DataFrame>
           <Int Name="Count">2</Int>
           <DataValue>
             <Real Name="Value">1.000000</Real>
+            <Real Name="Error">0.000000</Real>
           </DataValue>
           <DataValue>
-            <Real Name="Value">0.000000</Real>
+            <Real Name="Value">1.000000</Real>
+            <Real Name="Error">0.000000</Real>
           </DataValue>
         </DataValues>
       </DataFrame>
           <Int Name="Count">2</Int>
           <DataValue>
             <Real Name="Value">1.000000</Real>
+            <Real Name="Error">0.000000</Real>
           </DataValue>
           <DataValue>
-            <Real Name="Value">0.000000</Real>
+            <Real Name="Value">1.000000</Real>
+            <Real Name="Error">0.000000</Real>
           </DataValue>
         </DataValues>
       </DataFrame>
           <Int Name="Count">2</Int>
           <DataValue>
             <Real Name="Value">0.500000</Real>
+            <Real Name="Error">0.707107</Real>
           </DataValue>
           <DataValue>
-            <Real Name="Value">0.707107</Real>
+            <Real Name="Value">1.000000</Real>
+            <Real Name="Error">0.000000</Real>
           </DataValue>
         </DataValues>
       </DataFrame>
           <Int Name="Count">2</Int>
           <DataValue>
             <Real Name="Value">0.000000</Real>
+            <Real Name="Error">0.000000</Real>
           </DataValue>
           <DataValue>
-            <Real Name="Value">0.000000</Real>
+            <Real Name="Value">1.000000</Real>
+            <Real Name="Error">0.000000</Real>
           </DataValue>
         </DataValues>
       </DataFrame>
@@ -120,12 +138,15 @@ TITLE     frame t= 0.000
 REMARK    THIS IS A SIMULATION BOX
 CRYST1  100.000  100.000  100.000  90.00  90.00  90.00 P 1           1
 MODEL        1
-ATOM      1  CB   RA A   1      10.000  10.000   0.000  1.00  0.00            
-ATOM      2  S1   RA A   1      10.000  20.000   0.000  0.50  0.00            
-ATOM      3  S2   RA A   1      10.000  30.000   0.000  0.50  0.00            
-ATOM      7  CB   RA B   1      20.000  30.000   0.000  0.50  0.00            
-ATOM      8  S1   RA B   1      20.000  40.000   0.000  0.50  0.30            
-ATOM      9  S2   RA B   1      30.000  10.000   0.000  1.00  0.30            
+ATOM      1  CB   RA A   1      10.000  10.000   0.000  2.00  0.00            
+ATOM      2  S1   RA A   1      10.000  20.000   0.000  1.50  0.00            
+ATOM      3  S2   RA A   1      10.000  30.000   0.000  1.50  0.00            
+ATOM      4  CB   RB A   2      10.000  40.000   0.000  1.00  0.50            
+ATOM      5  S1   RB A   2      20.000  10.000   0.000  1.00  0.50            
+ATOM      6  S2   RB A   2      20.000  20.000   0.000  1.00  0.50            
+ATOM      7  CB   RA B   1      20.000  30.000   0.000  1.50  0.00            
+ATOM      8  S1   RA B   1      20.000  40.000   0.000  1.50  0.30            
+ATOM      9  S2   RA B   1      30.000  10.000   0.000  2.00  0.30            
 ATOM     13  CB   RD B   2      40.000  10.000   0.000  1.00  0.00            
 ATOM     14  S1   RD B   2      40.000  20.000   0.000  0.50  0.00            
 ATOM     15  S2   RD B   2      40.000  30.000   0.000  0.00  0.00            
index b53341d8144a891ac1cb91330e9126fe692af446..e0d25925f9dafe2d663b8120e5fc13cf04e1441e 100644 (file)
       <DataFrame Name="Frame0">
         <Real Name="X">1.000000</Real>
         <DataValues>
-          <Int Name="Count">2</Int>
+          <Int Name="Count">1</Int>
           <DataValue>
             <Real Name="Value">1.000000</Real>
-          </DataValue>
-          <DataValue>
-            <Real Name="Value">0.000000</Real>
+            <Real Name="Error">0.000000</Real>
           </DataValue>
         </DataValues>
       </DataFrame>
       <DataFrame Name="Frame1">
         <Real Name="X">2.000000</Real>
         <DataValues>
-          <Int Name="Count">2</Int>
+          <Int Name="Count">1</Int>
           <DataValue>
             <Real Name="Value">0.500000</Real>
-          </DataValue>
-          <DataValue>
-            <Real Name="Value">0.707107</Real>
+            <Real Name="Error">0.707107</Real>
           </DataValue>
         </DataValues>
       </DataFrame>
       <DataFrame Name="Frame2">
         <Real Name="X">3.000000</Real>
         <DataValues>
-          <Int Name="Count">2</Int>
+          <Int Name="Count">1</Int>
           <DataValue>
             <Real Name="Value">0.500000</Real>
-          </DataValue>
-          <DataValue>
-            <Real Name="Value">0.707107</Real>
+            <Real Name="Error">0.707107</Real>
           </DataValue>
         </DataValues>
       </DataFrame>
       <DataFrame Name="Frame3">
         <Real Name="X">4.000000</Real>
         <DataValues>
-          <Int Name="Count">2</Int>
+          <Int Name="Count">1</Int>
           <DataValue>
             <Real Name="Value">0.500000</Real>
-          </DataValue>
-          <DataValue>
-            <Real Name="Value">0.707107</Real>
+            <Real Name="Error">0.707107</Real>
           </DataValue>
         </DataValues>
       </DataFrame>
       <DataFrame Name="Frame4">
         <Real Name="X">5.000000</Real>
         <DataValues>
-          <Int Name="Count">2</Int>
+          <Int Name="Count">1</Int>
           <DataValue>
             <Real Name="Value">0.500000</Real>
-          </DataValue>
-          <DataValue>
-            <Real Name="Value">0.707107</Real>
+            <Real Name="Error">0.707107</Real>
           </DataValue>
         </DataValues>
       </DataFrame>
       <DataFrame Name="Frame5">
         <Real Name="X">6.000000</Real>
         <DataValues>
-          <Int Name="Count">2</Int>
+          <Int Name="Count">1</Int>
           <DataValue>
             <Real Name="Value">1.000000</Real>
-          </DataValue>
-          <DataValue>
-            <Real Name="Value">0.000000</Real>
+            <Real Name="Error">0.000000</Real>
           </DataValue>
         </DataValues>
       </DataFrame>
       <DataFrame Name="Frame6">
         <Real Name="X">7.000000</Real>
         <DataValues>
-          <Int Name="Count">2</Int>
+          <Int Name="Count">1</Int>
           <DataValue>
             <Real Name="Value">1.000000</Real>
-          </DataValue>
-          <DataValue>
-            <Real Name="Value">0.000000</Real>
+            <Real Name="Error">0.000000</Real>
           </DataValue>
         </DataValues>
       </DataFrame>
       <DataFrame Name="Frame7">
         <Real Name="X">8.000000</Real>
         <DataValues>
-          <Int Name="Count">2</Int>
+          <Int Name="Count">1</Int>
           <DataValue>
             <Real Name="Value">0.500000</Real>
-          </DataValue>
-          <DataValue>
-            <Real Name="Value">0.707107</Real>
+            <Real Name="Error">0.707107</Real>
           </DataValue>
         </DataValues>
       </DataFrame>
       <DataFrame Name="Frame8">
         <Real Name="X">9.000000</Real>
         <DataValues>
-          <Int Name="Count">2</Int>
-          <DataValue>
-            <Real Name="Value">0.000000</Real>
-          </DataValue>
+          <Int Name="Count">1</Int>
           <DataValue>
             <Real Name="Value">0.000000</Real>
+            <Real Name="Error">0.000000</Real>
           </DataValue>
         </DataValues>
       </DataFrame>
index 695c7276549d3025eff5d0b51b9ecb948c0e52d8..88a406a65f8402d7810c224a457d0cfa769619fc 100644 (file)
       <DataFrame Name="Frame0">
         <Real Name="X">1.000000</Real>
         <DataValues>
-          <Int Name="Count">2</Int>
+          <Int Name="Count">1</Int>
           <DataValue>
             <Real Name="Value">1.000000</Real>
-          </DataValue>
-          <DataValue>
-            <Real Name="Value">0.000000</Real>
+            <Real Name="Error">0.000000</Real>
           </DataValue>
         </DataValues>
       </DataFrame>
       <DataFrame Name="Frame1">
         <Real Name="X">2.000000</Real>
         <DataValues>
-          <Int Name="Count">2</Int>
+          <Int Name="Count">1</Int>
           <DataValue>
             <Real Name="Value">0.500000</Real>
-          </DataValue>
-          <DataValue>
-            <Real Name="Value">0.707107</Real>
+            <Real Name="Error">0.707107</Real>
           </DataValue>
         </DataValues>
       </DataFrame>
       <DataFrame Name="Frame2">
         <Real Name="X">3.000000</Real>
         <DataValues>
-          <Int Name="Count">2</Int>
+          <Int Name="Count">1</Int>
           <DataValue>
             <Real Name="Value">0.500000</Real>
-          </DataValue>
-          <DataValue>
-            <Real Name="Value">0.707107</Real>
+            <Real Name="Error">0.707107</Real>
           </DataValue>
         </DataValues>
       </DataFrame>
       <DataFrame Name="Frame3">
         <Real Name="X">4.000000</Real>
         <DataValues>
-          <Int Name="Count">2</Int>
+          <Int Name="Count">1</Int>
           <DataValue>
             <Real Name="Value">0.500000</Real>
-          </DataValue>
-          <DataValue>
-            <Real Name="Value">0.707107</Real>
+            <Real Name="Error">0.707107</Real>
           </DataValue>
         </DataValues>
       </DataFrame>
       <DataFrame Name="Frame4">
         <Real Name="X">5.000000</Real>
         <DataValues>
-          <Int Name="Count">2</Int>
+          <Int Name="Count">1</Int>
           <DataValue>
             <Real Name="Value">0.500000</Real>
-          </DataValue>
-          <DataValue>
-            <Real Name="Value">0.707107</Real>
+            <Real Name="Error">0.707107</Real>
           </DataValue>
         </DataValues>
       </DataFrame>
       <DataFrame Name="Frame5">
         <Real Name="X">6.000000</Real>
         <DataValues>
-          <Int Name="Count">2</Int>
+          <Int Name="Count">1</Int>
           <DataValue>
             <Real Name="Value">1.000000</Real>
-          </DataValue>
-          <DataValue>
-            <Real Name="Value">0.000000</Real>
+            <Real Name="Error">0.000000</Real>
           </DataValue>
         </DataValues>
       </DataFrame>
       <DataFrame Name="Frame6">
         <Real Name="X">7.000000</Real>
         <DataValues>
-          <Int Name="Count">2</Int>
+          <Int Name="Count">1</Int>
           <DataValue>
             <Real Name="Value">1.000000</Real>
-          </DataValue>
-          <DataValue>
-            <Real Name="Value">0.000000</Real>
+            <Real Name="Error">0.000000</Real>
           </DataValue>
         </DataValues>
       </DataFrame>
       <DataFrame Name="Frame7">
         <Real Name="X">8.000000</Real>
         <DataValues>
-          <Int Name="Count">2</Int>
+          <Int Name="Count">1</Int>
           <DataValue>
             <Real Name="Value">0.500000</Real>
-          </DataValue>
-          <DataValue>
-            <Real Name="Value">0.707107</Real>
+            <Real Name="Error">0.707107</Real>
           </DataValue>
         </DataValues>
       </DataFrame>
       <DataFrame Name="Frame8">
         <Real Name="X">9.000000</Real>
         <DataValues>
-          <Int Name="Count">2</Int>
-          <DataValue>
-            <Real Name="Value">0.000000</Real>
-          </DataValue>
+          <Int Name="Count">1</Int>
           <DataValue>
             <Real Name="Value">0.000000</Real>
+            <Real Name="Error">0.000000</Real>
           </DataValue>
         </DataValues>
       </DataFrame>
index af440d331b54f8548e6dd0625dbcda9d1de4a827..c14c5f2dd3c12ab60d41c520e45d3703c4519bdd 100644 (file)
@@ -1,7 +1,7 @@
 <?xml version="1.0"?>
 <?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
 <ReferenceData>
-  <String Name="CommandLine">select -select 'resname RA RD and y &lt; 2.5' -pdbatoms selected</String>
+  <String Name="CommandLine">select -select 'resname RA RD and y &lt; 2.5' 'resname RA RB' -pdbatoms selected</String>
   <OutputData Name="Data">
     <AnalysisData Name="occupancy">
       <DataFrame Name="Frame0">
           <Int Name="Count">2</Int>
           <DataValue>
             <Real Name="Value">1.000000</Real>
+            <Real Name="Error">0.000000</Real>
           </DataValue>
           <DataValue>
-            <Real Name="Value">0.000000</Real>
+            <Real Name="Value">1.000000</Real>
+            <Real Name="Error">0.000000</Real>
           </DataValue>
         </DataValues>
       </DataFrame>
           <Int Name="Count">2</Int>
           <DataValue>
             <Real Name="Value">0.500000</Real>
+            <Real Name="Error">0.707107</Real>
           </DataValue>
           <DataValue>
-            <Real Name="Value">0.707107</Real>
+            <Real Name="Value">1.000000</Real>
+            <Real Name="Error">0.000000</Real>
           </DataValue>
         </DataValues>
       </DataFrame>
           <Int Name="Count">2</Int>
           <DataValue>
             <Real Name="Value">0.500000</Real>
+            <Real Name="Error">0.707107</Real>
           </DataValue>
           <DataValue>
-            <Real Name="Value">0.707107</Real>
+            <Real Name="Value">1.000000</Real>
+            <Real Name="Error">0.000000</Real>
           </DataValue>
         </DataValues>
       </DataFrame>
           <Int Name="Count">2</Int>
           <DataValue>
             <Real Name="Value">0.500000</Real>
+            <Real Name="Error">0.707107</Real>
           </DataValue>
           <DataValue>
-            <Real Name="Value">0.707107</Real>
+            <Real Name="Value">1.000000</Real>
+            <Real Name="Error">0.000000</Real>
           </DataValue>
         </DataValues>
       </DataFrame>
           <Int Name="Count">2</Int>
           <DataValue>
             <Real Name="Value">0.500000</Real>
+            <Real Name="Error">0.707107</Real>
           </DataValue>
           <DataValue>
-            <Real Name="Value">0.707107</Real>
+            <Real Name="Value">1.000000</Real>
+            <Real Name="Error">0.000000</Real>
           </DataValue>
         </DataValues>
       </DataFrame>
           <Int Name="Count">2</Int>
           <DataValue>
             <Real Name="Value">1.000000</Real>
+            <Real Name="Error">0.000000</Real>
           </DataValue>
           <DataValue>
-            <Real Name="Value">0.000000</Real>
+            <Real Name="Value">1.000000</Real>
+            <Real Name="Error">0.000000</Real>
           </DataValue>
         </DataValues>
       </DataFrame>
           <Int Name="Count">2</Int>
           <DataValue>
             <Real Name="Value">1.000000</Real>
+            <Real Name="Error">0.000000</Real>
           </DataValue>
           <DataValue>
-            <Real Name="Value">0.000000</Real>
+            <Real Name="Value">1.000000</Real>
+            <Real Name="Error">0.000000</Real>
           </DataValue>
         </DataValues>
       </DataFrame>
           <Int Name="Count">2</Int>
           <DataValue>
             <Real Name="Value">0.500000</Real>
+            <Real Name="Error">0.707107</Real>
           </DataValue>
           <DataValue>
-            <Real Name="Value">0.707107</Real>
+            <Real Name="Value">1.000000</Real>
+            <Real Name="Error">0.000000</Real>
           </DataValue>
         </DataValues>
       </DataFrame>
           <Int Name="Count">2</Int>
           <DataValue>
             <Real Name="Value">0.000000</Real>
+            <Real Name="Error">0.000000</Real>
           </DataValue>
           <DataValue>
-            <Real Name="Value">0.000000</Real>
+            <Real Name="Value">1.000000</Real>
+            <Real Name="Error">0.000000</Real>
           </DataValue>
         </DataValues>
       </DataFrame>
@@ -120,12 +138,15 @@ TITLE     frame t= 0.000
 REMARK    THIS IS A SIMULATION BOX
 CRYST1  100.000  100.000  100.000  90.00  90.00  90.00 P 1           1
 MODEL        1
-ATOM      1  CB   RA A   1      10.000  10.000   0.000  1.00  0.00            
-ATOM      2  S1   RA A   1      10.000  20.000   0.000  0.50  0.00            
-ATOM      3  S2   RA A   1      10.000  30.000   0.000  0.50  0.00            
-ATOM      7  CB   RA B   1      20.000  30.000   0.000  0.50  0.00            
-ATOM      8  S1   RA B   1      20.000  40.000   0.000  0.50  0.30            
-ATOM      9  S2   RA B   1      30.000  10.000   0.000  1.00  0.30            
+ATOM      1  CB   RA A   1      10.000  10.000   0.000  2.00  0.00            
+ATOM      2  S1   RA A   1      10.000  20.000   0.000  1.50  0.00            
+ATOM      3  S2   RA A   1      10.000  30.000   0.000  1.50  0.00            
+ATOM      4  CB   RB A   2      10.000  40.000   0.000  1.00  0.50            
+ATOM      5  S1   RB A   2      20.000  10.000   0.000  1.00  0.50            
+ATOM      6  S2   RB A   2      20.000  20.000   0.000  1.00  0.50            
+ATOM      7  CB   RA B   1      20.000  30.000   0.000  1.50  0.00            
+ATOM      8  S1   RA B   1      20.000  40.000   0.000  1.50  0.30            
+ATOM      9  S2   RA B   1      30.000  10.000   0.000  2.00  0.30            
 ATOM     13  CB   RD B   2      40.000  10.000   0.000  1.00  0.00            
 ATOM     14  S1   RD B   2      40.000  20.000   0.000  0.50  0.00            
 TER
index abad36c26ad0cb0afb66fb9e89ea03b97c6a1cc7..9223385238c2e5c31edd3d1071226396511a3791 100644 (file)
@@ -13,12 +13,17 @@ and use the copy_xsl.sh script to copy it to relevant locations.
 <xsl:import href="common-referencedata.xsl"/>
 
 <xsl:template match="AnalysisData">
+    <xsl:variable name="has-datasetspec"
+                  select="DataFrame/DataValues/Int[@Name='DataSet']"/>
     <xsl:variable name="has-columnspec"
                   select="DataFrame/DataValues/Int[@Name='FirstColumn']"/>
     <table border="1">
         <tr>
             <th>Frame</th>
             <th>X</th>
+            <xsl:if test="$has-datasetspec">
+                <th>Set</th>
+            </xsl:if>
             <xsl:if test="$has-columnspec">
                 <th>Columns</th>
             </xsl:if>
@@ -28,6 +33,9 @@ and use the copy_xsl.sh script to copy it to relevant locations.
         <tr>
             <td><xsl:value-of select="../@Name"/></td>
             <td><xsl:value-of select="../Real[@Name='X']"/></td>
+            <xsl:if test="$has-datasetspec">
+                <td><xsl:value-of select="Int[@Name='DataSet']"/></td>
+            </xsl:if>
             <xsl:if test="$has-columnspec">
                 <td>
                     <xsl:choose>
@@ -46,8 +54,19 @@ and use the copy_xsl.sh script to copy it to relevant locations.
     </table>
 </xsl:template>
 
+<xsl:template match="DataValue[Bool[@Name='Present']='false']">
+    (
+    <xsl:value-of select="Real[@Name='Value']"/>
+    <xsl:if test="Real[@Name='Error']">
+        &#177; <xsl:value-of select="Real[@Name='Error']"/>
+    </xsl:if>
+    )
+</xsl:template>
 <xsl:template match="DataValue">
     <xsl:value-of select="Real[@Name='Value']"/>
+    <xsl:if test="Real[@Name='Error']">
+        &#177; <xsl:value-of select="Real[@Name='Error']"/>
+    </xsl:if>
 </xsl:template>
 
 </xsl:stylesheet>
index 9c3c3ae551285525b5ed570c6aa282dc2c600a22..8adc76abcedd2d4a7b122f35ddf968223f316275 100644 (file)
@@ -112,7 +112,7 @@ TEST_F(SelectModuleTest, HandlesMaxPDBOutput)
 {
     const char *const cmdline[] = {
         "select",
-        "-select", "resname RA RD and y < 2.5",
+        "-select", "resname RA RD and y < 2.5", "resname RA RB",
         "-pdbatoms", "maxsel"
     };
     setTopology("simple.pdb");
@@ -126,7 +126,7 @@ TEST_F(SelectModuleTest, HandlesSelectedPDBOutput)
 {
     const char *const cmdline[] = {
         "select",
-        "-select", "resname RA RD and y < 2.5",
+        "-select", "resname RA RD and y < 2.5", "resname RA RB",
         "-pdbatoms", "selected"
     };
     setTopology("simple.pdb");
@@ -136,19 +136,6 @@ TEST_F(SelectModuleTest, HandlesSelectedPDBOutput)
     runTest(CommandLine::create(cmdline));
 }
 
-TEST_F(SelectModuleTest, HandlesDumpOption)
-{
-    const char *const cmdline[] = {
-        "select",
-        "-select", "y < 2.5",
-        "-dump"
-    };
-    setTopology("simple.gro");
-    setOutputFile("-oi", "index.dat");
-    includeDataset("index");
-    runTest(CommandLine::create(cmdline));
-}
-
 TEST_F(SelectModuleTest, NormalizesSizes)
 {
     const char *const cmdline[] = {
index dc09af3c884a091e25fa4b959611fe3e7761174b..ae211ba7a7692a98036ef66bc903ae0b6f2c3057 100644 (file)
@@ -1,7 +1,7 @@
 #
 # This file is part of the GROMACS molecular simulation package.
 #
-# Copyright (c) 2010,2011,2012, by the GROMACS development team, led by
+# Copyright (c) 2010,2011,2012,2013, 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.
@@ -49,6 +49,7 @@ set(UTILITY_PUBLIC_HEADERS
     gmx_header_config.h
     gmxassert.h
     gmxmpi.h
+    init.h
     programinfo.h
     stringutil.h
     uniqueptr.h)
index fce3001ac7e6beb6e34231dc3d81f908bd0918b2..3f0d8868663e833df2f2bf12b3dd3c67523c2b3a 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2012, by the GROMACS development team, led by
+ * Copyright (c) 2012,2013, 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.
 
 #include <boost/scoped_ptr.hpp>
 
+namespace gmx
+{
+namespace internal
+{
+/*! \cond internal */
+/*! \internal \brief
+ * Helper for ignoring values in macros.
+ *
+ * \ingroup module_utility
+ */
+template <typename T>
+void inline ignoreValueHelper(const T &) {}
+//! \endcond
+} // namespace internal
+
 /*! \cond libapi */
 /*! \libinternal \brief
  * Macro to declare a class non-copyable and non-assignable.
 #define GMX_DISALLOW_ASSIGN(ClassName) \
     private: \
         ClassName &operator=(const ClassName &)
+/*! \libinternal \brief
+ * Macro to explicitly ignore a return value of a call.
+ *
+ * Mainly meant for ignoring values of functions declared with
+ * __attribute__((warn_unused_return)).  Makes it easy to find those places if
+ * they need to be fixed, and document the intent in cases where the return
+ * value really can be ignored.  It also makes it easy to adapt the approach so
+ * that they don't produce warnings.  A cast to void doesn't remove the warning
+ * in gcc, while adding a dummy variable can cause warnings about an unused
+ * variable.
+ *
+ * \inlibraryapi
+ */
+#define GMX_IGNORE_RETURN_VALUE(call) \
+    ::gmx::internal::ignoreValueHelper(call)
 //! \endcond
 
-namespace gmx
-{
-
 /*! \libinternal \brief
  * Helper class to manage a pointer to a private implementation class.
  *
index 1854b5e8203ac118c7032e400f6506fcf433be8c..a5b242721957c5a04b476807036bf11b36c7e8db 100644 (file)
  */
 #include "exceptions.h"
 
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
 #include <cstring>
 
 #include <new>
@@ -50,6 +54,7 @@
 #include <boost/exception/get_error_info.hpp>
 #include <boost/shared_ptr.hpp>
 
+#include "gromacs/legacyheaders/network.h"
 #include "gromacs/legacyheaders/thread_mpi/system_error.h"
 #include "gromacs/utility/errorcodes.h"
 #include "gromacs/utility/gmxassert.h"
@@ -222,54 +227,172 @@ int NotImplementedError::errorCode() const
 namespace
 {
 
+/*! \brief
+ * Abstracts actual output from the other logic in exception formatting.
+ *
+ * Object that implements this interface is passed to
+ * formatExceptionMessageInternal(), and is responsible for composing the
+ * output.  This allows using the same implementation of interpreting the
+ * exceptions while still supporting output to different formats (e.g., to a
+ * string or to stderr).
+ */
+class MessageWriterInterface
+{
+    public:
+        virtual ~MessageWriterInterface() {}
+
+        /*! \brief
+         * Writes a single line of text into the output.
+         *
+         * \param[in] text    Text to write on the line.
+         * \param[in] indent  Suggested number of spaces to indent the line.
+         */
+        virtual void writeLine(const char *text, int indent) = 0;
+        /*! \brief
+         * Writes information about a system error (errno-based).
+         *
+         * \param[in] errorNumber  errno value
+         * \param[in] funcName     Name of the system call (can be NULL).
+         * \param[in] indent       Suggested number of spaces to indent the output.
+         */
+        virtual void writeErrNoInfo(int errorNumber, const char *funcName,
+                                    int indent) = 0;
+};
+
+/*! \brief
+ * Exception information writer for cases where exceptions should be avoided.
+ *
+ * Formats the messages into the provided FILE handle without checking for
+ * errors in fprintf() calls.
+ */
+class MessageWriterFileNoThrow : public MessageWriterInterface
+{
+    public:
+        //! Initializes a writer that writes to the given file handle.
+        explicit MessageWriterFileNoThrow(FILE *fp) : fp_(fp) {}
+
+        virtual void writeLine(const char *text, int indent)
+        {
+            internal::printFatalErrorMessageLine(fp_, text, indent);
+        }
+        virtual void writeErrNoInfo(int errorNumber, const char *funcName,
+                                    int indent)
+        {
+            std::fprintf(fp_, "%*sReason: %s\n", indent, "",
+                         std::strerror(errorNumber));
+            if (funcName != NULL)
+            {
+                std::fprintf(fp_, "%*s(call to %s() returned error code %d)\n",
+                             indent, "", funcName, errorNumber);
+            }
+        }
+
+    private:
+        FILE                   *fp_;
+};
+
+/*! \brief
+ * Exception information writer to format into an std::string.
+ */
+class MessageWriterString : public MessageWriterInterface
+{
+    public:
+        //! Post-processes the output string to not end in a line feed.
+        void removeTerminatingLineFeed()
+        {
+            if (result_.size() > 0U)
+            {
+                result_.erase(result_.size() - 1);
+            }
+        }
+        //! Returns the constructed string.
+        const std::string &result() const { return result_; }
+
+        virtual void writeLine(const char *text, int indent)
+        {
+            result_.append(indent, ' ');
+            result_.append(text);
+            result_.append("\n");
+        }
+        virtual void writeErrNoInfo(int errorNumber, const char *funcName,
+                                    int indent)
+        {
+            writeLine(formatString("Reason: %s", std::strerror(errorNumber)).c_str(),
+                      indent);
+            if (funcName != NULL)
+            {
+                writeLine(formatString("(call to %s() returned error code %d)",
+                                       funcName, errorNumber).c_str(),
+                          indent);
+            }
+        }
+
+    private:
+        std::string             result_;
+};
+
 /*! \brief
  * Prints error information for an exception object.
  *
- * \param[in] fp      File to write the information out to (typically stderr).
+ * \param[in] writer  Writer to write out the information.
  * \param[in] ex      Exception object to print.
  * \param[in] indent  Indentation for the information.
  *
  * If the exception contains nested exceptions, information from them is
  * recursively printed.
+ *
+ * Does not throw unless the writer throws.
  */
-void printExceptionMessage(FILE *fp, const std::exception &ex, int indent)
+void formatExceptionMessageInternal(MessageWriterInterface *writer,
+                                    const std::exception &ex, int indent)
 {
     const boost::exception *boostEx = dynamic_cast<const boost::exception *>(&ex);
     if (boostEx != NULL)
     {
+        // TODO: Add an option to print this information for the tests
+        // const char *const *funcPtr =
+        //     boost::get_error_info<boost::throw_function>(*boostEx);
+        // const char *const *filePtr =
+        //     boost::get_error_info<boost::throw_file>(*boostEx);
+        // const int         *linePtr =
+        //     boost::get_error_info<boost::throw_line>(*boostEx);
+
+        // std::string        result;
+        // if (filePtr != NULL && linePtr != NULL)
+        // {
+        //     result = formatString("%s:%d: %s\n", *filePtr, *linePtr,
+        //                           funcPtr != NULL ? *funcPtr : "");
+        // }
+
         // TODO: Remove duplicate context if present in multiple nested exceptions.
         const ErrorMessage *msg = boost::get_error_info<errinfo_message>(*boostEx);
         if (msg != NULL)
         {
             while (msg != NULL && msg->isContext())
             {
-                internal::printFatalErrorMessageLine(fp, msg->text().c_str(), indent*2);
+                writer->writeLine(msg->text().c_str(), indent*2);
                 ++indent;
                 msg = &msg->child();
             }
             if (msg != NULL && !msg->text().empty())
             {
-                internal::printFatalErrorMessageLine(fp, msg->text().c_str(), indent*2);
+                writer->writeLine(msg->text().c_str(), indent*2);
             }
         }
         else
         {
-            internal::printFatalErrorMessageLine(fp, ex.what(), indent);
+            writer->writeLine(ex.what(), indent*2);
         }
 
         const int *errorNumber
             = boost::get_error_info<boost::errinfo_errno>(*boostEx);
         if (errorNumber != NULL)
         {
-            std::fprintf(fp, "%*sReason: %s\n", (indent+1)*2, "",
-                         std::strerror(*errorNumber));
             const char * const *funcName
                 = boost::get_error_info<boost::errinfo_api_function>(*boostEx);
-            if (funcName != NULL)
-            {
-                std::fprintf(fp, "%*s(call to %s() returned error code %d)\n",
-                             (indent+1)*2, "", *funcName, *errorNumber);
-            }
+            writer->writeErrNoInfo(*errorNumber,
+                                   funcName != NULL ? *funcName : NULL,
+                                   (indent+1)*2);
         }
 
         // TODO: Treat also boost::nested_exception (not currently used, though)
@@ -287,14 +410,14 @@ void printExceptionMessage(FILE *fp, const std::exception &ex, int indent)
                 }
                 catch (const std::exception &nestedEx)
                 {
-                    printExceptionMessage(fp, nestedEx, indent + 1);
+                    formatExceptionMessageInternal(writer, nestedEx, indent + 1);
                 }
             }
         }
     }
     else
     {
-        internal::printFatalErrorMessageLine(fp, ex.what(), indent);
+        writer->writeLine(ex.what(), indent*2);
     }
 }
 
@@ -353,100 +476,34 @@ void printFatalErrorMessage(FILE *fp, const std::exception &ex)
     {
         std::fprintf(fp, "(exception type: %s)\n", typeid(ex).name());
     }
-    printExceptionMessage(fp, ex, 0);
+    MessageWriterFileNoThrow writer(fp);
+    formatExceptionMessageInternal(&writer, ex, 0);
     internal::printFatalErrorFooter(fp);
 }
 
-std::string formatException(const std::exception &ex)
+std::string formatExceptionMessageToString(const std::exception &ex)
 {
-    // TODO: It would be nicer to not duplicate the logic from
-    // printExceptionMessage().
-    const boost::exception *boostEx = dynamic_cast<const boost::exception *>(&ex);
-    if (boostEx != NULL)
-    {
-        const char *const *funcPtr =
-            boost::get_error_info<boost::throw_function>(*boostEx);
-        const char *const *filePtr =
-            boost::get_error_info<boost::throw_file>(*boostEx);
-        const int         *linePtr =
-            boost::get_error_info<boost::throw_line>(*boostEx);
-
-        std::string        result;
-        if (filePtr != NULL && linePtr != NULL)
-        {
-            result = formatString("%s:%d: %s\n", *filePtr, *linePtr,
-                                  funcPtr != NULL ? *funcPtr : "");
-        }
-
-        // TODO: Remove duplicate context if present in multiple nested exceptions.
-        const ErrorMessage *msg =
-            boost::get_error_info<errinfo_message>(*boostEx);
-        if (msg != NULL)
-        {
-            while (msg != NULL && msg->isContext())
-            {
-                result.append(msg->text());
-                result.append("\n");
-                msg = &msg->child();
-            }
-            if (msg != NULL && !msg->text().empty())
-            {
-                result.append(msg->text());
-                result.append("\n");
-            }
-        }
-        else
-        {
-            result.append(ex.what());
-            result.append("\n");
-        }
-
-        const int *errorNumber
-            = boost::get_error_info<boost::errinfo_errno>(*boostEx);
-        if (errorNumber != NULL)
-        {
-            result.append(formatString("Reason: %s\n",
-                                       std::strerror(*errorNumber)));
-            const char * const *funcName
-                = boost::get_error_info<boost::errinfo_api_function>(*boostEx);
-            if (funcName != NULL)
-            {
-                result.append(formatString("(call to %s() returned error code %d)\n",
-                                           *funcName, *errorNumber));
-            }
-        }
+    MessageWriterString writer;
+    formatExceptionMessageInternal(&writer, ex, 0);
+    writer.removeTerminatingLineFeed();
+    return writer.result();
+}
 
-        // TODO: Treat also boost::nested_exception (not currently used, though)
+void formatExceptionMessageToFile(FILE *fp, const std::exception &ex)
+{
+    MessageWriterFileNoThrow writer(fp);
+    formatExceptionMessageInternal(&writer, ex, 0);
+}
 
-        const internal::NestedExceptionList *nested
-            = boost::get_error_info<errinfo_nested_exceptions>(*boostEx);
-        if (nested != NULL)
-        {
-            internal::NestedExceptionList::const_iterator ni;
-            for (ni = nested->begin(); ni != nested->end(); ++ni)
-            {
-                try
-                {
-                    rethrow_exception(*ni);
-                }
-                catch (const std::exception &nestedEx)
-                {
-                    result.append(formatException(nestedEx));
-                    result.append("\n");
-                }
-            }
-        }
-        // Remove terminating line feed.
-        if (result.size() > 0U)
-        {
-            result.erase(result.size() - 1);
-        }
-        return result;
-    }
-    else
-    {
-        return ex.what();
-    }
+int processExceptionAtExit(const std::exception &/*ex*/)
+{
+    int returnCode = 1;
+#ifdef GMX_LIB_MPI
+    // TODO: Consider moving the output done in gmx_abort() into the message
+    // printing routine above, so that this could become a simple MPI_Abort().
+    gmx_abort(gmx_node_rank(), gmx_node_num(), returnCode);
+#endif
+    return returnCode;
 }
 
 } // namespace gmx
index d6826e0c749a12ab7ddb1bf6a88cffadd2d59ea2..722ccda059382e3f1d8ea9182acac26aad2dd787 100644 (file)
@@ -84,7 +84,8 @@ typedef std::vector<boost::exception_ptr> NestedExceptionList;
  * \todo
  * With the exception of the reason string, information added with this class
  * is not currently accessible through any public API, except for calling
- * printFatalErrorMessage().  This is not implemented as there is no current
+ * printFatalErrorMessage(), formatExceptionMessageToString() or
+ * formatExceptionMessageToFile().  This is not implemented as there is not yet
  * need for it, and it is not clear what would be the best alternative for the
  * access.  It should be possible to refactor the internal implementation to
  * suit the needs of such external access without requiring changes in code
@@ -185,7 +186,8 @@ class GromacsException : public std::exception, public boost::exception
          * \todo
          * The added information is currently not accessible through what(),
          * nor through any other means except for calling
-         * printFatalErrorMessage(). See ExceptionInitializer for more
+         * printFatalErrorMessage(), formatExceptionMessageToString() or
+         * formatExceptionMessageToFile(). See ExceptionInitializer for more
          * discussion.
          */
         void prependContext(const std::string &context);
@@ -396,7 +398,7 @@ class NotImplementedError : public APIError
  * \code
    int main(int argc, char *argv[])
    {
-       gmx::ProgramInfo::init(argc, argv);
+       gmx::init(&argc, &argv);
        try
        {
            // The actual code for the program
@@ -405,7 +407,7 @@ class NotImplementedError : public APIError
        catch (const std::exception &ex)
        {
            gmx::printFatalErrorMessage(stderr, ex);
-           return 1;
+           return gmx::processExceptionAtExit(ex);
        }
    }
  * \endcode
@@ -417,12 +419,32 @@ void printFatalErrorMessage(FILE *fp, const std::exception &ex);
  * \param[in] ex  Exception to format.
  * \returns   Formatted string containing details of \p ex.
  * \throws    std::bad_alloc if out of memory.
+ */
+std::string formatExceptionMessageToString(const std::exception &ex);
+/*! \brief
+ * Formats an error message for reporting an exception.
+ *
+ * \param     fp  File to write the message to.
+ * \param[in] ex  Exception to format.
+ * \throws    std::bad_alloc if out of memory.
+ */
+void formatExceptionMessageToFile(FILE *fp, const std::exception &ex);
+/*! \brief
+ * Handles an exception that is causing the program to terminate.
+ *
+ * \param[in] ex  Exception that is the cause for terminating the program.
+ * \returns   Return code to return from main().
+ *
+ * This method should be called as the last thing before terminating the
+ * program because of an exception.  It exists to terminate the program as
+ * gracefully as possible in the case of MPI processing (but the current
+ * implementation always calls MPI_Abort()).
+ *
+ * See printFatalErrorMessage() for example usage.
  *
- * Currently, the output format is useful mainly for tests and debugging
- * purposes; additional flags for controlling the format can be added if other
- * uses for the function arise.
+ * Does not throw.
  */
-std::string formatException(const std::exception &ex);
+int processExceptionAtExit(const std::exception &ex);
 
 /*! \brief
  * Converts an exception into a return code.
@@ -459,7 +481,7 @@ int translateException(const std::exception &ex);
 #define GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR \
     catch (const std::exception &ex) { \
         ::gmx::printFatalErrorMessage(stderr, ex); \
-        std::exit(1); \
+        ::std::exit(::gmx::processExceptionAtExit(ex)); \
     }
 //! \endcond
 
index 48a142d7022a0682dce08a07461c2c1f9612e266..9e36299cd2dd5e0903aa14040efda28492ace513 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2011,2012, by the GROMACS development team, led by
+ * Copyright (c) 2011,2012,2013, 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.
@@ -50,7 +50,8 @@
  * \{
  */
 
-/*! \brief
+/*! \def GMX_RELEASE_ASSERT
+ * \brief
  * Macro for asserts that should also be present in the release version.
  *
  * Regardless of NDEBUG, this macro checks \p condition, and if it is not true,
  * should only be used in a context where it is safe to throw an exception to
  * keep the option open.
  */
+#ifdef GMX_DISABLE_ASSERTS
+#define GMX_RELEASE_ASSERT(condition, msg)
+#else
 #define GMX_RELEASE_ASSERT(condition, msg) \
     ((void) ((condition) ? (void)0 : \
              ::gmx::internal::assertHandler(#condition, msg, \
                                             BOOST_CURRENT_FUNCTION, __FILE__, __LINE__)))
+#endif
 /*! \def GMX_ASSERT
  * \brief
  * Macro for debug asserts.
diff --git a/src/gromacs/utility/init.cpp b/src/gromacs/utility/init.cpp
new file mode 100644 (file)
index 0000000..2c34d94
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2013, 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.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, 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 http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+/*! \internal \file
+ * \brief
+ * Implements functions from init.h.
+ *
+ * \author Teemu Murtola <teemu.murtola@gmail.com>
+ * \ingroup module_utility
+ */
+#include "gromacs/utility/init.h"
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <cstring>
+
+#ifdef GMX_LIB_MPI
+#include "gromacs/utility/gmxmpi.h"
+#endif
+
+#include "gromacs/legacyheaders/network.h"
+#include "gromacs/legacyheaders/smalloc.h"
+#include "gromacs/legacyheaders/types/commrec.h"
+
+#include "gromacs/utility/programinfo.h"
+
+namespace gmx
+{
+
+#ifdef GMX_LIB_MPI
+namespace
+{
+
+void broadcastArguments(const t_commrec *cr, int *argc, char ***argv)
+{
+    gmx_bcast(sizeof(*argc), argc, cr);
+
+    if (!MASTER(cr))
+    {
+        snew(*argv, *argc+1);
+    }
+    for (int i = 0; i < *argc; i++)
+    {
+        int len;
+        if (MASTER(cr))
+        {
+            len = std::strlen((*argv)[i])+1;
+        }
+        gmx_bcast(sizeof(len), &len, cr);
+        if (!MASTER(cr))
+        {
+            snew((*argv)[i], len);
+        }
+        gmx_bcast(len, (*argv)[i], cr);
+    }
+}
+
+} // namespace
+#endif
+
+ProgramInfo &init(const char *realBinaryName, int *argc, char ***argv)
+{
+#ifdef GMX_LIB_MPI
+    // TODO: Rewrite this to not use t_commrec once there is clarity on
+    // the approach for MPI in C++ code.
+    // TODO: Consider whether the argument broadcast would better be done
+    // in CommandLineModuleManager.
+    t_commrec cr;
+    std::memset(&cr, 0, sizeof(cr));
+    cr.nodeid = gmx_setup(argc, argv, &cr.nnodes);
+    cr.mpi_comm_mygroup = MPI_COMM_WORLD;
+    if (PAR(&cr))
+    {
+        broadcastArguments(&cr, argc, argv);
+    }
+#endif
+    return ProgramInfo::init(realBinaryName, *argc, *argv);
+}
+
+ProgramInfo &init(int *argc, char ***argv)
+{
+    return init(NULL, argc, argv);
+}
+
+void finalize()
+{
+    gmx_finalize_par();
+}
+
+} // namespace gmx
diff --git a/src/gromacs/utility/init.h b/src/gromacs/utility/init.h
new file mode 100644 (file)
index 0000000..90d6de8
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2013, 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.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, 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 http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+/*! \file
+ * \brief
+ * Declares functions for initializing the GROMACS library.
+ *
+ * \author Teemu Murtola <teemu.murtola@gmail.com>
+ * \inpublicapi
+ * \ingroup module_utility
+ */
+#ifndef GMX_UTILITY_INIT_H
+#define GMX_UTILITY_INIT_H
+
+// Forward declaration is not sufficient for MSVC if the return value is
+// ignored...
+#include "programinfo.h"
+
+namespace gmx
+{
+
+class ProgramInfo;
+
+/*! \brief
+ * Initializes the Gromacs library with explicit binary name.
+ *
+ * \param[in] realBinaryName  Name of the binary
+ *     (without Gromacs binary suffix or .exe on Windows).
+ * \param[in] argc  argc value passed to main().
+ * \param[in] argv  argv array passed to main().
+ * \returns   Reference to initialized program information object.
+ *
+ * This overload is provided for cases where the program may be invoked
+ * through a symlink, and it is necessary to know the real name of the
+ * binary.
+ * See init(int *, char ***) for more information on the general behavior.
+ *
+ * Does not throw. Terminates the program on out-of-memory error.
+ */
+ProgramInfo &init(const char *realBinaryName, int *argc, char ***argv);
+/*! \brief
+ * Initializes the Gromacs library.
+ *
+ * \param[in] argc  argc value passed to main().
+ * \param[in] argv  argv array passed to main().
+ * \returns   Reference to initialized program information object.
+ *
+ * Currently, this is tailored for use in command-line/standalone applications.
+ * Some additional thought may be required to make it generally usable.
+ * Always calls MPI_Init() if Gromacs is compiled with MPI support.
+ *
+ * The command line arguments are communicated so that they can be
+ * parsed on each processor.
+ * Arguments are the number of command line arguments, and a pointer to the
+ * array of argument strings. Both are allowed to be NULL.
+ *
+ * Does not throw. Terminates the program on out-of-memory error.
+ */
+ProgramInfo &init(int *argc, char ***argv);
+/*! \brief
+ * Deinitializes the Gromacs library.
+ *
+ * Currently always calls MPI_Finalize() if Gromacs is compiled with MPI
+ * support, unless MPI has already been finalized.
+ * Thus, it is not possible to reinitialize Gromacs after calling this
+ * function.
+ */
+void finalize();
+
+} // namespace gmx
+
+#endif
index 927ce87a3e293bb3b5bdec4e012fae83b3ab20c9..499abba514f71029e182d0501d73671491a9f16c 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2012, by the GROMACS development team, led by
+ * Copyright (c) 2012,2013, 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.
@@ -186,7 +186,7 @@ ProgramInfo &ProgramInfo::init(const char *realBinaryName,
     catch (const std::exception &ex)
     {
         printFatalErrorMessage(stderr, ex);
-        std::exit(1);
+        std::exit(processExceptionAtExit(ex));
     }
 }
 
index c7bba8ac1c0ba7691ffa0bff5359ed4207d2a4dc..f18036f3a5a8e68818154f267e43760f7b9b8af2 100644 (file)
@@ -41,7 +41,6 @@
 #include <string.h>
 #include "macros.h"
 #include "Xstuff.h"
-#include "copyrite.h"
 #include "xutil.h"
 #include "futil.h"
 #include "x11.h"
@@ -50,7 +49,7 @@
 #include "rama.bm"
 #include "nrama.h"
 
-#include "gromacs/utility/programinfo.h"
+#include "gromacs/commandline/cmdlinemodulemanager.h"
 
 #define MAXDEG 360
 
@@ -341,7 +340,7 @@ static void mk_gly(t_app *app)
     }
 }
 
-int main(int argc, char *argv[])
+int gmx_xrama(int argc, char *argv[])
 {
     const char  *desc[] = {
         "[TT]g_xrama[tt] shows a Ramachandran movie, that is, it shows",
@@ -360,8 +359,7 @@ int main(int argc, char *argv[])
     };
 #define NFILE asize(fnm)
 
-    gmx::ProgramInfo::init(argc, argv);
-    parse_common_args(&argc, argv, PCA_CAN_TIME | PCA_STANDALONE, NFILE, fnm,
+    parse_common_args(&argc, argv, PCA_CAN_TIME, NFILE, fnm,
                       0, NULL, asize(desc), desc, 0, NULL, &oenv);
 
 
@@ -382,7 +380,10 @@ int main(int argc, char *argv[])
     x11->MainLoop(x11);
     x11->CleanUp(x11);
 
-    gmx_thanx(stderr);
-
     return 0;
 }
+
+int main(int argc, char *argv[])
+{
+    return gmx::CommandLineModuleManager::runAsMainCMain(argc, argv, &gmx_xrama);
+}
index 112f19d230a464a07be361ed816fe715ad0500a3..c65f34bd864a43cbd3417b05ea0571869ec51088 100644 (file)
 #include "nmol.h"
 #include "tpxio.h"
 
+#include "gromacs/commandline/cmdlinemodulemanager.h"
+
 /* Forward declarations: I Don't want all that init shit here */
 void init_gmx(t_x11 *x11, char *program, int nfile, t_filenm fnm[],
               const output_env_t oenv);
 
-static void dump_xw(char *dispname, Window w, char *fn)
-{
-    char comm[256];
-
-    sprintf(comm, "xwd -id %d -display %s > %s", (int)w, dispname, fn);
-
-#ifdef GMX_NO_SYSTEM
-    printf("Warning-- No calls to system(3) supported on this platform.");
-    printf("Warning-- Skipping execution of 'system(\"%s\")'.", buf);
-#else
-    (void)system(comm);
-#endif
-}
-
 static void dump_it(t_manager *man)
 {
     t_psdata ps;
@@ -273,7 +261,7 @@ static gmx_bool MainCallBack(t_x11 *x11, XEvent *event, Window w, void *data)
     return result;
 }
 
-int main(int argc, char *argv[])
+int gmx_ngmx(int argc, char *argv[])
 {
     const char  *desc[] = {
         "[TT]ngmx[tt] is the GROMACS trajectory viewer. This program reads a",
@@ -305,8 +293,7 @@ int main(int argc, char *argv[])
     };
 #define NFILE asize(fnm)
 
-    gmx::ProgramInfo::init(argc, argv);
-    parse_common_args(&argc, argv, PCA_CAN_TIME | PCA_STANDALONE, NFILE, fnm,
+    parse_common_args(&argc, argv, PCA_CAN_TIME, NFILE, fnm,
                       0, NULL, asize(desc), desc, asize(bugs), bugs, &oenv);
 
     if ((x11 = GetX11(&argc, argv)) == NULL)
@@ -320,11 +307,14 @@ int main(int argc, char *argv[])
     x11->MainLoop(x11);
     x11->CleanUp(x11);
 
-    gmx_thanx(stderr);
-
     return 0;
 }
 
+int main(int argc, char *argv[])
+{
+    return gmx::CommandLineModuleManager::runAsMainCMain(argc, argv, &gmx_ngmx);
+}
+
 static t_mentry  FileMenu[] = {
     { 0,  IDEXPORT,   FALSE,  "Export..." },
     { 0,  IDDUMPWIN,  FALSE,  "Print"     },
index 6023d9c95138253bbab9da2b08a23eee72a19519..67324d97f396e2e97007f71b748b9225e97e71ca 100644 (file)
@@ -1,7 +1,7 @@
 #
 # This file is part of the GROMACS molecular simulation package.
 #
-# Copyright (c) 2012, by the GROMACS development team, led by
+# Copyright (c) 2012,2013, 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.
@@ -100,6 +100,7 @@ set(SYMLINK_NAMES
     g_nmtraj
     g_options
     g_order
+    g_pme_error
     g_polystat
     g_potential
     g_principal
index 2661139986a7a347eef87ed3850ad2722807209e..d4fec6c3a32902e06ea3a1ab05ebddf5a8484561 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2010,2011,2012, by the GROMACS development team, led by
+ * Copyright (c) 2010,2011,2012,2013, 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.
 #include "gromacs/selection/selectioncollection.h"
 #include "gromacs/trajectoryanalysis/modules.h"
 #include "gromacs/utility/exceptions.h"
-#include "gromacs/utility/programinfo.h"
+#include "gromacs/utility/init.h"
 
 #include "legacymodules.h"
 
 int
 main(int argc, char *argv[])
 {
-    gmx::ProgramInfo &info = gmx::ProgramInfo::init("gmx", argc, argv);
+    gmx::ProgramInfo &info = gmx::init("gmx", &argc, &argv);
     try
     {
         gmx::CommandLineModuleManager manager(&info);
         registerTrajectoryAnalysisModules(&manager);
         registerLegacyModules(&manager);
         manager.addHelpTopic(gmx::SelectionCollection::createDefaultHelpTopic());
-        return manager.run(argc, argv);
+        int rc = manager.run(argc, argv);
+        gmx::finalize();
+        return rc;
     }
     catch (const std::exception &ex)
     {
         gmx::printFatalErrorMessage(stderr, ex);
-        return 1;
+        return gmx::processExceptionAtExit(ex);
     }
 }
index 273fb12c29b0e41b2b6e9f67d1fc31d07e816d30..0b85c26e0700b2d4fc3c1984cdc6743e1df9a3cc 100644 (file)
@@ -33,7 +33,7 @@
  * the research papers on the package. Check out http://www.gromacs.org.
  */
 /*! \internal \brief
- * Implements command-line modules for pre-5.0 binaries.
+ * Registers command-line modules for pre-5.0 binaries.
  *
  * \author Teemu Murtola <teemu.murtola@gmail.com>
  */
@@ -62,82 +62,19 @@ int gmx_x2top(int argc, char *argv[]);
 namespace
 {
 
-/*! \internal \brief
- * Command-line module for wrapping pre-5.0 binaries.
+/*! \brief
+ * Convenience function for creating and registering a module.
  *
- * Implements a gmx::CommandLineModuleInterface, given a function with
- * C/C++ main signature.
+ * \param[in] manager          Module manager to which to register the module.
+ * \param[in] mainFunction     Main function to wrap.
+ * \param[in] name             Name for the new module.
+ * \param[in] shortDescription One-line description for the new module.
  */
-class LegacyCmdLineWrapper : public gmx::CommandLineModuleInterface
-{
-    public:
-        //! Function pointer type for the main function of the module.
-        typedef int (*MainFunction)(int argc, char *argv[]);
-
-        /*! \brief
-         * Convenience function for creating and registering a module.
-         *
-         * \param[in] manager  Module manager to which to register the module.
-         * \param[in] main     Main function to wrap.
-         * \param[in] name     Name for the new module.
-         * \param[in] shortDescription One-line description for the new module.
-         */
-        static void registerModule(gmx::CommandLineModuleManager *manager,
-                                   MainFunction main, const char *name,
-                                   const char *shortDescription)
-        {
-            gmx::CommandLineModulePointer module(
-                    new LegacyCmdLineWrapper(main, name, shortDescription));
-            manager->addModule(gmx::move(module));
-        }
-
-        /*! \brief
-         * Creates a wrapper module for the given main function.
-         *
-         * \see registerModule()
-         */
-        LegacyCmdLineWrapper(MainFunction main, const char *name,
-                             const char *shortDescription)
-            : main_(main), name_(name), shortDescription_(shortDescription)
-        {
-        }
-
-        virtual const char *name() const
-        {
-            return name_;
-        }
-        virtual const char *shortDescription() const
-        {
-            return shortDescription_;
-        }
-
-        virtual int run(int argc, char *argv[]);
-        virtual void writeHelp(const gmx::HelpWriterContext &context) const;
-
-    private:
-        MainFunction            main_;
-        const char             *name_;
-        const char             *shortDescription_;
-
-};
-
-int LegacyCmdLineWrapper::run(int argc, char *argv[])
-{
-    return main_(argc, argv);
-}
-
-void LegacyCmdLineWrapper::writeHelp(const gmx::HelpWriterContext &context) const
+void registerModule(gmx::CommandLineModuleManager                *manager,
+                    gmx::CommandLineModuleManager::CMainFunction  mainFunction,
+                    const char *name, const char *shortDescription)
 {
-    if (context.outputFormat() != gmx::eHelpOutputFormat_Console)
-    {
-        GMX_THROW(gmx::NotImplementedError(
-                          "Command-line help is not implemented for this output format"));
-    }
-    char *argv[2];
-    // TODO: The constness should not be cast away.
-    argv[0] = const_cast<char *>(name_);
-    argv[1] = const_cast<char *>("-h");
-    main_(2, argv);
+    manager->addModuleCMain(name, shortDescription, mainFunction);
 }
 
 } // namespace
@@ -145,197 +82,193 @@ void LegacyCmdLineWrapper::writeHelp(const gmx::HelpWriterContext &context) cons
 void registerLegacyModules(gmx::CommandLineModuleManager *manager)
 {
     // Modules from this directory (were in src/kernel/).
-    LegacyCmdLineWrapper::registerModule(manager, &gmx_gmxcheck, "gmxcheck",
-                                         "Check and compare files");
-    LegacyCmdLineWrapper::registerModule(manager, &gmx_gmxdump, "gmxdump",
-                                         "Make binary files human readable");
-    LegacyCmdLineWrapper::registerModule(manager, &gmx_grompp, "grompp",
-                                         "Make a run input file");
-    LegacyCmdLineWrapper::registerModule(manager, &gmx_pdb2gmx, "pdb2gmx",
-                                         "Convert coordinate files to topology and FF-compliant coordinate files");
-    LegacyCmdLineWrapper::registerModule(manager, &gmx_tpbconv, "tpbconv",
-                                         "Make a run input file for restarting a crashed run");
+    registerModule(manager, &gmx_gmxcheck, "gmxcheck",
+                   "Check and compare files");
+    registerModule(manager, &gmx_gmxdump, "gmxdump",
+                   "Make binary files human readable");
+    registerModule(manager, &gmx_grompp, "grompp",
+                   "Make a run input file");
+    registerModule(manager, &gmx_pdb2gmx, "pdb2gmx",
+                   "Convert coordinate files to topology and FF-compliant coordinate files");
+    registerModule(manager, &gmx_tpbconv, "tpbconv",
+                   "Make a run input file for restarting a crashed run");
 
-    LegacyCmdLineWrapper::registerModule(manager, &gmx_protonate, "protonate",
-                                         "Protonate structures");
-    LegacyCmdLineWrapper::registerModule(manager, &gmx_x2top, "x2top",
-                                         "Generate a primitive topology from coordinates");
+    registerModule(manager, &gmx_protonate, "protonate",
+                   "Protonate structures");
+    registerModule(manager, &gmx_x2top, "x2top",
+                   "Generate a primitive topology from coordinates");
 
     // Modules from gmx_ana.h.
-    LegacyCmdLineWrapper::registerModule(manager, &gmx_do_dssp, "do_dssp",
-                                         "Assign secondary structure and calculate solvent accessible surface area");
-    LegacyCmdLineWrapper::registerModule(manager, &gmx_editconf, "editconf",
-                                         "Convert and manipulates structure files");
-    LegacyCmdLineWrapper::registerModule(manager, &gmx_eneconv, "eneconv",
-                                         "Convert energy files");
-    LegacyCmdLineWrapper::registerModule(manager, &gmx_genbox, "genbox",
-                                         "Solvate a system");
-    LegacyCmdLineWrapper::registerModule(manager, &gmx_genconf, "genconf",
-                                         "Multiply a conformation in 'random' orientations");
-    LegacyCmdLineWrapper::registerModule(manager, &gmx_genion, "genion",
-                                         "Generate monoatomic ions on energetically favorable positions");
-    LegacyCmdLineWrapper::registerModule(manager, &gmx_genpr, "genrestr",
-                                         "Generate position restraints or distance restraints for index groups");
-    LegacyCmdLineWrapper::registerModule(manager, &gmx_make_edi, "make_edi",
-                                         "Generate input files for essential dynamics sampling");
-    LegacyCmdLineWrapper::registerModule(manager, &gmx_make_ndx, "make_ndx",
-                                         "Make index files");
-    LegacyCmdLineWrapper::registerModule(manager, &gmx_mk_angndx, "mk_angndx",
-                                         "Generate index files for 'gmx angle'");
-    LegacyCmdLineWrapper::registerModule(manager, &gmx_trjcat, "trjcat",
-                                         "Concatenate trajectory files");
-    LegacyCmdLineWrapper::registerModule(manager, &gmx_trjconv, "trjconv",
-                                         "Convert and manipulates trajectory files");
-    LegacyCmdLineWrapper::registerModule(manager, &gmx_trjorder, "trjorder",
-                                         "Order molecules according to their distance to a group");
-    LegacyCmdLineWrapper::registerModule(manager, &gmx_xpm2ps, "xpm2ps",
-                                         "Convert XPM (XPixelMap) matrices to postscript or XPM");
+    registerModule(manager, &gmx_do_dssp, "do_dssp",
+                   "Assign secondary structure and calculate solvent accessible surface area");
+    registerModule(manager, &gmx_editconf, "editconf",
+                   "Convert and manipulates structure files");
+    registerModule(manager, &gmx_eneconv, "eneconv",
+                   "Convert energy files");
+    registerModule(manager, &gmx_genbox, "genbox",
+                   "Solvate a system");
+    registerModule(manager, &gmx_genconf, "genconf",
+                   "Multiply a conformation in 'random' orientations");
+    registerModule(manager, &gmx_genion, "genion",
+                   "Generate monoatomic ions on energetically favorable positions");
+    registerModule(manager, &gmx_genpr, "genrestr",
+                   "Generate position restraints or distance restraints for index groups");
+    registerModule(manager, &gmx_make_edi, "make_edi",
+                   "Generate input files for essential dynamics sampling");
+    registerModule(manager, &gmx_make_ndx, "make_ndx",
+                   "Make index files");
+    registerModule(manager, &gmx_mk_angndx, "mk_angndx",
+                   "Generate index files for 'gmx angle'");
+    registerModule(manager, &gmx_trjcat, "trjcat",
+                   "Concatenate trajectory files");
+    registerModule(manager, &gmx_trjconv, "trjconv",
+                   "Convert and manipulates trajectory files");
+    registerModule(manager, &gmx_trjorder, "trjorder",
+                   "Order molecules according to their distance to a group");
+    registerModule(manager, &gmx_xpm2ps, "xpm2ps",
+                   "Convert XPM (XPixelMap) matrices to postscript or XPM");
 
-    // TODO: Include remaining binaries from src/tools/.
-    // These are commented out below, and have some issues to consider how to
-    // best handle them.
-    LegacyCmdLineWrapper::registerModule(manager, &gmx_anadock, "anadock",
-                                         "Cluster structures from Autodock runs");
-    LegacyCmdLineWrapper::registerModule(manager, &gmx_anaeig, "anaeig",
-                                         "Analyze eigenvectors/normal modes");
-    LegacyCmdLineWrapper::registerModule(manager, &gmx_analyze, "analyze",
-                                         "Analyze data sets");
-    LegacyCmdLineWrapper::registerModule(manager, &gmx_g_angle, "angle",
-                                         "Calculate distributions and correlations for angles and dihedrals");
-    LegacyCmdLineWrapper::registerModule(manager, &gmx_bar, "bar",
-                                         "Calculate free energy difference estimates through Bennett's acceptance ratio");
-    LegacyCmdLineWrapper::registerModule(manager, &gmx_bond, "bond",
-                                         "Calculate distances between atoms and bond length distributions");
-    LegacyCmdLineWrapper::registerModule(manager, &gmx_bundle, "bundle",
-                                         "Analyze bundles of axes, e.g., helices");
-    LegacyCmdLineWrapper::registerModule(manager, &gmx_chi, "chi",
-                                         "Calculate everything you want to know about chi and other dihedrals");
-    LegacyCmdLineWrapper::registerModule(manager, &gmx_cluster, "cluster",
-                                         "Cluster structures");
-    LegacyCmdLineWrapper::registerModule(manager, &gmx_clustsize, "clustsize",
-                                         "Calculate size distributions of atomic clusters");
-    LegacyCmdLineWrapper::registerModule(manager, &gmx_confrms, "confrms",
-                                         "Fit two structures and calculates the RMSD");
-    LegacyCmdLineWrapper::registerModule(manager, &gmx_covar, "covar",
-                                         "Calculate and diagonalize the covariance matrix");
-    LegacyCmdLineWrapper::registerModule(manager, &gmx_current, "current",
-                                         "Calculate dielectric constants and charge autocorrelation function");
-    LegacyCmdLineWrapper::registerModule(manager, &gmx_density, "density",
-                                         "Calculate the density of the system");
-    LegacyCmdLineWrapper::registerModule(manager, &gmx_densmap, "densmap",
-                                         "Calculate 2D planar or axial-radial density maps");
-    LegacyCmdLineWrapper::registerModule(manager, &gmx_densorder, "densorder",
-                                         "Calculate surface fluctuations");
-    LegacyCmdLineWrapper::registerModule(manager, &gmx_dielectric, "dielectric",
-                                         "Calculate frequency dependent dielectric constants");
-    LegacyCmdLineWrapper::registerModule(manager, &gmx_dipoles, "dipoles",
-                                         "Compute the total dipole plus fluctuations");
-    LegacyCmdLineWrapper::registerModule(manager, &gmx_disre, "disre",
-                                         "Analyze distance restraints");
-    LegacyCmdLineWrapper::registerModule(manager, &gmx_dist, "dist",
-                                         "Calculate distances between centers of mass of two groups");
-    LegacyCmdLineWrapper::registerModule(manager, &gmx_dos, "dos",
-                                         "Analyze density of states and properties based on that");
-    LegacyCmdLineWrapper::registerModule(manager, &gmx_dyecoupl, "dyecoupl",
-                                         "Extract dye dynamics from trajectories");
-    LegacyCmdLineWrapper::registerModule(manager, &gmx_dyndom, "dyndom",
-                                         "Interpolate and extrapolate structure rotations");
-    LegacyCmdLineWrapper::registerModule(manager, &gmx_enemat, "enemat",
-                                         "Extract an energy matrix from an energy file");
-    LegacyCmdLineWrapper::registerModule(manager, &gmx_energy, "energy",
-                                         "Writes energies to xvg files and display averages");
-    LegacyCmdLineWrapper::registerModule(manager, &gmx_filter, "filter",
-                                         "Frequency filter trajectories, useful for making smooth movies");
-    LegacyCmdLineWrapper::registerModule(manager, &gmx_gyrate, "gyrate",
-                                         "Calculate the radius of gyration");
-    LegacyCmdLineWrapper::registerModule(manager, &gmx_h2order, "h2order",
-                                         "Compute the orientation of water molecules");
-    LegacyCmdLineWrapper::registerModule(manager, &gmx_hbond, "hbond",
-                                         "Compute and analyze hydrogen bonds");
-    LegacyCmdLineWrapper::registerModule(manager, &gmx_helix, "helix",
-                                         "Calculate basic properties of alpha helices");
-    LegacyCmdLineWrapper::registerModule(manager, &gmx_helixorient, "helixorient",
-                                         "Calculate local pitch/bending/rotation/orientation inside helices");
-    LegacyCmdLineWrapper::registerModule(manager, &gmx_hydorder, "hydorder",
-                                         "Compute tetrahedrality parameters around a given atom");
-    LegacyCmdLineWrapper::registerModule(manager, &gmx_kinetics, "kinetics",
-                                         "Analyze kinetic constants from properties based on the Eyring model");
-    LegacyCmdLineWrapper::registerModule(manager, &gmx_lie, "lie",
-                                         "Estimate free energy from linear combinations");
-    LegacyCmdLineWrapper::registerModule(manager, &gmx_mdmat, "mdmat",
-                                         "Calculate residue contact maps");
-    LegacyCmdLineWrapper::registerModule(manager, &gmx_mindist, "mindist",
-                                         "Calculate the minimum distance between two groups");
-    LegacyCmdLineWrapper::registerModule(manager, &gmx_morph, "morph",
-                                         "Interpolate linearly between conformations");
-    LegacyCmdLineWrapper::registerModule(manager, &gmx_msd, "msd",
-                                         "Calculates mean square displacements");
-    LegacyCmdLineWrapper::registerModule(manager, &gmx_nmeig, "nmeig",
-                                         "Diagonalize the Hessian for normal mode analysis");
-    LegacyCmdLineWrapper::registerModule(manager, &gmx_nmens, "nmens",
-                                         "Generate an ensemble of structures from the normal modes");
-    LegacyCmdLineWrapper::registerModule(manager, &gmx_nmtraj, "nmtraj",
-                                         "Generate a virtual oscillating trajectory from an eigenvector");
-    LegacyCmdLineWrapper::registerModule(manager, &gmx_options, "options",
-                                         NULL);
-    LegacyCmdLineWrapper::registerModule(manager, &gmx_order, "order",
-                                         "Compute the order parameter per atom for carbon tails");
-    //LegacyCmdLineWrapper::registerModule(manager, &gmx_pme_error, "pme_error",
-    //        "Estimate the error of using PME with a given input file");
-    LegacyCmdLineWrapper::registerModule(manager, &gmx_polystat, "polystat",
-                                         "Calculate static properties of polymers");
-    LegacyCmdLineWrapper::registerModule(manager, &gmx_potential, "potential",
-                                         "Calculate the electrostatic potential across the box");
-    LegacyCmdLineWrapper::registerModule(manager, &gmx_principal, "principal",
-                                         "Calculate principal axes of inertia for a group of atoms");
-    LegacyCmdLineWrapper::registerModule(manager, &gmx_rama, "rama",
-                                         "Compute Ramachandran plots");
-    LegacyCmdLineWrapper::registerModule(manager, &gmx_rdf, "rdf",
-                                         "Calculate radial distribution functions");
-    LegacyCmdLineWrapper::registerModule(manager, &gmx_rms, "rms",
-                                         "Calculate RMSDs with a reference structure and RMSD matrices");
-    LegacyCmdLineWrapper::registerModule(manager, &gmx_rmsdist, "rmsdist",
-                                         "Calculate atom pair distances averaged with power -2, -3 or -6");
-    LegacyCmdLineWrapper::registerModule(manager, &gmx_rmsf, "rmsf",
-                                         "Calculate atomic fluctuations");
-    LegacyCmdLineWrapper::registerModule(manager, &gmx_rotacf, "rotacf",
-                                         "Calculate the rotational correlation function for molecules");
-    LegacyCmdLineWrapper::registerModule(manager, &gmx_rotmat, "rotmat",
-                                         "Plot the rotation matrix for fitting to a reference structure");
-    LegacyCmdLineWrapper::registerModule(manager, &gmx_saltbr, "saltbr",
-                                         "Compute salt bridges");
-    LegacyCmdLineWrapper::registerModule(manager, &gmx_sans, "sans",
-                                         "Compute the small angle neutron scattering spectra");
-    LegacyCmdLineWrapper::registerModule(manager, &gmx_sas, "sas",
-                                         "Compute solvent accessible surface area");
-    LegacyCmdLineWrapper::registerModule(manager, &gmx_saxs, "saxs",
-                                         "Calculates SAXS structure factors based on Cromer's method");
-    LegacyCmdLineWrapper::registerModule(manager, &gmx_sgangle, "sgangle",
-                                         "Compute the angle and distance between two groups");
-    LegacyCmdLineWrapper::registerModule(manager, &gmx_sham, "sham",
-                                         "Compute free energies or other histograms from histograms");
-    LegacyCmdLineWrapper::registerModule(manager, &gmx_sigeps, "sigeps",
-                                         "Convert c6/12 or c6/cn combinations to and from sigma/epsilon");
-    LegacyCmdLineWrapper::registerModule(manager, &gmx_sorient, "sorient",
-                                         "Analyze solvent orientation around solutes");
-    LegacyCmdLineWrapper::registerModule(manager, &gmx_spatial, "spatial",
-                                         "Calculate the spatial distribution function");
-    LegacyCmdLineWrapper::registerModule(manager, &gmx_spol, "spol",
-                                         "Analyze solvent dipole orientation and polarization around solutes");
-    LegacyCmdLineWrapper::registerModule(manager, &gmx_tcaf, "tcaf",
-                                         "Calculate viscosities of liquids");
-    LegacyCmdLineWrapper::registerModule(manager, &gmx_traj, "traj",
-                                         "Plot x, v, f, box, temperature and rotational energy from trajectories");
-    LegacyCmdLineWrapper::registerModule(manager, &gmx_tune_pme, "tune_pme",
-                                         "Time mdrun as a function of PME nodes to optimize settings");
-    LegacyCmdLineWrapper::registerModule(manager, &gmx_vanhove, "vanhove",
-                                         "Compute Van Hove correlation functions");
-    LegacyCmdLineWrapper::registerModule(manager, &gmx_velacc, "velacc",
-                                         "Calculate velocity autocorrelation functions");
-    LegacyCmdLineWrapper::registerModule(manager, &gmx_wham, "wham",
-                                         "Perform weighted histogram analysis after umbrella sampling");
-    LegacyCmdLineWrapper::registerModule(manager, &gmx_wheel, "wheel",
-                                         "Plot helical wheels");
+    registerModule(manager, &gmx_anadock, "anadock",
+                   "Cluster structures from Autodock runs");
+    registerModule(manager, &gmx_anaeig, "anaeig",
+                   "Analyze eigenvectors/normal modes");
+    registerModule(manager, &gmx_analyze, "analyze",
+                   "Analyze data sets");
+    registerModule(manager, &gmx_g_angle, "angle",
+                   "Calculate distributions and correlations for angles and dihedrals");
+    registerModule(manager, &gmx_bar, "bar",
+                   "Calculate free energy difference estimates through Bennett's acceptance ratio");
+    registerModule(manager, &gmx_bond, "bond",
+                   "Calculate distances between atoms and bond length distributions");
+    registerModule(manager, &gmx_bundle, "bundle",
+                   "Analyze bundles of axes, e.g., helices");
+    registerModule(manager, &gmx_chi, "chi",
+                   "Calculate everything you want to know about chi and other dihedrals");
+    registerModule(manager, &gmx_cluster, "cluster",
+                   "Cluster structures");
+    registerModule(manager, &gmx_clustsize, "clustsize",
+                   "Calculate size distributions of atomic clusters");
+    registerModule(manager, &gmx_confrms, "confrms",
+                   "Fit two structures and calculates the RMSD");
+    registerModule(manager, &gmx_covar, "covar",
+                   "Calculate and diagonalize the covariance matrix");
+    registerModule(manager, &gmx_current, "current",
+                   "Calculate dielectric constants and charge autocorrelation function");
+    registerModule(manager, &gmx_density, "density",
+                   "Calculate the density of the system");
+    registerModule(manager, &gmx_densmap, "densmap",
+                   "Calculate 2D planar or axial-radial density maps");
+    registerModule(manager, &gmx_densorder, "densorder",
+                   "Calculate surface fluctuations");
+    registerModule(manager, &gmx_dielectric, "dielectric",
+                   "Calculate frequency dependent dielectric constants");
+    registerModule(manager, &gmx_dipoles, "dipoles",
+                   "Compute the total dipole plus fluctuations");
+    registerModule(manager, &gmx_disre, "disre",
+                   "Analyze distance restraints");
+    registerModule(manager, &gmx_dist, "dist",
+                   "Calculate distances between centers of mass of two groups");
+    registerModule(manager, &gmx_dos, "dos",
+                   "Analyze density of states and properties based on that");
+    registerModule(manager, &gmx_dyecoupl, "dyecoupl",
+                   "Extract dye dynamics from trajectories");
+    registerModule(manager, &gmx_dyndom, "dyndom",
+                   "Interpolate and extrapolate structure rotations");
+    registerModule(manager, &gmx_enemat, "enemat",
+                   "Extract an energy matrix from an energy file");
+    registerModule(manager, &gmx_energy, "energy",
+                   "Writes energies to xvg files and display averages");
+    registerModule(manager, &gmx_filter, "filter",
+                   "Frequency filter trajectories, useful for making smooth movies");
+    registerModule(manager, &gmx_gyrate, "gyrate",
+                   "Calculate the radius of gyration");
+    registerModule(manager, &gmx_h2order, "h2order",
+                   "Compute the orientation of water molecules");
+    registerModule(manager, &gmx_hbond, "hbond",
+                   "Compute and analyze hydrogen bonds");
+    registerModule(manager, &gmx_helix, "helix",
+                   "Calculate basic properties of alpha helices");
+    registerModule(manager, &gmx_helixorient, "helixorient",
+                   "Calculate local pitch/bending/rotation/orientation inside helices");
+    registerModule(manager, &gmx_hydorder, "hydorder",
+                   "Compute tetrahedrality parameters around a given atom");
+    registerModule(manager, &gmx_kinetics, "kinetics",
+                   "Analyze kinetic constants from properties based on the Eyring model");
+    registerModule(manager, &gmx_lie, "lie",
+                   "Estimate free energy from linear combinations");
+    registerModule(manager, &gmx_mdmat, "mdmat",
+                   "Calculate residue contact maps");
+    registerModule(manager, &gmx_mindist, "mindist",
+                   "Calculate the minimum distance between two groups");
+    registerModule(manager, &gmx_morph, "morph",
+                   "Interpolate linearly between conformations");
+    registerModule(manager, &gmx_msd, "msd",
+                   "Calculates mean square displacements");
+    registerModule(manager, &gmx_nmeig, "nmeig",
+                   "Diagonalize the Hessian for normal mode analysis");
+    registerModule(manager, &gmx_nmens, "nmens",
+                   "Generate an ensemble of structures from the normal modes");
+    registerModule(manager, &gmx_nmtraj, "nmtraj",
+                   "Generate a virtual oscillating trajectory from an eigenvector");
+    registerModule(manager, &gmx_options, "options", NULL);
+    registerModule(manager, &gmx_order, "order",
+                   "Compute the order parameter per atom for carbon tails");
+    registerModule(manager, &gmx_pme_error, "pme_error",
+                   "Estimate the error of using PME with a given input file");
+    registerModule(manager, &gmx_polystat, "polystat",
+                   "Calculate static properties of polymers");
+    registerModule(manager, &gmx_potential, "potential",
+                   "Calculate the electrostatic potential across the box");
+    registerModule(manager, &gmx_principal, "principal",
+                   "Calculate principal axes of inertia for a group of atoms");
+    registerModule(manager, &gmx_rama, "rama",
+                   "Compute Ramachandran plots");
+    registerModule(manager, &gmx_rdf, "rdf",
+                   "Calculate radial distribution functions");
+    registerModule(manager, &gmx_rms, "rms",
+                   "Calculate RMSDs with a reference structure and RMSD matrices");
+    registerModule(manager, &gmx_rmsdist, "rmsdist",
+                   "Calculate atom pair distances averaged with power -2, -3 or -6");
+    registerModule(manager, &gmx_rmsf, "rmsf",
+                   "Calculate atomic fluctuations");
+    registerModule(manager, &gmx_rotacf, "rotacf",
+                   "Calculate the rotational correlation function for molecules");
+    registerModule(manager, &gmx_rotmat, "rotmat",
+                   "Plot the rotation matrix for fitting to a reference structure");
+    registerModule(manager, &gmx_saltbr, "saltbr",
+                   "Compute salt bridges");
+    registerModule(manager, &gmx_sans, "sans",
+                   "Compute the small angle neutron scattering spectra");
+    registerModule(manager, &gmx_sas, "sas",
+                   "Compute solvent accessible surface area");
+    registerModule(manager, &gmx_saxs, "saxs",
+                   "Calculates SAXS structure factors based on Cromer's method");
+    registerModule(manager, &gmx_sgangle, "sgangle",
+                   "Compute the angle and distance between two groups");
+    registerModule(manager, &gmx_sham, "sham",
+                   "Compute free energies or other histograms from histograms");
+    registerModule(manager, &gmx_sigeps, "sigeps",
+                   "Convert c6/12 or c6/cn combinations to and from sigma/epsilon");
+    registerModule(manager, &gmx_sorient, "sorient",
+                   "Analyze solvent orientation around solutes");
+    registerModule(manager, &gmx_spatial, "spatial",
+                   "Calculate the spatial distribution function");
+    registerModule(manager, &gmx_spol, "spol",
+                   "Analyze solvent dipole orientation and polarization around solutes");
+    registerModule(manager, &gmx_tcaf, "tcaf",
+                   "Calculate viscosities of liquids");
+    registerModule(manager, &gmx_traj, "traj",
+                   "Plot x, v, f, box, temperature and rotational energy from trajectories");
+    registerModule(manager, &gmx_tune_pme, "tune_pme",
+                   "Time mdrun as a function of PME nodes to optimize settings");
+    registerModule(manager, &gmx_vanhove, "vanhove",
+                   "Compute Van Hove correlation functions");
+    registerModule(manager, &gmx_velacc, "velacc",
+                   "Calculate velocity autocorrelation functions");
+    registerModule(manager, &gmx_wham, "wham",
+                   "Perform weighted histogram analysis after umbrella sampling");
+    registerModule(manager, &gmx_wheel, "wheel",
+                   "Plot helical wheels");
 
     // TODO: Also include binaries from other directories than src/tools/:
     //        "g_xrama|Show animated Ramachandran plots");
index 090710ff61783b9bb163ba0eae14f9321c1dfac5..ec64f9ad314e6900619e2b4e1cf27a16565873e0 100644 (file)
@@ -5,16 +5,6 @@ set(MDRUN_SOURCES
     md.c          mdrun.cpp     membed.c
     pme_loadbal.c repl_ex.c     runner.c    xutils.c)
 
-if(GMX_OPENMM)
-    # Even though the OpenMM build has "moved to contrib", many things
-    # have be be done from within the scope of the CMakeLists.txt that
-    # builds its mdrun, and that is here
-    list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/src/contrib)
-    find_package(OpenMM)
-    include_directories(${CMAKE_CURRENT_SOURCE_DIR})
-    include(${CMAKE_SOURCE_DIR}/src/contrib/BuildMdrunOpenMM.cmake)
-endif(GMX_OPENMM)
-
 if(GMX_FAHCORE)
     add_library(fahcore ${MDRUN_SOURCES})
 else(GMX_FAHCORE)
@@ -24,9 +14,6 @@ else(GMX_FAHCORE)
         ${GMX_EXE_LINKER_FLAGS})
     set_target_properties(mdrun PROPERTIES OUTPUT_NAME "mdrun${GMX_BINARY_SUFFIX}"
         COMPILE_FLAGS "${OpenMP_C_FLAGS}")
-    if(GMX_OPENMM)
-        target_link_libraries(mdrun openmm_api_wrapper)
-    endif()
     install(TARGETS mdrun DESTINATION ${BIN_INSTALL_DIR} COMPONENT mdrun)
 
     # Create the custom install-mdrun target
index ead14cf8ea3bec1b9b79bb750d0c30f6e98b2676..d2c79a6de0741ecf4131967f86e5ec6a13579578 100644 (file)
@@ -51,9 +51,9 @@
 #include "gromacs/legacyheaders/statutil.h"
 #include "gromacs/legacyheaders/typedefs.h"
 
-#include "gromacs/utility/programinfo.h"
+#include "gromacs/commandline/cmdlinemodulemanager.h"
 
-int main(int argc, char *argv[])
+int gmx_mdrun(int argc, char *argv[])
 {
     const char   *desc[] = {
         "The [TT]mdrun[tt] program is the main computational chemistry engine",
@@ -551,10 +551,9 @@ int main(int argc, char *argv[])
     char        **multidir = NULL;
 
 
-    cr = init_par(&argc, &argv);
-    gmx::ProgramInfo::init(argc, argv);
+    cr = init_par();
 
-    PCA_Flags = (PCA_CAN_SET_DEFFNM | PCA_STANDALONE | (MASTER(cr) ? 0 : PCA_QUIET));
+    PCA_Flags = (PCA_CAN_SET_DEFFNM | (MASTER(cr) ? 0 : PCA_QUIET));
 
     /* Comment this in to do fexist calls only on master
      * works not with rerun or tables at the moment
@@ -728,13 +727,6 @@ int main(int argc, char *argv[])
                   nmultisim, repl_ex_nst, repl_ex_nex, repl_ex_seed,
                   pforce, cpt_period, max_hours, deviceOptions, Flags);
 
-    gmx_finalize_par();
-
-    if (MULTIMASTER(cr))
-    {
-        gmx_thanx(stderr);
-    }
-
     /* Log file has to be closed in mdrunner if we are appending to it
        (fplog not set here) */
     if (MASTER(cr) && !bAppendFiles)
@@ -744,3 +736,8 @@ int main(int argc, char *argv[])
 
     return rc;
 }
+
+int main(int argc, char *argv[])
+{
+    return gmx::CommandLineModuleManager::runAsMainCMain(argc, argv, &gmx_mdrun);
+}
index abad36c26ad0cb0afb66fb9e89ea03b97c6a1cc7..9223385238c2e5c31edd3d1071226396511a3791 100644 (file)
@@ -13,12 +13,17 @@ and use the copy_xsl.sh script to copy it to relevant locations.
 <xsl:import href="common-referencedata.xsl"/>
 
 <xsl:template match="AnalysisData">
+    <xsl:variable name="has-datasetspec"
+                  select="DataFrame/DataValues/Int[@Name='DataSet']"/>
     <xsl:variable name="has-columnspec"
                   select="DataFrame/DataValues/Int[@Name='FirstColumn']"/>
     <table border="1">
         <tr>
             <th>Frame</th>
             <th>X</th>
+            <xsl:if test="$has-datasetspec">
+                <th>Set</th>
+            </xsl:if>
             <xsl:if test="$has-columnspec">
                 <th>Columns</th>
             </xsl:if>
@@ -28,6 +33,9 @@ and use the copy_xsl.sh script to copy it to relevant locations.
         <tr>
             <td><xsl:value-of select="../@Name"/></td>
             <td><xsl:value-of select="../Real[@Name='X']"/></td>
+            <xsl:if test="$has-datasetspec">
+                <td><xsl:value-of select="Int[@Name='DataSet']"/></td>
+            </xsl:if>
             <xsl:if test="$has-columnspec">
                 <td>
                     <xsl:choose>
@@ -46,8 +54,19 @@ and use the copy_xsl.sh script to copy it to relevant locations.
     </table>
 </xsl:template>
 
+<xsl:template match="DataValue[Bool[@Name='Present']='false']">
+    (
+    <xsl:value-of select="Real[@Name='Value']"/>
+    <xsl:if test="Real[@Name='Error']">
+        &#177; <xsl:value-of select="Real[@Name='Error']"/>
+    </xsl:if>
+    )
+</xsl:template>
 <xsl:template match="DataValue">
     <xsl:value-of select="Real[@Name='Value']"/>
+    <xsl:if test="Real[@Name='Error']">
+        &#177; <xsl:value-of select="Real[@Name='Error']"/>
+    </xsl:if>
 </xsl:template>
 
 </xsl:stylesheet>
index 23ba787b2c6d5398767772601e3856266b12ebd7..a3397caa740db9f60847e7cd2a8d3ee72f790db9 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2012, by the GROMACS development team, led by
+ * Copyright (c) 2012,2013, 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.
@@ -47,6 +47,7 @@
 #include <new>
 #include <vector>
 
+#include "gromacs/utility/gmxassert.h"
 #include "gromacs/utility/programinfo.h"
 
 namespace gmx
@@ -119,6 +120,8 @@ CommandLine::~CommandLine()
 
 void CommandLine::append(const char *arg)
 {
+    GMX_RELEASE_ASSERT(impl_->argc_ == static_cast<int>(impl_->args_.size()),
+                       "Command-line has been modified externally");
     size_t newSize = impl_->args_.size() + 1;
     impl_->args_.reserve(newSize);
     impl_->argv_.reserve(newSize);
index 32ea8f32e0725d88853355d8400cf7754a786228..ca979042ae3241ffa196251e8a5fb632008cea89 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2012, by the GROMACS development team, led by
+ * Copyright (c) 2012,2013, 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.
@@ -64,9 +64,8 @@ namespace test
  * Note that although the interface allows passing the argc and argv pointers
  * to methods that modify them (typically as \p f(&argc(), argv())), currently
  * the CommandLine object is not in a consistent state internally if the
- * parameters are actually modified.
- * Currently, the C++ methods with this signature do not modify their
- * parameters, so this is not yet a problem.
+ * parameters are actually modified.  Reading the command line is possible
+ * afterwards, but modification is not.
  *
  * All constructors and methods that modify this class may throw an
  * std::bad_alloc.  Const methods and accessors do not throw.
index d3ad9a9795bac5104c138da165180b3cc856b05f..723e0ad2948be83f2e4da30f3f450743ff55fc5f 100644 (file)
@@ -63,8 +63,8 @@ namespace test
  */
 
 AnalysisDataTestInputPointSet::AnalysisDataTestInputPointSet(
-        int index, int firstColumn)
-    : index_(index), firstColumn_(firstColumn)
+        int index, int dataSetIndex, int firstColumn)
+    : index_(index), dataSetIndex_(dataSetIndex), firstColumn_(firstColumn)
 {
 }
 
@@ -79,42 +79,52 @@ AnalysisDataTestInputFrame::AnalysisDataTestInputFrame(int index, real x)
 }
 
 AnalysisDataTestInputPointSet &
-AnalysisDataTestInputFrame::addPointSet(int firstColumn)
+AnalysisDataTestInputFrame::addPointSet(int dataSet, int firstColumn)
 {
-    pointSets_.push_back(AnalysisDataTestInputPointSet(pointSets_.size(), firstColumn));
+    pointSets_.push_back(
+            AnalysisDataTestInputPointSet(pointSets_.size(),
+                                          dataSet, firstColumn));
     return pointSets_.back();
 }
 
-void AnalysisDataTestInputFrame::addPointSetWithValues(int firstColumn, real y1)
+void AnalysisDataTestInputFrame::addPointSetWithValues(
+        int dataSet, int firstColumn, real y1)
 {
-    AnalysisDataTestInputPointSet &pointSet = addPointSet(firstColumn);
+    AnalysisDataTestInputPointSet &pointSet = addPointSet(dataSet, firstColumn);
     pointSet.addValue(y1);
 }
 
-void AnalysisDataTestInputFrame::addPointSetWithValues(int firstColumn, real y1,
-                                                       real y2)
+void AnalysisDataTestInputFrame::addPointSetWithValues(
+        int dataSet, int firstColumn, real y1, real y2)
 {
-    AnalysisDataTestInputPointSet &pointSet = addPointSet(firstColumn);
+    AnalysisDataTestInputPointSet &pointSet = addPointSet(dataSet, firstColumn);
     pointSet.addValue(y1);
     pointSet.addValue(y2);
 }
 
-void AnalysisDataTestInputFrame::addPointSetWithValues(int firstColumn, real y1,
-                                                       real y2, real y3)
+void AnalysisDataTestInputFrame::addPointSetWithValues(
+        int dataSet, int firstColumn, real y1, real y2, real y3)
 {
-    AnalysisDataTestInputPointSet &pointSet = addPointSet(firstColumn);
+    AnalysisDataTestInputPointSet &pointSet = addPointSet(dataSet, firstColumn);
     pointSet.addValue(y1);
     pointSet.addValue(y2);
     pointSet.addValue(y3);
 }
 
+void AnalysisDataTestInputFrame::addPointSetWithValueAndError(
+        int dataSet, int firstColumn, real y1, real e1)
+{
+    AnalysisDataTestInputPointSet &pointSet = addPointSet(dataSet, firstColumn);
+    pointSet.addValueWithError(y1, e1);
+}
+
 
 /********************************************************************
  * AnalysisDataTestInput
  */
 
-AnalysisDataTestInput::AnalysisDataTestInput(int columnCount, bool bMultipoint)
-    : columnCount_(columnCount), bMultipoint_(bMultipoint)
+AnalysisDataTestInput::AnalysisDataTestInput(int dataSetCount, bool bMultipoint)
+    : columnCounts_(dataSetCount), bMultipoint_(bMultipoint)
 {
 }
 
@@ -132,6 +142,14 @@ const AnalysisDataTestInputFrame &AnalysisDataTestInput::frame(int index) const
 }
 
 
+void AnalysisDataTestInput::setColumnCount(int dataSet, int columnCount)
+{
+    GMX_RELEASE_ASSERT(dataSet >= 0 && dataSet < dataSetCount(),
+                       "Out-of-range data set index");
+    columnCounts_[dataSet] = columnCount;
+}
+
+
 AnalysisDataTestInputFrame &AnalysisDataTestInput::addFrame(real x)
 {
     frames_.push_back(AnalysisDataTestInputFrame(frames_.size(), x));
@@ -141,19 +159,25 @@ AnalysisDataTestInputFrame &AnalysisDataTestInput::addFrame(real x)
 void AnalysisDataTestInput::addFrameWithValues(real x, real y1)
 {
     AnalysisDataTestInputFrame &frame = addFrame(x);
-    frame.addPointSetWithValues(0, y1);
+    frame.addPointSetWithValues(0, 0, y1);
 }
 
 void AnalysisDataTestInput::addFrameWithValues(real x, real y1, real y2)
 {
     AnalysisDataTestInputFrame &frame = addFrame(x);
-    frame.addPointSetWithValues(0, y1, y2);
+    frame.addPointSetWithValues(0, 0, y1, y2);
 }
 
 void AnalysisDataTestInput::addFrameWithValues(real x, real y1, real y2, real y3)
 {
     AnalysisDataTestInputFrame &frame = addFrame(x);
-    frame.addPointSetWithValues(0, y1, y2, y3);
+    frame.addPointSetWithValues(0, 0, y1, y2, y3);
+}
+
+void AnalysisDataTestInput::addFrameWithValueAndError(real x, real y1, real e1)
+{
+    AnalysisDataTestInputFrame &frame = addFrame(x);
+    frame.addPointSetWithValueAndError(0, 0, y1, e1);
 }
 
 
@@ -169,7 +193,11 @@ AnalysisDataTestFixture::AnalysisDataTestFixture()
 void AnalysisDataTestFixture::setupDataObject(const AnalysisDataTestInput &input,
                                               AnalysisData                *data)
 {
-    data->setColumnCount(input.columnCount());
+    data->setDataSetCount(input.dataSetCount());
+    for (int i = 0; i < input.dataSetCount(); ++i)
+    {
+        data->setColumnCount(i, input.columnCount(i));
+    }
     data->setMultipoint(input.isMultipoint());
 }
 
@@ -196,10 +224,19 @@ void AnalysisDataTestFixture::presentDataFrame(const AnalysisDataTestInput &inpu
     for (int i = 0; i < frame.pointSetCount(); ++i)
     {
         const AnalysisDataTestInputPointSet &points = frame.pointSet(i);
+        handle.selectDataSet(points.dataSetIndex());
         for (int j = 0; j < points.size(); ++j)
         {
-            handle.setPoint(j + points.firstColumn(),
-                            points.y(j), points.dy(j), points.present(j));
+            if (points.hasError(j))
+            {
+                handle.setPoint(j + points.firstColumn(),
+                                points.y(j), points.error(j), points.present(j));
+            }
+            else
+            {
+                handle.setPoint(j + points.firstColumn(),
+                                points.y(j), points.present(j));
+            }
         }
         if (input.isMultipoint())
         {
index 0de86506f5dc755accb69d6995835279277fb7ec..ef2290120fdb2dcc19a55b9285702d16678e8a51 100644 (file)
@@ -49,6 +49,7 @@
 
 #include "gromacs/legacyheaders/types/simple.h"
 
+#include "gromacs/analysisdata/dataframe.h"
 #include "gromacs/utility/gmxassert.h"
 
 #include "testutils/refdata.h"
@@ -79,31 +80,62 @@ class AnalysisDataTestInputPointSet
     public:
         //! Returns zero-based index of this point set in its frame.
         int index() const { return index_; }
+        //! Returns zero-based index of the data set of this point set.
+        int dataSetIndex() const { return dataSetIndex_; }
         //! Returns zero-based index of the first column in this point set.
         int firstColumn() const { return firstColumn_; }
         //! Returns zero-based index of the last column in this point set.
         int lastColumn() const { return firstColumn_ + size() - 1; }
         //! Returns the number of columns in the point set.
-        int size() const { return y_.size(); }
+        int size() const { return values_.size(); }
         //! Returns the value in column \p i.
-        real y(int i) const { return y_[i]; }
+        real y(int i) const { return values_[i].y; }
+        //! Returns whether the error is present for column \p i.
+        bool hasError(int i) const { return values_[i].bError; }
         //! Returns the error in column \p i.
-        real dy(int i) const { return 0.0; }
+        real error(int i) const { return values_[i].error; }
         //! Returns whether the value in column \p i is present.
-        real present(int i) const { return true; }
-        //! Returns a vector of values for all columns.
-        const std::vector<real> &yvector() const { return y_; }
+        bool present(int i) const { return true; }
+        //! Returns an AnalysisDataValue for column \p i.
+        AnalysisDataValue value(int i) const
+        {
+            AnalysisDataValue result;
+            result.setValue(values_[i].y);
+            if (values_[i].bError)
+            {
+                result.setError(values_[i].error);
+            }
+            return result;
+        }
 
         //! Appends a value to this point set.
-        void addValue(real y) { y_.push_back(y); }
+        void addValue(real y) { values_.push_back(Value(y)); }
+        //! Appends a value with an error estimate to this point set.
+        void addValueWithError(real y, real error)
+        {
+            values_.push_back(Value(y, error));
+        }
 
     private:
         //! Creates an empty point set.
-        AnalysisDataTestInputPointSet(int index, int firstColumn);
+        AnalysisDataTestInputPointSet(int index, int dataSetIndex,
+                                      int firstColumn);
+
+        struct Value
+        {
+            Value() : y(0.0), error(0.0), bError(false) {}
+            explicit Value(real y) : y(y), error(0.0), bError(false) {}
+            Value(real y, real error) : y(y), error(error), bError(true) {}
+
+            real                y;
+            real                error;
+            bool                bError;
+        };
 
         int                     index_;
+        int                     dataSetIndex_;
         int                     firstColumn_;
-        std::vector<real>       y_;
+        std::vector<Value>      values_;
 
         //! For constructing new point sets.
         friend class AnalysisDataTestInputFrame;
@@ -136,13 +168,18 @@ class AnalysisDataTestInputFrame
         }
 
         //! Appends an empty point set to this frame.
-        AnalysisDataTestInputPointSet &addPointSet(int firstColumn);
+        AnalysisDataTestInputPointSet &addPointSet(int dataSet, int firstColumn);
+        //! Adds a point set with given values to this frame.
+        void addPointSetWithValues(int dataSet, int firstColumn, real y1);
         //! Adds a point set with given values to this frame.
-        void addPointSetWithValues(int firstColumn, real y1);
+        void addPointSetWithValues(int dataSet, int firstColumn,
+                                   real y1, real y2);
         //! Adds a point set with given values to this frame.
-        void addPointSetWithValues(int firstColumn, real y1, real y2);
+        void addPointSetWithValues(int dataSet, int firstColumn,
+                                   real y1, real y2, real y3);
         //! Adds a point set with given values to this frame.
-        void addPointSetWithValues(int firstColumn, real y1, real y2, real y3);
+        void addPointSetWithValueAndError(int dataSet, int firstColumn,
+                                          real y1, real e1);
 
     private:
         //! Constructs a new frame object with the given values.
@@ -173,21 +210,28 @@ class AnalysisDataTestInput
         /*! \brief
          * Constructs empty input data.
          *
-         * \param[in] columnCount  Number of columns in the data.
+         * \param[in] dataSetCount Number of data sets in the data.
          * \param[in] bMultipoint  Whether the data will be multipoint.
+         *
+         * The column count for each data set must be set with
+         * setColumnCount().
          */
-        AnalysisDataTestInput(int columnCount, bool bMultipoint);
+        AnalysisDataTestInput(int dataSetCount, bool bMultipoint);
         ~AnalysisDataTestInput();
 
         //! Whether the input data is multipoint.
         bool isMultipoint() const { return bMultipoint_; }
-        //! Returns the number of columns in the input data.
-        int columnCount() const { return columnCount_; }
+        //! Returns the number of data sets in the input data.
+        int dataSetCount() const { return columnCounts_.size(); }
+        //! Returns the number of columns in a given data set.
+        int columnCount(int dataSet) const { return columnCounts_[dataSet]; }
         //! Returns the number of frames in the input data.
         int frameCount() const { return frames_.size(); }
         //! Returns a frame object for the given input frame.
         const AnalysisDataTestInputFrame &frame(int index) const;
 
+        //! Sets the number of columns in a data set.
+        void setColumnCount(int dataSet, int columnCount);
         //! Appends an empty frame to this data.
         AnalysisDataTestInputFrame &addFrame(real x);
         //! Adds a frame with a single point set and the given values.
@@ -196,9 +240,11 @@ class AnalysisDataTestInput
         void addFrameWithValues(real x, real y1, real y2);
         //! Adds a frame with a single point set and the given values.
         void addFrameWithValues(real x, real y1, real y2, real y3);
+        //! Adds a frame with a single point set and the given values.
+        void addFrameWithValueAndError(real x, real y1, real e1);
 
     private:
-        int                                     columnCount_;
+        std::vector<int>                        columnCounts_;
         bool                                    bMultipoint_;
         std::vector<AnalysisDataTestInputFrame> frames_;
 };
@@ -393,11 +439,13 @@ void AnalysisDataTestFixture::setupArrayData(const AnalysisDataTestInput &input,
 {
     GMX_RELEASE_ASSERT(!input.isMultipoint(),
                        "Array data cannot be initialized from multipoint data");
-    GMX_RELEASE_ASSERT(data->columnCount() == 0 || data->columnCount() == input.columnCount(),
+    GMX_RELEASE_ASSERT(input.dataSetCount() == 1,
+                       "Array data cannot be initialized from multiple data sets");
+    GMX_RELEASE_ASSERT(data->columnCount() == 0 || data->columnCount() == input.columnCount(0),
                        "Mismatching input and target data");
     GMX_RELEASE_ASSERT(data->rowCount() == 0 || data->rowCount() == input.frameCount(),
                        "Mismatching input and target data");
-    data->setColumnCount(input.columnCount());
+    data->setColumnCount(input.columnCount(0));
     data->setRowCount(input.frameCount());
     data->allocateValues();
     for (int row = 0; row < input.frameCount(); ++row)
@@ -409,7 +457,7 @@ void AnalysisDataTestFixture::setupArrayData(const AnalysisDataTestInput &input,
         const AnalysisDataTestInputPointSet &points = frame.pointSet(0);
         for (int column = 0; column < points.size(); ++column)
         {
-            data->setValue(row, column + points.firstColumn(), points.y(column));
+            data->value(row, column + points.firstColumn()) = points.value(column);
         }
     }
 }
index 4be423ac1b24f03ade918c0751ce94a8b46447a6..ec583a25fc0c5129f0f8689b6fa8a51dbe11546c 100644 (file)
@@ -77,7 +77,7 @@ class MockAnalysisDataModule::Impl
          * Callback used to initialize reference data checks
          *
          * Called in response to dataStarted().
-         * Records information about the source data for later use.
+         * Records the source data for later use (for access to data properties).
          */
         void startReferenceData(AbstractAnalysisData *data);
         /*! \brief
@@ -115,12 +115,12 @@ class MockAnalysisDataModule::Impl
          * calls.
          */
         boost::scoped_ptr<TestReferenceChecker>  frameChecker_;
+        //! Source data.
+        const AbstractAnalysisData              *source_;
         //! Flags that will be returned by the mock module.
         int                                      flags_;
         //! Index of the current/next frame.
         int                                      frameIndex_;
-        //! Number of columns in the source data (for reference checking only).
-        int                                      columnCount_;
 };
 
 namespace
@@ -149,7 +149,7 @@ void checkReferenceDataPoint(TestReferenceChecker    *checker,
 }       // namespace
 
 MockAnalysisDataModule::Impl::Impl(int flags)
-    : flags_(flags), frameIndex_(0), columnCount_(-1)
+    : source_(NULL), flags_(flags), frameIndex_(0)
 {
 }
 
@@ -157,7 +157,7 @@ MockAnalysisDataModule::Impl::Impl(int flags)
 void
 MockAnalysisDataModule::Impl::startReferenceData(AbstractAnalysisData *data)
 {
-    columnCount_ = data->columnCount();
+    source_ = data;
 }
 
 
@@ -186,13 +186,19 @@ MockAnalysisDataModule::Impl::checkReferencePoints(
         TestReferenceChecker checker(
                 frameChecker_->checkCompound("DataValues", NULL));
         checker.checkInteger(points.columnCount(), "Count");
-        bool bAllColumns = (points.firstColumn() == 0
-                            && points.columnCount() == columnCount_);
+        if (checker.checkPresent(source_->dataSetCount() > 1, "DataSet"))
+        {
+            checker.checkInteger(points.dataSetIndex(), "DataSet");
+        }
+        const int  sourceColumnCount = source_->columnCount(points.dataSetIndex());
+        const bool bAllColumns       = (points.firstColumn() == 0
+                                        && points.columnCount() == sourceColumnCount);
         if (checker.checkPresent(!bAllColumns, "FirstColumn"))
         {
             checker.checkInteger(points.firstColumn(), "FirstColumn");
             checker.checkInteger(points.lastColumn(),  "LastColumn");
         }
+
         AnalysisDataValuesRef::const_iterator value;
         for (value = points.values().begin(); value != points.values().end(); ++value)
         {
@@ -342,6 +348,7 @@ class StaticDataPointsChecker
         {
             SCOPED_TRACE(formatString("Frame %d, point set %d",
                                       frame_->index(), points_->index()));
+            EXPECT_EQ(points_->dataSetIndex(), points.dataSetIndex());
             const int expectedFirstColumn
                 = std::max(0, points_->firstColumn() - firstcol_);
             const int expectedLastColumn
@@ -482,9 +489,7 @@ void
 MockAnalysisDataModule::setupStaticCheck(const AnalysisDataTestInput &data,
                                          AbstractAnalysisData        *source)
 {
-    GMX_RELEASE_ASSERT(data.columnCount() == source->columnCount(),
-                       "Mismatching data column count");
-    impl_->flags_ |= efAllowMulticolumn | efAllowMultipoint;
+    impl_->flags_ |= efAllowMulticolumn | efAllowMultipoint | efAllowMultipleDataSets;
 
     ::testing::InSequence dummy;
     using ::testing::_;
@@ -499,9 +504,9 @@ MockAnalysisDataModule::setupStaticCheck(const AnalysisDataTestInput &data,
         for (int ps = 0; ps < frame.pointSetCount(); ++ps)
         {
             const AnalysisDataTestInputPointSet &points = frame.pointSet(ps);
-            EXPECT_CALL(*this, pointsAdded(_))
-                .WillOnce(Invoke(StaticDataPointsChecker(&frame, &points, 0,
-                                                         data.columnCount())));
+            StaticDataPointsChecker              checker(&frame, &points, 0,
+                                                         data.columnCount(points.dataSetIndex()));
+            EXPECT_CALL(*this, pointsAdded(_)).WillOnce(Invoke(checker));
         }
         EXPECT_CALL(*this, frameFinished(_))
             .WillOnce(Invoke(StaticDataFrameHeaderChecker(&frame)));
@@ -515,11 +520,7 @@ MockAnalysisDataModule::setupStaticColumnCheck(
         const AnalysisDataTestInput &data,
         int firstcol, int n, AbstractAnalysisData *source)
 {
-    GMX_RELEASE_ASSERT(data.columnCount() == source->columnCount(),
-                       "Mismatching data column count");
-    GMX_RELEASE_ASSERT(firstcol >= 0 && n > 0 && firstcol + n <= data.columnCount(),
-                       "Out-of-range columns");
-    impl_->flags_ |= efAllowMulticolumn | efAllowMultipoint;
+    impl_->flags_ |= efAllowMulticolumn | efAllowMultipoint | efAllowMultipleDataSets;
 
     ::testing::InSequence dummy;
     using ::testing::_;
@@ -553,11 +554,9 @@ MockAnalysisDataModule::setupStaticStorageCheck(
         const AnalysisDataTestInput &data,
         int storageCount, AbstractAnalysisData *source)
 {
-    GMX_RELEASE_ASSERT(data.columnCount() == source->columnCount(),
-                       "Mismatching data column count");
     GMX_RELEASE_ASSERT(data.isMultipoint() == source->isMultipoint(),
                        "Mismatching multipoint properties");
-    impl_->flags_ |= efAllowMulticolumn | efAllowMultipoint;
+    impl_->flags_ |= efAllowMulticolumn | efAllowMultipoint | efAllowMultipleDataSets;
 
     ::testing::InSequence dummy;
     using ::testing::_;
@@ -587,7 +586,8 @@ void
 MockAnalysisDataModule::setupReferenceCheck(const TestReferenceChecker &checker,
                                             AbstractAnalysisData       *source)
 {
-    impl_->flags_ |= efAllowMulticolumn | efAllowMultipoint;
+    impl_->flags_ |= efAllowMulticolumn | efAllowMultipoint | efAllowMissing
+        | efAllowMultipleDataSets;
 
     impl_->rootChecker_.reset(new TestReferenceChecker(checker));
     // Google Mock does not support checking the order fully, because
index d94195b5b4e340e7bb407583815efe00a0988787..755aeceabc50499b50f4e006080337472b93898b 100644 (file)
 
 #include <cstdio>
 #include <cstdlib>
-#include <cstring>
 
-#include <new>
 #include <string>
 
 #include <gtest/gtest.h>
 #include <libxml/parser.h>
 #include <libxml/xmlmemory.h>
 
+#include "gromacs/options/basicoptions.h"
+#include "gromacs/options/options.h"
 #include "gromacs/utility/exceptions.h"
 #include "gromacs/utility/gmxassert.h"
 #include "gromacs/utility/path.h"
@@ -76,7 +76,8 @@ class TestReferenceDataEnvironment : public ::testing::Environment
 };
 
 //! Global reference data mode set with gmx::test::setReferenceDataMode().
-gmx::test::ReferenceDataMode g_referenceDataMode = gmx::test::erefdataCompare;
+// TODO: Make this a real enum; requires solving a TODO in StringOption.
+int g_referenceDataMode = gmx::test::erefdataCompare;
 
 } // namespace
 
@@ -87,7 +88,7 @@ namespace test
 
 ReferenceDataMode getReferenceDataMode()
 {
-    return g_referenceDataMode;
+    return static_cast<ReferenceDataMode>(g_referenceDataMode);
 }
 
 void setReferenceDataMode(ReferenceDataMode mode)
@@ -100,34 +101,16 @@ std::string getReferenceDataPath()
     return TestFileManager::getInputFilePath("refdata");
 }
 
-void initReferenceData(int *argc, char **argv)
+void initReferenceData(Options *options)
 {
-    int i, newi;
-
-    for (i = newi = 1; i < *argc; ++i, ++newi)
-    {
-        argv[newi] = argv[i];
-        if (!std::strcmp(argv[i], "--create-ref-data"))
-        {
-            setReferenceDataMode(erefdataCreateMissing);
-            --newi;
-        }
-        else if (!std::strcmp(argv[i], "--update-ref-data"))
-        {
-            setReferenceDataMode(erefdataUpdateAll);
-            --newi;
-        }
-    }
-    *argc = newi;
-    try
-    {
-        ::testing::AddGlobalTestEnvironment(new TestReferenceDataEnvironment);
-    }
-    catch (const std::bad_alloc &)
-    {
-        std::fprintf(stderr, "Out of memory\n");
-        std::exit(1);
-    }
+    // Needs to correspond to the enum order in refdata.h.
+    const char *const refDataEnum[] = { "check", "create", "update" };
+    options->addOption(
+            StringOption("ref-data").enumValue(refDataEnum)
+                .defaultEnumIndex(0)
+                .storeEnumIndex(&g_referenceDataMode)
+                .description("Operation mode for tests that use reference data"));
+    ::testing::AddGlobalTestEnvironment(new TestReferenceDataEnvironment);
 }
 
 /********************************************************************
index 8bd91204f3bd1a337b99aa1e2d88b98aff092445..ed678309ffd50533786c038cc1cd7f08ddc3a725 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2011,2012, by the GROMACS development team, led by
+ * Copyright (c) 2011,2012,2013, 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.
@@ -50,6 +50,9 @@
 
 namespace gmx
 {
+
+class Options;
+
 namespace test
 {
 
@@ -105,17 +108,13 @@ std::string getReferenceDataPath();
 /*! \libinternal \brief
  * Initializes reference data handling.
  *
- * Sets the reference data mode based on command-line arguments.  By default,
- * ::erefdataCompare is used, but \c --create-ref-data or \c --update-ref-data
- * can be used to change it.
- * Recognized command-line arguments are removed from the list.
- *
- * Does not throw.  Terminates the program with a non-zero error code if an
- * error occurs.
+ * Adds command-line options to \p options to set the reference data mode.
+ * By default, ::erefdataCompare is used, but \c "--ref-data create" or
+ * \c "--ref-data update" can be used to change it.
  *
  * This function is automatically called by initTestUtils().
  */
-void initReferenceData(int *argc, char **argv);
+void initReferenceData(Options *options);
 
 
 class TestReferenceChecker;
@@ -150,7 +149,7 @@ class TestReferenceChecker;
        checker.checkInteger(functionToTest(3), "ValueWith3");
        checker.checkInteger(functionToTest(5), "ValueWith5");
        gmx::test::TestReferenceChecker compound(
-               checker.startCompound("CustomCompound", "Item"));
+               checker.checkCompound("CustomCompound", "Item"));
        compound.checkInteger(function2ToTest(3), "ValueWith3");
        compound.checkInteger(function2ToTest(5), "ValueWith5");
        checker.checkInteger(functionToTest(4), "ValueWith4");
index 8df4c3f1f1557c27a8e82013d68a7bae0537db95..239eea71ae258d30aeb882ecfab9b57159ef4925 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2012, by the GROMACS development team, led by
+ * Copyright (c) 2012,2013, 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.
@@ -44,6 +44,7 @@
 #include "gromacs/options/basicoptions.h"
 #include "gromacs/options/options.h"
 #include "gromacs/utility/file.h"
+
 #include "testutils/testoptions.h"
 
 namespace gmx
@@ -51,13 +52,21 @@ namespace gmx
 namespace test
 {
 
-bool StringTestBase::s_bWriteToStdOut = false;
+namespace
+{
+//! Stores the -stdout flag value to print out values instead of checking them.
+bool g_bWriteToStdOut = false;
+}
 
-void StringTestBase::SetUpTestCase()
+// TODO: Only add this option to those test binaries that actually need it
+// (depending on the linker, it may or may not appear right now),
+// or replace by a generic mechanism in TestReferenceData.
+GMX_TEST_OPTIONS(StringTestOptions, options)
 {
-    Options options(NULL, NULL);
-    options.addOption(BooleanOption("stdout").store(&s_bWriteToStdOut));
-    parseTestOptions(&options);
+    options->addOption(
+            BooleanOption("stdout")
+                .store(&g_bWriteToStdOut)
+                .description("Print the test string to stdout instead of checking against reference data"));
 }
 
 StringTestBase::StringTestBase()
@@ -81,7 +90,7 @@ StringTestBase::checker()
 void
 StringTestBase::checkText(const std::string &text, const char *id)
 {
-    if (s_bWriteToStdOut)
+    if (g_bWriteToStdOut)
     {
         printf("%s:\n", id);
         printf("%s[END]\n", text.c_str());
index a300ac22b5e4332f8380ade4b8c7961dda14fa43..290dd03e90d5ce846981c8d94f0c2bbd415f474e 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2012, by the GROMACS development team, led by
+ * Copyright (c) 2012,2013, 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.
@@ -69,9 +69,6 @@ namespace test
 class StringTestBase : public ::testing::Test
 {
     public:
-        //! Static fixture setup to parse command-line options.
-        static void SetUpTestCase();
-
         StringTestBase();
         ~StringTestBase();
 
@@ -102,8 +99,6 @@ class StringTestBase : public ::testing::Test
         void checkFileContents(const std::string &filename, const char *id);
 
     private:
-        static bool                             s_bWriteToStdOut;
-
         TestReferenceData                       data_;
         boost::scoped_ptr<TestReferenceChecker> checker_;
 };
index 664973f182e7b59b0ad6306aaf5d1f915bc790b0..8eb6af261e42a6ee1e079c4d60edc25d78a99d6d 100644 (file)
@@ -92,7 +92,7 @@ namespace test
         catch (std::exception const &ex) { \
             gmx_ar << "Expected: " #statement " throws an exception of type " \
             << #expected_exception ".\n  Actual: it throws a different type.\n" \
-            << "Exception details:\n" << ::gmx::formatException(ex); \
+            << "Exception details:\n" << ::gmx::formatExceptionMessageToString(ex); \
             goto GTEST_CONCAT_TOKEN_(gmx_label_testthrow_, __LINE__); \
         } \
         catch (...) { \
@@ -128,7 +128,7 @@ namespace test
         catch (std::exception const &ex) { \
             gmx_ar << "Expected: " #statement " doesn't throw an exception.\n" \
             << "  Actual: it throws.\n" \
-            << "Exception details:\n" << ::gmx::formatException(ex); \
+            << "Exception details:\n" << ::gmx::formatExceptionMessageToString(ex); \
             goto GTEST_CONCAT_TOKEN_(gmx_label_testnothrow_, __LINE__); \
         } \
         catch (...) { \
index debc0c072890e5e495ab9d2ad66095510bda3b3e..e97eed1ad6ec445b777da7d3263ed84323b4a7a1 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2012, by the GROMACS development team, led by
+ * Copyright (c) 2012,2013, 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.
 #include <cstdio>
 #include <cstdlib>
 
-#include <new>
-#include <string>
-#include <vector>
+#include <list>
 
-#include <boost/scoped_ptr.hpp>
 #include <gmock/gmock.h>
 
+#include "gromacs/legacyheaders/thread_mpi/mutex.h"
+
+#include "gromacs/commandline/cmdlinehelpwriter.h"
 #include "gromacs/commandline/cmdlineparser.h"
+#include "gromacs/onlinehelp/helpwritercontext.h"
+#include "gromacs/options/basicoptions.h"
 #include "gromacs/options/options.h"
+#include "gromacs/utility/common.h"
 #include "gromacs/utility/errorcodes.h"
-#include "gromacs/utility/gmxassert.h"
-#include "gromacs/utility/programinfo.h"
+#include "gromacs/utility/exceptions.h"
+#include "gromacs/utility/file.h"
+#include "gromacs/utility/init.h"
 
 #include "refdata.h"
-#include "testexceptions.h"
 #include "testfilemanager.h"
 
+namespace gmx
+{
+namespace test
+{
+
 namespace
 {
 
-//! Stored command line for gmx::test::parseTestOptions().
-boost::scoped_ptr<std::vector<std::string> > s_commandLine;
+/*! \internal \brief
+ * Global test environment for freeing up libxml2 internal buffers.
+ */
+class GromacsTestEnvironment : public ::testing::Environment
+{
+    public:
+        //! Calls MPI_Finalize() if necessary.
+        virtual void TearDown()
+        {
+            gmx::finalize();
+        }
+};
 
-} // namespace
+/*! \brief
+ * Singleton registry for test options added with GMX_TEST_OPTIONS.
+ *
+ * \ingroup module_testutils
+ */
+class TestOptionsRegistry
+{
+    public:
+        //! Returns the singleton instance of this class.
+        static TestOptionsRegistry &getInstance()
+        {
+            static TestOptionsRegistry singleton;
+            return singleton;
+        }
 
-namespace gmx
+        //! Adds a provider into the registry.
+        void add(const char * /*name*/, TestOptionsProvider *provider)
+        {
+            tMPI::lock_guard<tMPI::mutex> lock(listMutex_);
+            providerList_.push_back(provider);
+        }
+
+        //! Initializes the options from all the provides.
+        void initOptions(Options *options);
+
+    private:
+        TestOptionsRegistry() {}
+
+        typedef std::list<TestOptionsProvider *> ProviderList;
+
+        tMPI::mutex             listMutex_;
+        ProviderList            providerList_;
+
+        GMX_DISALLOW_COPY_AND_ASSIGN(TestOptionsRegistry);
+};
+
+void TestOptionsRegistry::initOptions(Options *options)
 {
-namespace test
+    // TODO: Have some deterministic order for the options; now it depends on
+    // the order in which the global initializers are run.
+    tMPI::lock_guard<tMPI::mutex> lock(listMutex_);
+    ProviderList::const_iterator i;
+    for (i = providerList_.begin(); i != providerList_.end(); ++i)
+    {
+        (*i)->initOptions(options);
+    }
+}
+
+//! Prints the command-line options for the unit test binary.
+void printHelp(const Options &options)
 {
+    std::fprintf(stderr,
+                 "\nYou can use the following GROMACS-specific command-line flags\n"
+                 "to control the behavior of the tests:\n\n");
+    HelpWriterContext context(&File::standardError(),
+                              eHelpOutputFormat_Console);
+    CommandLineHelpWriter(options).writeHelp(context);
+}
+
+} // namespace
+
+void registerTestOptions(const char *name, TestOptionsProvider *provider)
+{
+    TestOptionsRegistry::getInstance().add(name, provider);
+}
 
-void initTestUtils(const char *dataPath, int *argc, char *argv[])
+void initTestUtils(const char *dataPath, int *argc, char ***argv)
 {
     try
     {
-        ProgramInfo::init(*argc, argv);
-        ::testing::InitGoogleMock(argc, argv);
+        gmx::init(argc, argv);
+        ::testing::InitGoogleMock(argc, *argv);
         if (dataPath != NULL)
         {
             TestFileManager::setInputDataDirectory(dataPath);
         }
-        initReferenceData(argc, argv);
-        boost::scoped_ptr<std::vector<std::string> > commandLine(
-                new std::vector<std::string>());
-        for (int i = 0; i < *argc; ++i)
+        bool bHelp = false;
+        Options options(NULL, NULL);
+        // TODO: A single option that accepts multiple names would be nicer.
+        // Also, we recognize -help, but GTest doesn't, which leads to a bit
+        // unintuitive behavior.
+        options.addOption(BooleanOption("h").store(&bHelp)
+                              .description("Print GROMACS-specific unit test options"));
+        options.addOption(BooleanOption("help").store(&bHelp).hidden());
+        options.addOption(BooleanOption("?").store(&bHelp).hidden());
+        // TODO: Consider removing this option from test binaries that do not need it.
+        initReferenceData(&options);
+        TestOptionsRegistry::getInstance().initOptions(&options);
+        try
         {
-            commandLine->push_back(argv[i]);
+            CommandLineParser(&options).parse(argc, *argv);
+            options.finish();
         }
-        swap(commandLine, s_commandLine);
+        catch (const UserInputError &)
+        {
+            printHelp(options);
+            throw;
+        }
+        if (bHelp)
+        {
+            printHelp(options);
+        }
+        setFatalErrorHandler(NULL);
+        ::testing::AddGlobalTestEnvironment(new GromacsTestEnvironment);
     }
     catch (const std::exception &ex)
     {
         printFatalErrorMessage(stderr, ex);
-        std::exit(1);
-    }
-    ::gmx::setFatalErrorHandler(NULL);
-}
-
-void parseTestOptions(Options *options)
-{
-    GMX_RELEASE_ASSERT(s_commandLine.get() != NULL,
-                       "Test options not initialized");
-    try
-    {
-        CommandLineParser(options).parse(s_commandLine.get());
-        options->finish();
-    }
-    catch (const GromacsException &ex)
-    {
-        GMX_THROW_WRAPPER_TESTEXCEPTION(ex);
+        std::exit(processExceptionAtExit(ex));
     }
 }
 
index 0ab2ff9a3121b994b9f5f93b88765dbc74fad19c..eb0a7c23b87bafc5f3ef52a185cb2b7b2ddd8505 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2012, by the GROMACS development team, led by
+ * Copyright (c) 2012,2013, 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.
@@ -56,29 +56,98 @@ namespace test
 {
 
 /*! \libinternal \brief
- * Initializes the test utilities library.
+ * Provides additional options for the test executable.
  *
- * Does not throw.  Terminates the program with a non-zero error code if an
- * error occurs.
+ * Typically not used directly in test code, but through the
+ * GMX_TEST_OPTIONS macro.
  *
- * This function is automatically called by test_main_gtest.cpp and
- * test_main_gmock.cpp.
+ * \inlibraryapi
+ * \ingroup module_testutils
  */
-void initTestUtils(const char *dataPath, int *argc, char *argv[]);
+class TestOptionsProvider
+{
+    public:
+        /*! \brief
+         * Initializes the options from this provider.
+         *
+         * \param   options  The options need to be added here.
+         */
+        virtual void initOptions(Options *options) = 0;
+
+    protected:
+        virtual ~TestOptionsProvider() {}
+};
+
 /*! \libinternal \brief
- * Parses given options from the command line.
+ * Registers a test option provider with the test framework.
  *
- * \param[in] options  Definition of options to parse.
- * \throws  std::bad_alloc if out of memory.
- * \throws  TestException if an error occurs in the parsing.
+ * \param[in] name     Name of the options provider (for ordering).
+ * \param[in] provider The provider to register.
+ * \throws  std::bad_alloc     if out of memory.
+ * \throws  tMPI::system_error on mutex failures.
  *
- * This can be used from test or test fixture setup functions to initialize
- * local variables.  Although this means that the parameters are potentially
- * parsed multiple times, the performance impact should not be significant.
+ * Typically not used directly in test code, but through the
+ * GMX_TEST_OPTIONS macro.
  *
- * \inlibraryapi
+ * This gets called from constructors for global variables, so ideally
+ * it would not throw to avoid unhandled exceptions.  But since this
+ * is only test code, it is not worth the effort to try to remove those
+ * rare exceptions (mutex failures and out-of-memory from STL).
+ *
+ * \ingroup module_testutils
+ */
+void registerTestOptions(const char *name, TestOptionsProvider *provider);
+
+/*! \libinternal \brief
+ * Macro to add additional command-line options for the test binary.
+ *
+ * Typical usage:
+ * \code
+   namespace
+   {
+
+   bool g_optionValue = false;
+
+   GMX_TEST_OPTIONS(MyTestOptions, options)
+   {
+       options->addOption(BooleanOption("-flag").store(g_optionValue)
+                              .description("My description"));
+   }
+
+   } // namespace
+ * \endcode
+ *
+ * One macro invocation per an added option, with more of the implementation
+ * details hidden inside the macro, could be nicer.  But that requires more
+ * elaborate macro machinery, so it is probably not worth the effort and
+ * complexity.
+ *
+ * \ingroup module_testutils
+ */
+#define GMX_TEST_OPTIONS(name, options) \
+    class name : public ::gmx::test::TestOptionsProvider \
+    { \
+        public: \
+            name() \
+            { \
+                ::gmx::test::registerTestOptions(#name, this); \
+            } \
+            virtual void initOptions(::gmx::Options *options); \
+    }; \
+    \
+    static name s_##name##Instance; \
+    \
+    void name::initOptions(::gmx::Options *options)
+
+/*! \libinternal \brief
+ * Initializes the test utilities library.
+ *
+ * Does not throw.  Terminates the program with a non-zero error code if an
+ * error occurs.
+ *
+ * This function is automatically called by unittest_main.cpp.
  */
-void parseTestOptions(Options *options);
+void initTestUtils(const char *dataPath, int *argc, char ***argv);
 
 } // namespace test
 } // namespace gmx
index 751b9be05364d28ed6f7f0f172292f97e0c38b4d..3ab8a2081a5ce17031126f690654bcb66db13872 100644 (file)
@@ -54,6 +54,6 @@
 int main(int argc, char *argv[])
 {
     // Calls ::testing::InitGoogleMock()
-    ::gmx::test::initTestUtils(TEST_DATA_PATH, &argc, argv);
+    ::gmx::test::initTestUtils(TEST_DATA_PATH, &argc, &argv);
     return RUN_ALL_TESTS();
 }
diff --git a/src/tools/CMakeLists.txt b/src/tools/CMakeLists.txt
deleted file mode 100644 (file)
index 1ebdb44..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-# List of programs with single corresponding .c source file,
-# used to create build rules automatically.
-#
-set(GMX_TOOLS_PROGRAMS
-    g_pme_error
-    )
-
-foreach(TOOL ${GMX_TOOLS_PROGRAMS})
-    add_executable(${TOOL} ${TOOL}.c)
-    gmx_add_man_page(${TOOL})
-    target_link_libraries(${TOOL} libgromacs ${GMX_EXE_LINKER_FLAGS})
-    set_target_properties(${TOOL} PROPERTIES OUTPUT_NAME "${TOOL}${GMX_BINARY_SUFFIX}")
-endforeach(TOOL ${GMX_TOOLS_PROGRAMS})
-
-install(TARGETS ${GMX_TOOLS_PROGRAMS}
-        DESTINATION ${BIN_INSTALL_DIR}
-        COMPONENT runtime)
diff --git a/src/tools/g_pme_error.c b/src/tools/g_pme_error.c
deleted file mode 100644 (file)
index 6249737..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- *
- *                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-2008, 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
- *
- * And Hey:
- * Gallium Rubidium Oxygen Manganese Argon Carbon Silicon
- */
-#include "gromacs/gmxana/gmx_ana.h"
-
-/* This is just a wrapper binary.
- */
-int
-main(int argc, char *argv[])
-{
-    gmx_pme_error(argc, argv);
-    return 0;
-}