# 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)
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).
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)
\newcommand{\threadmpi}{ThreadMPI}
\newcommand{\openmpi}{OpenMPI}
\newcommand{\openmp}{OpenMP}
-\newcommand{\openmm}{OpenMM}
\newcommand{\lammpi}{LAM/MPI}
\newcommand{\mpich}{MPICH}
\newcommand{\cmake}{CMake}
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}
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
{
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
{
nb_.setCutoff(cutoff_);
- data_.setColumnCount(sel_.size());
+ data_.setColumnCount(0, sel_.size());
avem_.reset(new AnalysisDataAverageModule());
data_.addModule(avem_);
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));
}
}
-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)
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)
add_subdirectory(programs)
if(NOT GMX_FAHCORE)
- add_subdirectory(tools)
add_subdirectory(ngmx)
add_subdirectory(contrib)
endif(NOT GMX_FAHCORE)
+++ /dev/null
-#
-# 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()
)
-# 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}")
+++ /dev/null
-# 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)
+++ /dev/null
-/*
- * 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;
-}
+++ /dev/null
-/*
- * 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 */
+++ /dev/null
-/*
- * 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;
-}
-
+++ /dev/null
-/*
- * 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);
-}
-
-
+++ /dev/null
-/*
- * 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_ */
+++ /dev/null
-/* -*- 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());
- }
-}
+++ /dev/null
-/*
- * 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_ */
-
+++ /dev/null
-/*
- * 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;
-}
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
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.
};
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,
*/
/*! \cond libapi */
AbstractAnalysisData::AbstractAnalysisData()
- : impl_(new Impl()), columnCount_(0), bMultiPoint_(false)
+ : impl_(new Impl())
{
}
//! \endcond
{
}
+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
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_)
{
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_)
{
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");
/*! \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;
}
{
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);
}
}
{
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())
* 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
*
* \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().
*
* 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.
*
* 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.
*
* \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()
*/
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().
class Impl;
PrivateImplPointer<Impl> impl_;
- int columnCount_;
- bool bMultiPoint_;
/*! \brief
* Needed to provide access to notification methods.
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);
}
}
+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)
{
*
* 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
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.
*
*
* 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.
* 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.
* 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.
*
{
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)
{
}
{
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);
}
* 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
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:
*/
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.
using AbstractAnalysisArrayData::allocateValues;
using AbstractAnalysisArrayData::setXAxis;
using AbstractAnalysisArrayData::value;
- using AbstractAnalysisArrayData::setValue;
using AbstractAnalysisArrayData::valuesReady;
// Copy and assign disallowed by base.
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())
{
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");
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");
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_;
};
{
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
{
private:
AnalysisDataFrameHeader header_;
+ int dataSetIndex_;
int firstColumn_;
AnalysisDataValuesRef values_;
};
/*
* 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.
*/
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() {};
/*
* 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.
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());
}
int
AnalysisDataProxy::flags() const
{
- return efAllowMultipoint | efAllowMulticolumn | efAllowMissing;
+ return efAllowMultipoint | efAllowMulticolumn | efAllowMissing
+ | efAllowMultipleDataSets;
}
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();
}
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
/*! \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().
*
}
-int
-AnalysisDataStorage::Impl::columnCount() const
-{
- GMX_ASSERT(data_ != NULL, "columnCount() called too early");
- return data_->columnCount();
-}
-
-
bool
AnalysisDataStorage::Impl::isMultipoint() const
{
{
if (builders_.empty())
{
- return FrameBuilderPointer(new AnalysisDataStorageFrame(columnCount()));
+ return FrameBuilderPointer(new AnalysisDataStorageFrame(*data_));
}
FrameBuilderPointer builder(move(builders_.back()));
builders_.pop_back();
// 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;
+ }
}
}
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)));
else
{
pointSets_.push_back(
- AnalysisDataPointSetInfo(values_.size(), valueCount, firstColumn));
+ AnalysisDataPointSetInfo(values_.size(), valueCount,
+ dataSetIndex, firstColumn));
std::copy(begin, end, std::back_inserter(values_));
}
}
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();
* 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);
}
}
+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()
{
"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();
}
*/
~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.
{
GMX_ASSERT(column >= 0 && column < columnCount(),
"Invalid column index");
- values_[column].setValue(value, bPresent);
+ values_[currentOffset_ + column].setValue(value, bPresent);
bPointSetInProgress_ = true;
}
/*! \brief
{
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
{
GMX_ASSERT(column >= 0 && column < columnCount(),
"Invalid column index");
- return values_[column].value();
+ return values_[currentOffset_ + column].value();
}
/*! \brief
* Access value for a column.
{
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.
/*! \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();
//! 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_;
#include <cmath>
+#include <algorithm>
+#include <vector>
+
#include "gromacs/analysisdata/dataframe.h"
#include "gromacs/analysisdata/datastorage.h"
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
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
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);
}
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()
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);
}
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];
}
}
}
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());
}
* 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.
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);
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;
/*! \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
int ncol = _impl->nmax / _impl->ndim + 1;
_impl->currValues_.reserve(ncol);
- setColumnCount(ncol);
+ setColumnCount(0, ncol);
}
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.
*
*/
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");
*/
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");
#include <cmath>
#include <limits>
+#include <vector>
#include "gromacs/analysisdata/dataframe.h"
#include "gromacs/analysisdata/datastorage.h"
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)
{
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];
+ }
}
}
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);
}
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));
+ }
}
void
BasicAverageHistogramModule::pointsAdded(const AnalysisDataPointSetRef &points)
{
- averager_.addPoints(points);
+ averagers_[points.dataSetIndex()].addPoints(points);
}
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)));
+ }
}
}
/*! \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_;
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
int
AnalysisDataSimpleHistogramModule::flags() const
{
- return efAllowMulticolumn | efAllowMultipoint;
+ return efAllowMulticolumn | efAllowMultipoint | efAllowMissing
+ | efAllowMultipleDataSets;
}
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);
}
AnalysisDataSimpleHistogramModule::frameStarted(const AnalysisDataFrameHeader &header)
{
AnalysisDataStorageFrame &frame = impl_->storage_.startFrame(header);
- impl_->initFrame(&frame);
+ impl_->initFrame(dataSetCount(), &frame);
}
{
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;
+ }
}
}
}
int
AnalysisDataWeightedHistogramModule::flags() const
{
- return efAllowMulticolumn | efAllowMultipoint;
+ return efAllowMulticolumn | efAllowMultipoint | efAllowMultipleDataSets;
}
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);
}
AnalysisDataWeightedHistogramModule::frameStarted(const AnalysisDataFrameHeader &header)
{
AnalysisDataStorageFrame &frame = impl_->storage_.startFrame(header);
- impl_->initFrame(&frame);
+ impl_->initFrame(dataSetCount(), &frame);
}
{
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);
}
//! 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()
const AnalysisHistogramSettings &settings)
: impl_(new Impl(settings))
{
- setColumnCount(3);
setRowCount(settings.binCount());
setXAxis(settings.firstEdge() + 0.5 * settings.binWidth(),
settings.binWidth());
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());
+ }
}
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));
}
}
}
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();
}
* 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
*/
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.
*
/*! \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
/*! \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
* 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
#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"
FILE *fp_;
bool bPlain_;
- bool gOmitX_;
+ bool bOmitX_;
+ bool bErrorsAsSeparateColumn_;
std::string title_;
std::string subtitle_;
std::string xlabel_;
};
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");
}
+void
+AbstractPlotModule::setErrorsAsSeparateColumn(bool bSeparate)
+{
+ impl_->bErrorsAsSeparateColumn_ = bSeparate;
+}
+
+
void
AbstractPlotModule::setOmitX(bool bOmitX)
{
- impl_->gOmitX_ = bOmitX;
+ impl_->bOmitX_ = bOmitX;
}
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())
{
{
return;
}
- if (!impl_->gOmitX_)
+ if (!impl_->bOmitX_)
{
std::fprintf(impl_->fp_, impl_->xformat_, frame.x() * impl_->xscale_);
}
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
}
for (int i = 0; i < points.columnCount(); ++i)
{
- writeValue(points.y(i));
+ writeValue(points.values()[i]);
}
}
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"));
}
{
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);
}
}
}
/*
* 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.
namespace gmx
{
+class AnalysisDataValue;
class Options;
class SelectionCollection;
* 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
*/
* 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.
*
*
* Must not be called if isFileOpen() returns false.
*/
- void writeValue(real value) const;
+ void writeValue(const AnalysisDataValue &value) const;
//! \endcond
private:
#
# 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.
analysisdata.cpp
arraydata.cpp
average.cpp
- histogram.cpp)
+ histogram.cpp
+ lifetime.cpp)
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());
}
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);
* 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));
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);
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
{
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:
//! 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);
/*
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);
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);
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:
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();
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
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:
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:
TEST_F(WeightedHistogramModuleTest, ComputesCorrectly)
{
- const AnalysisDataTestInput &input = WeightedInputData::get();
+ const AnalysisDataTestInput &input = WeightedSimpleInputData::get();
gmx::AnalysisData data;
ASSERT_NO_THROW_GMX(setupDataObject(input, &data));
TEST_F(WeightedHistogramModuleTest, ComputesCorrectlyWithAll)
{
- const AnalysisDataTestInput &input = WeightedInputData::get();
+ const AnalysisDataTestInput &input = WeightedSimpleInputData::get();
gmx::AnalysisData data;
ASSERT_NO_THROW_GMX(setupDataObject(input, &data));
}
+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.
*/
TEST_F(BinAverageModuleTest, ComputesCorrectly)
{
- const AnalysisDataTestInput &input = WeightedInputData::get();
+ const AnalysisDataTestInput &input = WeightedSimpleInputData::get();
gmx::AnalysisData data;
ASSERT_NO_THROW_GMX(setupDataObject(input, &data));
TEST_F(BinAverageModuleTest, ComputesCorrectlyWithAll)
{
- const AnalysisDataTestInput &input = WeightedInputData::get();
+ const AnalysisDataTestInput &input = WeightedSimpleInputData::get();
gmx::AnalysisData data;
ASSERT_NO_THROW_GMX(setupDataObject(input, &data));
}
+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.
*
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:
using AbstractAverageHistogram::setColumnCount;
using AbstractAverageHistogram::setRowCount;
using AbstractAverageHistogram::allocateValues;
- using AbstractAverageHistogram::setValue;
+ using AbstractAverageHistogram::value;
};
--- /dev/null
+/*
+ * 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
<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>
<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>
<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>
<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>
--- /dev/null
+<?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>
--- /dev/null
+<?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>
<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>
<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>
<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>
<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>
<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>
--- /dev/null
+<?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>
<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>
--- /dev/null
+<?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>
--- /dev/null
+<?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>
--- /dev/null
+<?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>
--- /dev/null
+<?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>
<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>
<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>
<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>
<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>
--- /dev/null
+<?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>
<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>
<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>
</table>
</xsl:template>
+<xsl:template match="DataValue[Bool[@Name='Present']='false']">
+ (
+ <xsl:value-of select="Real[@Name='Value']"/>
+ <xsl:if test="Real[@Name='Error']">
+ ± <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']">
+ ± <xsl:value-of select="Real[@Name='Error']"/>
+ </xsl:if>
</xsl:template>
</xsl:stylesheet>
#include <utility>
#include "gromacs/legacyheaders/copyrite.h"
+#include "gromacs/legacyheaders/network.h"
#include "gromacs/commandline/cmdlinemodule.h"
#include "gromacs/commandline/cmdlineparser.h"
#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"
// 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
*/
: programInfo_(*programInfo), helpModule_(NULL), singleModule_(NULL),
bQuiet_(false), bStdOutInfo_(false)
{
+ binaryInfoSettings_.copyright(true);
}
CommandLineModuleMap::const_iterator
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;
}
/********************************************************************
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)
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);
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
/*
* 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.
* \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
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.
*
*/
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.
* \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.
*
/*
* 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
//! 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
*/
{
}
-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
{
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)
{
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
{
/*
* 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.
~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;
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;
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)
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
#include "cmat.h"
#include "smalloc.h"
#include "macros.h"
+#include "vec.h"
#include "xvgr.h"
#include "matio.h"
#include "futil.h"
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);
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;
*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;
}
}
int n1, nn;
int *m_ind;
gmx_bool b1D;
- real emat, minrms, maxrms, sumrms;
+ real minrms, maxrms, sumrms;
real *erow;
real **mat;
} t_mat;
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);
#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"
}
}
-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)
"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]",
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;
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;
{ "-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)" },
{ 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},
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 "
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);
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));
}
}
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");
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;
}
};
#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);
do_view(oenv, opt2fn("-dm", NFILE, fnm), "-nxy");
}
- gmx_finalize_par();
-
gmx_log_close(fplog);
return 0;
#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))
#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,
fclose(fp);
}
- gmx_finalize_par();
-
return 0;
}
#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)
{
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]);
}
}
{
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',
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 */
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;
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;
}
}
-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)
{
}
}
-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))");
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 */
#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");
/* 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 );
#include <cmath>
#include <cstdlib>
-#include "copyrite.h"
#include "sysstuff.h"
#include "macros.h"
#include "string2.h"
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
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},
// 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++)
{
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);
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();
#endif
#endif
- if (!(FF(PCA_QUIET) || bQuiet))
+ if (!(FF(PCA_QUIET)))
{
if (bHelp)
{
}
}
}
+ 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)
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];
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);
__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);
#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);
__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);
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);
__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;
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);
__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;
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);
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);
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;
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;
#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);
__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);
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);
__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;
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);
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;
* 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);
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);
/* 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)
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;
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)
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)
/*
* 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.
}
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)
/*
* 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.
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.
*/
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.
*
}
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);
}
/*!
/* 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
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));
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));
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));
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));
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));
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);
case 16:
/* Line 1787 of yacc.c */
-#line 322 "parser.y"
+#line 320 "parser.y"
{
BEGIN_ACTION;
set((yyval.vlist), SelectionParserValue::createList());
case 17:
/* Line 1787 of yacc.c */
-#line 328 "parser.y"
+#line 326 "parser.y"
{
BEGIN_ACTION;
SelectionParserValueListPointer list(get((yyvsp[(1) - (2)].vlist)));
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));
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));
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)));
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)));
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)));
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));
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));
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));
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));
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));
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));
case 47:
/* Line 1787 of yacc.c */
-#line 512 "parser.y"
+#line 508 "parser.y"
{
BEGIN_ACTION;
SelectionTreeElementPointer sel(
case 48:
/* Line 1787 of yacc.c */
-#line 523 "parser.y"
+#line 519 "parser.y"
{
BEGIN_ACTION;
SelectionTreeElementPointer sel(
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));
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));
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));
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));
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));
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));
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));
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));
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(
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));
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)));
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));
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));
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))));
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))));
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))));
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());
case 70:
/* Line 1787 of yacc.c */
-#line 704 "parser.y"
+#line 700 "parser.y"
{
BEGIN_ACTION;
SelectionParserParameterListPointer list(get((yyvsp[(1) - (2)].plist)));
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));
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());
case 75:
/* Line 1787 of yacc.c */
-#line 735 "parser.y"
+#line 731 "parser.y"
{
BEGIN_ACTION;
SelectionParserValueListPointer list(get((yyvsp[(1) - (2)].vlist)));
case 76:
/* Line 1787 of yacc.c */
-#line 743 "parser.y"
+#line 739 "parser.y"
{
BEGIN_ACTION;
SelectionParserValueListPointer list(get((yyvsp[(1) - (3)].vlist)));
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))));
case 80:
/* Line 1787 of yacc.c */
-#line 765 "parser.y"
+#line 761 "parser.y"
{
BEGIN_ACTION;
SelectionParserValueListPointer list(get((yyvsp[(1) - (2)].vlist)));
case 81:
/* Line 1787 of yacc.c */
-#line 773 "parser.y"
+#line 769 "parser.y"
{
BEGIN_ACTION;
SelectionParserValueListPointer list(get((yyvsp[(1) - (3)].vlist)));
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))));
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))));
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))));
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))));
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)));
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)));
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));
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)));
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)));
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)));
/* Line 1787 of yacc.c */
-#line 2835 "parser.cpp"
+#line 2831 "parser.cpp"
default: break;
}
/* User semantic actions sometimes alter yychar, and that requires
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
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
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;
}
;
#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"
}
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;
}
/*!
* \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.
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;
}
/* 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))
} // namespace
+void
+SelectionData::refreshName()
+{
+ rootElement_.fillNameIfMissing(selectionText_.c_str());
+ name_ = rootElement_.name();
+}
+
void
SelectionData::initializeMassesAndCharges(const t_topology *top)
{
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.
//! \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.
*
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.
/*
* 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.
namespace gmx
{
-class MessageStringCollector;
+class ExceptionInitializer;
/*! \internal \brief
* Private implemention class for SelectionCollection.
*
* \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_;
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();
}
}
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();
}
}
/*
* 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.
*
* \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.
/*
* 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.
#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"
}
}
+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
/*!
/*
* 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.
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;
/*
* 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.
}
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];
<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 > 2</String>
- <String Name="Name">y > 2</String>
<String Name="Text">y > 2</String>
<Bool Name="Dynamic">true</Bool>
</ParsedSelection>
<ParsedSelection Name="Selection3">
<String Name="Input">res_cog of y > 2</String>
- <String Name="Name">res_cog of y > 2</String>
<String Name="Text">res_cog of y > 2</String>
<Bool Name="Dynamic">true</Bool>
</ParsedSelection>
<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 > 2</String>
- <String Name="Name">y > 2</String>
<String Name="Text">y > 2</String>
<Bool Name="Dynamic">true</Bool>
</ParsedSelection>
<ParsedSelection Name="Selection3">
<String Name="Input">cog of (y > 2)</String>
- <String Name="Name">cog of (y > 2)</String>
<String Name="Text">cog of (y > 2)</String>
<Bool Name="Dynamic">true</Bool>
</ParsedSelection>
<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>
<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>
<ParsedSelections Name="Parsed">
<ParsedSelection Name="Selection1">
<String Name="Input">x+1 > 3</String>
- <String Name="Name">x+1 > 3</String>
<String Name="Text">x+1 > 3</String>
<Bool Name="Dynamic">true</Bool>
</ParsedSelection>
<ParsedSelection Name="Selection2">
<String Name="Input">(y-1)^2 <= 1</String>
- <String Name="Name">(y-1)^2 <= 1</String>
<String Name="Text">(y-1)^2 <= 1</String>
<Bool Name="Dynamic">true</Bool>
</ParsedSelection>
<ParsedSelection Name="Selection3">
<String Name="Input">x+--1 > 3</String>
- <String Name="Name">x+--1 > 3</String>
<String Name="Text">x+--1 > 3</String>
<Bool Name="Dynamic">true</Bool>
</ParsedSelection>
<ParsedSelection Name="Selection4">
<String Name="Input">-x+-1 < -3</String>
- <String Name="Name">-x+-1 < -3</String>
<String Name="Text">-x+-1 < -3</String>
<Bool Name="Dynamic">true</Bool>
</ParsedSelection>
<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>
<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 <= 5</String>
- <String Name="Name">atomnr <= 5</String>
<String Name="Text">atomnr <= 5</String>
<Bool Name="Dynamic">false</Bool>
</ParsedSelection>
--- /dev/null
+<?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>
<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 < 5 and atomnr 1 to 5 and y < 3 and atomnr 2 to 4</String>
- <String Name="Name">x < 5 and atomnr 1 to 5 and y < 3 and atomnr 2 to 4</String>
<String Name="Text">x < 5 and atomnr 1 to 5 and y < 3 and atomnr 2 to 4</String>
<Bool Name="Dynamic">true</Bool>
</ParsedSelection>
<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 >= 0.3</String>
- <String Name="Name">betafactor >= 0.3</String>
<String Name="Text">betafactor >= 0.3</String>
<Bool Name="Dynamic">false</Bool>
</ParsedSelection>
<ParsedSelections Name="Parsed">
<ParsedSelection Name="Selection1">
<String Name="Input">atomnr 1 to 5 and atomnr 2 to 7 and x < 2</String>
- <String Name="Name">atomnr 1 to 5 and atomnr 2 to 7 and x < 2</String>
<String Name="Text">atomnr 1 to 5 and atomnr 2 to 7 and x < 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 < 2)</String>
- <String Name="Name">atomnr 1 to 5 and (atomnr 4 to 7 or x < 2)</String>
<String Name="Text">atomnr 1 to 5 and (atomnr 4 to 7 or x < 2)</String>
<Bool Name="Dynamic">true</Bool>
</ParsedSelection>
<ParsedSelection Name="Selection3">
<String Name="Input">atomnr 1 to 5 and y < 3 and (atomnr 4 to 7 or x < 2)</String>
- <String Name="Name">atomnr 1 to 5 and y < 3 and (atomnr 4 to 7 or x < 2)</String>
<String Name="Text">atomnr 1 to 5 and y < 3 and (atomnr 4 to 7 or x < 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 < 2)</String>
- <String Name="Name">atomnr 1 to 5 and not (atomnr 4 to 7 or x < 2)</String>
<String Name="Text">atomnr 1 to 5 and not (atomnr 4 to 7 or x < 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 < 2))</String>
- <String Name="Name">atomnr 1 to 5 or (atomnr 4 to 6 and (atomnr 5 to 7 or x < 2))</String>
<String Name="Text">atomnr 1 to 5 or (atomnr 4 to 6 and (atomnr 5 to 7 or x < 2))</String>
<Bool Name="Dynamic">true</Bool>
</ParsedSelection>
</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 < 3 and bar2</String>
- <String Name="Name">atomnr 2 to 6 and y < 3 and bar2</String>
<String Name="Text">atomnr 2 to 6 and y < 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>
</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 < 3 and foo</String>
- <String Name="Name">atomnr 2 to 6 and y < 3 and foo</String>
<String Name="Text">atomnr 2 to 6 and y < 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>
<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>
<ParsedSelections Name="Parsed">
<ParsedSelection Name="Selection1">
<String Name="Input">charge < 0.5</String>
- <String Name="Name">charge < 0.5</String>
<String Name="Text">charge < 0.5</String>
<Bool Name="Dynamic">false</Bool>
</ParsedSelection>
</ParsedVariable>
<ParsedSelection Name="Selection1">
<String Name="Input">resname RA and value <= 4</String>
- <String Name="Name">resname RA and value <= 4</String>
<String Name="Text">resname RA and value <= 4</String>
<Bool Name="Dynamic">true</Bool>
</ParsedSelection>
<ParsedSelection Name="Selection2">
<String Name="Input">resname RA RB and x < 3 and value <= 4</String>
- <String Name="Name">resname RA RB and x < 3 and value <= 4</String>
<String Name="Text">resname RA RB and x < 3 and value <= 4</String>
<Bool Name="Dynamic">true</Bool>
</ParsedSelection>
</ParsedVariable>
<ParsedSelection Name="Selection3">
<String Name="Input">resname RA and index < 3</String>
- <String Name="Name">resname RA and index < 3</String>
<String Name="Text">resname RA and index < 3</String>
<Bool Name="Dynamic">false</Bool>
</ParsedSelection>
<ParsedSelection Name="Selection4">
<String Name="Input">resname RB and y < 3 and index < 6</String>
- <String Name="Name">resname RB and y < 3 and index < 6</String>
<String Name="Text">resname RB and y < 3 and index < 6</String>
<Bool Name="Dynamic">true</Bool>
</ParsedSelection>
</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>
<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>
<ParsedSelections Name="Parsed">
<ParsedSelection Name="Selection1">
<String Name="Input">x < 3</String>
- <String Name="Name">x < 3</String>
<String Name="Text">x < 3</String>
<Bool Name="Dynamic">true</Bool>
</ParsedSelection>
<ParsedSelection Name="Selection2">
<String Name="Input">y >= 3</String>
- <String Name="Name">y >= 3</String>
<String Name="Text">y >= 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>
<ParsedSelections Name="Parsed">
<ParsedSelection Name="Selection1">
<String Name="Input">distance from cog of resnr 1 < 2</String>
- <String Name="Name">distance from cog of resnr 1 < 2</String>
<String Name="Text">distance from cog of resnr 1 < 2</String>
<Bool Name="Dynamic">true</Bool>
</ParsedSelection>
<ParsedSelections Name="Parsed">
<ParsedSelection Name="Selection1">
<String Name="Input">same residue as (atomnr 3 5 13 or y > 5)</String>
- <String Name="Name">same residue as (atomnr 3 5 13 or y > 5)</String>
<String Name="Text">same residue as (atomnr 3 5 13 or y > 5)</String>
<Bool Name="Dynamic">true</Bool>
</ParsedSelection>
<ParsedSelection Name="Selection2">
- <String Name="Input">(resnr 1 3 5 or x > 10) and same residue as (atomnr 3 5 13 or y > 5)</String>
- <String Name="Name">(resnr 1 3 5 or x > 10) and same residue as (atomnr 3 5 13 or y > 5)</String>
- <String Name="Text">(resnr 1 3 5 or x > 10) and same residue as (atomnr 3 5 13 or y > 5)</String>
+ <String Name="Input">(resnr 1 3 5 or x > 10) and same residue as (atomnr 3 5 13 or z > 5)</String>
+ <String Name="Text">(resnr 1 3 5 or x > 10) and same residue as (atomnr 3 5 13 or z > 5)</String>
<Bool Name="Dynamic">true</Bool>
</ParsedSelection>
</ParsedSelections>
<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>
<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>
--- /dev/null
+<?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>
--- /dev/null
+<?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>
<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>
<ParsedSelections Name="Parsed">
<ParsedSelection Name="Selection1">
<String Name="Input">mass > 5</String>
- <String Name="Name">mass > 5</String>
<String Name="Text">mass > 5</String>
<Bool Name="Dynamic">false</Bool>
</ParsedSelection>
<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 < 2.5 merge res_cog of x < 2.5</String>
- <String Name="Name">name S1 and x < 2.5 merge res_cog of x < 2.5</String>
<String Name="Text">name S1 and x < 2.5 merge res_cog of x < 2.5</String>
<Bool Name="Dynamic">true</Bool>
</ParsedSelection>
<ParsedSelections Name="Parsed">
<ParsedSelection Name="Selection1">
<String Name="Input">mindistance from resnr 1 < 2</String>
- <String Name="Name">mindistance from resnr 1 < 2</String>
<String Name="Text">mindistance from resnr 1 < 2</String>
<Bool Name="Dynamic">true</Bool>
</ParsedSelection>
--- /dev/null
+<?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>
<ParsedSelections Name="Parsed">
<ParsedSelection Name="Selection1">
<String Name="Input">x > 2</String>
- <String Name="Name">x > 2</String>
<String Name="Text">x > 2</String>
<Bool Name="Dynamic">true</Bool>
</ParsedSelection>
<ParsedSelection Name="Selection2">
<String Name="Input">2 < x</String>
- <String Name="Name">2 < x</String>
<String Name="Text">2 < x</String>
<Bool Name="Dynamic">true</Bool>
</ParsedSelection>
<ParsedSelection Name="Selection3">
<String Name="Input">y > resnr</String>
- <String Name="Name">y > resnr</String>
<String Name="Text">y > resnr</String>
<Bool Name="Dynamic">true</Bool>
</ParsedSelection>
<ParsedSelection Name="Selection4">
<String Name="Input">resnr < 2.5</String>
- <String Name="Name">resnr < 2.5</String>
<String Name="Text">resnr < 2.5</String>
<Bool Name="Dynamic">false</Bool>
</ParsedSelection>
<ParsedSelection Name="Selection5">
<String Name="Input">2.5 > resnr</String>
- <String Name="Name">2.5 > resnr</String>
<String Name="Text">2.5 > resnr</String>
<Bool Name="Dynamic">false</Bool>
</ParsedSelection>
</ParsedVariable>
<ParsedSelection Name="Selection1">
<String Name="Input">resnr < constint</String>
- <String Name="Name">resnr < constint</String>
<String Name="Text">resnr < constint</String>
<Bool Name="Dynamic">false</Bool>
</ParsedSelection>
<ParsedSelection Name="Selection2">
<String Name="Input">x + constreal1 < constreal2</String>
- <String Name="Name">x + constreal1 < constreal2</String>
<String Name="Text">x + constreal1 < constreal2</String>
<Bool Name="Dynamic">true</Bool>
</ParsedSelection>
</ParsedVariable>
<ParsedSelection Name="Selection1">
<String Name="Input">value <= 4</String>
- <String Name="Name">value <= 4</String>
<String Name="Text">value <= 4</String>
<Bool Name="Dynamic">true</Bool>
</ParsedSelection>
</ParsedVariable>
<ParsedSelection Name="Selection2">
<String Name="Input">index < 3</String>
- <String Name="Name">index < 3</String>
<String Name="Text">index < 3</String>
<Bool Name="Dynamic">false</Bool>
</ParsedSelection>
<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 < .5</String>
- <String Name="Name">occupancy < .5</String>
<String Name="Text">occupancy < .5</String>
<Bool Name="Dynamic">false</Bool>
</ParsedSelection>
<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>
<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 < 3 permute 2 1</String>
- <String Name="Name">name CB S1 and res_cog x < 3 permute 2 1</String>
<String Name="Text">name CB S1 and res_cog x < 3 permute 2 1</String>
<Bool Name="Dynamic">true</Bool>
</ParsedSelection>
<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 < 3 plus res_cog of x < 2.5</String>
- <String Name="Name">name S1 and y < 3 plus res_cog of x < 2.5</String>
<String Name="Text">name S1 and y < 3 plus res_cog of x < 2.5</String>
<Bool Name="Dynamic">true</Bool>
</ParsedSelection>
<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 < 3</String>
- <String Name="Name">part_res_cog of x < 3</String>
<String Name="Text">part_res_cog of x < 3</String>
<Bool Name="Dynamic">true</Bool>
</ParsedSelection>
<ParsedSelection Name="Selection5">
<String Name="Input">dyn_res_cog of x < 3</String>
- <String Name="Name">dyn_res_cog of x < 3</String>
<String Name="Text">dyn_res_cog of x < 3</String>
<Bool Name="Dynamic">true</Bool>
</ParsedSelection>
</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>
<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>
<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>
<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>
<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>
<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>
<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>
--- /dev/null
+<?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 < 5</String>
+ <String Name="Name">DynamicSelection</String>
+ <String Name="Text">"DynamicSelection" x < 5</String>
+ <Bool Name="Dynamic">true</Bool>
+ </ParsedSelection>
+ <ParsedSelection Name="Selection3">
+ <String Name="Input">y < 3</String>
+ <String Name="Name">y < 3</String>
+ <String Name="Text">y < 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 < 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>
</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>
</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>
</ParsedVariable>
<ParsedSelection Name="Selection1">
<String Name="Input">atomnr 1 to 5 and y < 10 and foo</String>
- <String Name="Name">atomnr 1 to 5 and y < 10 and foo</String>
<String Name="Text">atomnr 1 to 5 and y < 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>
</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>
<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>
<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>
<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>
<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']">
#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"
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);
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
efTestPositionMapping = 1<<3,
efTestPositionMasses = 1<<4,
efTestPositionCharges = 1<<5,
+ efTestSelectionNames = 1<<6,
efDontTestCompiledAtoms = 1<<8
};
typedef gmx::FlagsTemplate<TestFlag> TestFlags;
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_;
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);
// 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);
}
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)
{
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)
{
* 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[] = {
{
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);
--- /dev/null
+[ GrpA ]
+1 2 3 4 5
+
+[ GrpB ]
+4 5 6 7 8
+
+[ GrpUnsorted ]
+1 2 4 3 2
#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"
}
}
+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");
#ifndef GMX_SELECTION_TESTS_TOPUTILS_H
#define GMX_SELECTION_TESTS_TOPUTILS_H
+#include <vector>
+
#include "gromacs/legacyheaders/typedefs.h"
namespace gmx
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);
t_trxframe *frame() { return frame_; }
private:
- t_topology *top_;
- t_trxframe *frame_;
+ t_topology *top_;
+ t_trxframe *frame_;
+ std::vector<char *> atomtypes_;
};
} // namespace test
/*
* 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.
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");
"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",
"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" };
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"));
}
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(
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));
+ }
+ }
+ }
}
}
{
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());
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])
{
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();
/*
* 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.
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");
}
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);
+ }
}
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
/*
* 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 "../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
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.
};
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;
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_);
#include <cstring>
#include <algorithm>
+#include <set>
#include <string>
#include <vector>
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");
}
"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",
"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]",
"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));
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_)
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
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)
}
// 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)
{
sdata_.addModule(plot);
}
- cdata_.setColumnCount(sel_.size());
+ cdata_.setColumnCount(0, sel_.size());
if (!fnFrac_.empty())
{
AnalysisDataPlotModulePointer plot(
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())
{
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");
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_ = ⊤
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();
}
{
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);
+ }
}
}
}
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");
/*
* 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.
#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
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
#
# 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.
gmx_add_unit_test(TrajectoryAnalysisUnitTests trajectoryanalysis-test
moduletest.cpp
angle.cpp
+ distance.cpp
freevolume.cpp
select.cpp)
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
--- /dev/null
+/*
+ * 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
<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>
--- /dev/null
+<?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>
<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>
<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>
<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>
<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>
<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>
<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>
--- /dev/null
+<?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 < 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>
--- /dev/null
+<?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>
--- /dev/null
+<?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>
--- /dev/null
+<?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 < 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>
</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>
+++ /dev/null
-<?xml version="1.0"?>
-<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
-<ReferenceData>
- <String Name="CommandLine">select -select 'y < 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>
<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
<ReferenceData>
- <String Name="CommandLine">select -select 'resname RA RD and y < 2.5' -pdbatoms maxsel</String>
+ <String Name="CommandLine">select -select 'resname RA RD and y < 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>
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
<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>
<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>
<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
<ReferenceData>
- <String Name="CommandLine">select -select 'resname RA RD and y < 2.5' -pdbatoms selected</String>
+ <String Name="CommandLine">select -select 'resname RA RD and y < 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>
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
<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>
<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>
</table>
</xsl:template>
+<xsl:template match="DataValue[Bool[@Name='Present']='false']">
+ (
+ <xsl:value-of select="Real[@Name='Value']"/>
+ <xsl:if test="Real[@Name='Error']">
+ ± <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']">
+ ± <xsl:value-of select="Real[@Name='Error']"/>
+ </xsl:if>
</xsl:template>
</xsl:stylesheet>
{
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");
{
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");
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[] = {
#
# 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.
gmx_header_config.h
gmxassert.h
gmxmpi.h
+ init.h
programinfo.h
stringutil.h
uniqueptr.h)
/*
* 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.
*
*/
#include "exceptions.h"
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
#include <cstring>
#include <new>
#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"
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)
}
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);
}
}
{
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
* \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
* \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);
* \code
int main(int argc, char *argv[])
{
- gmx::ProgramInfo::init(argc, argv);
+ gmx::init(&argc, &argv);
try
{
// The actual code for the program
catch (const std::exception &ex)
{
gmx::printFatalErrorMessage(stderr, ex);
- return 1;
+ return gmx::processExceptionAtExit(ex);
}
}
* \endcode
* \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.
#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
/*
* 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.
* \{
*/
-/*! \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.
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
/*
* 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.
catch (const std::exception &ex)
{
printFatalErrorMessage(stderr, ex);
- std::exit(1);
+ std::exit(processExceptionAtExit(ex));
}
}
#include <string.h>
#include "macros.h"
#include "Xstuff.h"
-#include "copyrite.h"
#include "xutil.h"
#include "futil.h"
#include "x11.h"
#include "rama.bm"
#include "nrama.h"
-#include "gromacs/utility/programinfo.h"
+#include "gromacs/commandline/cmdlinemodulemanager.h"
#define MAXDEG 360
}
}
-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",
};
#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);
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);
+}
#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;
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",
};
#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)
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" },
#
# 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.
g_nmtraj
g_options
g_order
+ g_pme_error
g_polystat
g_potential
g_principal
/*
* 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);
}
}
* 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>
*/
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
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");
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)
${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
#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",
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
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)
return rc;
}
+
+int main(int argc, char *argv[])
+{
+ return gmx::CommandLineModuleManager::runAsMainCMain(argc, argv, &gmx_mdrun);
+}
<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>
<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>
</table>
</xsl:template>
+<xsl:template match="DataValue[Bool[@Name='Present']='false']">
+ (
+ <xsl:value-of select="Real[@Name='Value']"/>
+ <xsl:if test="Real[@Name='Error']">
+ ± <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']">
+ ± <xsl:value-of select="Real[@Name='Error']"/>
+ </xsl:if>
</xsl:template>
</xsl:stylesheet>
/*
* 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 <new>
#include <vector>
+#include "gromacs/utility/gmxassert.h"
#include "gromacs/utility/programinfo.h"
namespace gmx
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);
/*
* 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.
* 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.
*/
AnalysisDataTestInputPointSet::AnalysisDataTestInputPointSet(
- int index, int firstColumn)
- : index_(index), firstColumn_(firstColumn)
+ int index, int dataSetIndex, int firstColumn)
+ : index_(index), dataSetIndex_(dataSetIndex), firstColumn_(firstColumn)
{
}
}
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)
{
}
}
+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));
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);
}
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());
}
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())
{
#include "gromacs/legacyheaders/types/simple.h"
+#include "gromacs/analysisdata/dataframe.h"
#include "gromacs/utility/gmxassert.h"
#include "testutils/refdata.h"
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;
}
//! 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.
/*! \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.
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_;
};
{
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)
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);
}
}
}
* 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
* 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
} // namespace
MockAnalysisDataModule::Impl::Impl(int flags)
- : flags_(flags), frameIndex_(0), columnCount_(-1)
+ : source_(NULL), flags_(flags), frameIndex_(0)
{
}
void
MockAnalysisDataModule::Impl::startReferenceData(AbstractAnalysisData *data)
{
- columnCount_ = data->columnCount();
+ source_ = data;
}
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)
{
{
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
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::_;
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)));
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::_;
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::_;
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
#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"
};
//! 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
ReferenceDataMode getReferenceDataMode()
{
- return g_referenceDataMode;
+ return static_cast<ReferenceDataMode>(g_referenceDataMode);
}
void setReferenceDataMode(ReferenceDataMode mode)
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);
}
/********************************************************************
/*
* 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.
namespace gmx
{
+
+class Options;
+
namespace test
{
/*! \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;
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");
/*
* 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 "gromacs/options/basicoptions.h"
#include "gromacs/options/options.h"
#include "gromacs/utility/file.h"
+
#include "testutils/testoptions.h"
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()
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());
/*
* 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.
class StringTestBase : public ::testing::Test
{
public:
- //! Static fixture setup to parse command-line options.
- static void SetUpTestCase();
-
StringTestBase();
~StringTestBase();
void checkFileContents(const std::string &filename, const char *id);
private:
- static bool s_bWriteToStdOut;
-
TestReferenceData data_;
boost::scoped_ptr<TestReferenceChecker> checker_;
};
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 (...) { \
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 (...) { \
/*
* 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));
}
}
/*
* 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.
{
/*! \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
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();
}
+++ /dev/null
-# 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)
+++ /dev/null
-/*
- *
- * 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;
-}